// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // #define LOGENABLE // uncomment this line to enable the log, // create c:\temp\cim.log before invoking cimcmdlets using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Management.Automation; using System.Text.RegularExpressions; using System.Threading; namespace Microsoft.Management.Infrastructure.CimCmdlets { /// /// /// Global Non-localization strings /// /// internal static class ConstValue { /// /// /// Default computername /// /// internal static string[] DefaultSessionName = { @"*" }; /// /// /// Empty computername, which will create DCOM session /// /// internal static string NullComputerName = null; /// /// /// Empty computername array, which will create DCOM session /// /// internal static string[] NullComputerNames = { NullComputerName }; /// /// /// localhost computername, which will create WSMAN session /// /// internal static string LocalhostComputerName = @"localhost"; /// /// /// Default namespace /// /// internal static string DefaultNameSpace = @"root\cimv2"; /// /// /// Default namespace /// /// internal static string DefaultQueryDialect = @"WQL"; /// /// Name of the note property that controls if "PSComputerName" column is shown. /// internal static string ShowComputerNameNoteProperty = "PSShowComputerName"; /// /// /// Whether given computername is either null or empty /// /// /// /// internal static bool IsDefaultComputerName(string computerName) { return string.IsNullOrEmpty(computerName); } /// /// /// Get computer names, if it is null then return DCOM one /// /// /// /// internal static IEnumerable GetComputerNames(IEnumerable computerNames) { return (computerNames == null) ? NullComputerNames : computerNames; } /// /// Get computer name, if it is null then return default one. /// /// /// internal static string GetComputerName(string computerName) { return string.IsNullOrEmpty(computerName) ? NullComputerName : computerName; } /// /// /// Get namespace, if it is null then return default one /// /// /// /// internal static string GetNamespace(string nameSpace) { return (nameSpace == null) ? DefaultNameSpace : nameSpace; } /// /// /// Get queryDialect, if it is null then return default query Dialect /// /// /// /// internal static string GetQueryDialectWithDefault(string queryDialect) { return (queryDialect == null) ? DefaultQueryDialect : queryDialect; } } /// /// /// Debug helper class used to dump debug message to log file /// /// internal static class DebugHelper { #region private members /// /// Flag used to control generating log message into file. /// private static bool generateLog = true; internal static bool GenerateLog { get { return generateLog; } set { generateLog = value; } } /// /// Whether the log been initialized. /// private static bool logInitialized = false; /// /// Flag used to control generating message into powershell. /// private static bool generateVerboseMessage = true; internal static bool GenerateVerboseMessage { get { return generateVerboseMessage; } set { generateVerboseMessage = value; } } /// /// Flag used to control generating message into powershell. /// internal static string logFile = @"c:\temp\Cim.log"; /// /// Indent space string. /// internal static string space = @" "; /// /// Indent space strings array. /// internal static string[] spaces = { string.Empty, space, space + space, space + space + space, space + space + space + space, space + space + space + space + space, }; /// /// Lock the log file. /// internal static object logLock = new object(); #endregion #region internal strings internal static string runspaceStateChanged = "Runspace {0} state changed to {1}"; internal static string classDumpInfo = @"Class type is {0}"; internal static string propertyDumpInfo = @"Property name {0} of type {1}, its value is {2}"; internal static string defaultPropertyType = @"It is a default property, default value is {0}"; internal static string propertyValueSet = @"This property value is set by user {0}"; internal static string addParameterSetName = @"Add parameter set {0} name to cache"; internal static string removeParameterSetName = @"Remove parameter set {0} name from cache"; internal static string currentParameterSetNameCount = @"Cache have {0} parameter set names"; internal static string currentParameterSetNameInCache = @"Cache have parameter set {0} valid {1}"; internal static string currentnonMandatoryParameterSetInCache = @"Cache have optional parameter set {0} valid {1}"; internal static string optionalParameterSetNameCount = @"Cache have {0} optional parameter set names"; internal static string finalParameterSetName = @"------Final parameter set name of the cmdlet is {0}"; internal static string addToOptionalParameterSet = @"Add to optional ParameterSetNames {0}"; internal static string startToResolveParameterSet = @"------Resolve ParameterSet Name"; internal static string reservedString = @"------"; #endregion #region runtime methods internal static string GetSourceCodeInformation(bool withFileName, int depth) { StackTrace trace = new StackTrace(); StackFrame frame = trace.GetFrame(depth); // if (withFileName) // { // return string.Format(CultureInfo.CurrentUICulture, "{0}#{1}:{2}:", frame.GetFileName()., frame.GetFileLineNumber(), frame.GetMethod().Name); // } // else // { // return string.Format(CultureInfo.CurrentUICulture, "{0}:", frame.GetMethod()); // } return string.Format(CultureInfo.CurrentUICulture, "{0}::{1} ", frame.GetMethod().DeclaringType.Name, frame.GetMethod().Name); } #endregion /// /// Write message to log file named @logFile. /// /// internal static void WriteLog(string message) { WriteLog(message, 0); } /// /// Write blank line to log file named @logFile. /// /// internal static void WriteEmptyLine() { WriteLog(string.Empty, 0); } /// /// Write message to log file named @logFile with args. /// /// internal static void WriteLog(string message, int indent, params object[] args) { string outMessage = string.Empty; FormatLogMessage(ref outMessage, message, args); WriteLog(outMessage, indent); } /// /// Write message to log file w/o arguments. /// /// /// internal static void WriteLog(string message, int indent) { WriteLogInternal(message, indent, -1); } /// /// Write message to log file named @logFile with args. /// /// internal static void WriteLogEx(string message, int indent, params object[] args) { string outMessage = string.Empty; WriteLogInternal(string.Empty, 0, -1); FormatLogMessage(ref outMessage, message, args); WriteLogInternal(outMessage, indent, 3); } /// /// Write message to log file w/o arguments. /// /// /// internal static void WriteLogEx(string message, int indent) { WriteLogInternal(string.Empty, 0, -1); WriteLogInternal(message, indent, 3); } /// /// Write message to log file w/o arguments. /// /// /// internal static void WriteLogEx() { WriteLogInternal(string.Empty, 0, -1); WriteLogInternal(string.Empty, 0, 3); } /// /// Format the message. /// /// /// /// [Conditional("LOGENABLE")] private static void FormatLogMessage(ref string outMessage, string message, params object[] args) { outMessage = string.Format(CultureInfo.CurrentCulture, message, args); } /// /// Write message to log file named @logFile /// with indent space ahead of the message. /// /// /// [Conditional("LOGENABLE")] private static void WriteLogInternal(string message, int indent, int depth) { if (!logInitialized) { lock (logLock) { if (!logInitialized) { DebugHelper.GenerateLog = File.Exists(logFile); logInitialized = true; } } } if (generateLog) { if (indent < 0) { indent = 0; } if (indent > 5) { indent = 5; } string sourceInformation = string.Empty; if (depth != -1) { sourceInformation = string.Format( CultureInfo.InvariantCulture, "Thread {0}#{1}:{2}:{3} {4}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, GetSourceCodeInformation(true, depth)); } lock (logLock) { using (FileStream fs = new FileStream(logFile, FileMode.OpenOrCreate)) using (StreamWriter writer = new StreamWriter(fs)) { writer.WriteLineAsync(spaces[indent] + sourceInformation + @" " + message); } } } } } /// /// /// Helper class used to validate given parameter /// /// internal static class ValidationHelper { /// /// Validate the argument is not null. /// /// /// public static void ValidateNoNullArgument(object obj, string argumentName) { if (obj == null) { throw new ArgumentNullException(argumentName); } } /// /// Validate the argument is not null and not whitespace. /// /// /// public static void ValidateNoNullorWhiteSpaceArgument(string obj, string argumentName) { if (string.IsNullOrWhiteSpace(obj)) { throw new ArgumentException(argumentName); } } /// /// Validate that given classname/propertyname is a valid name compliance with DMTF standard. /// Only for verifying ClassName and PropertyName argument. /// /// /// /// /// Throw if the given value is not a valid name (class name or property name). public static string ValidateArgumentIsValidName(string parameterName, string value) { DebugHelper.WriteLogEx(); if (value != null) { string trimed = value.Trim(); // The first character should be contained in set: [A-Za-z_] // Inner characters should be contained in set: [A-Za-z0-9_] Regex regex = new Regex(@"^[a-zA-Z_][a-zA-Z0-9_]*\z"); if (regex.IsMatch(trimed)) { DebugHelper.WriteLogEx("A valid name: {0}={1}", 0, parameterName, value); return trimed; } } DebugHelper.WriteLogEx("An invalid name: {0}={1}", 0, parameterName, value); throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, Strings.InvalidParameterValue, value, parameterName)); } /// /// Validate given arry argument contains all valid name (for -SelectProperties). /// * is valid for this case. /// /// /// /// /// Throw if the given value contains any invalid name (class name or property name). public static string[] ValidateArgumentIsValidName(string parameterName, string[] value) { if (value != null) { foreach (string propertyName in value) { // * is wild char supported in select properties if ((propertyName != null) && (string.Compare(propertyName.Trim(), "*", StringComparison.OrdinalIgnoreCase) == 0)) { continue; } ValidationHelper.ValidateArgumentIsValidName(parameterName, propertyName); } } return value; } } }