/// <summary> /// AnalyzeScript: Analyzes the ast to check that $null is on the left side of any equality comparisons. /// <param name="ast">The script's ast</param> /// <param name="fileName">The script's file name</param> /// <returns>The diagnostic results of this rule</returns> /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> binExpressionAsts = ast.FindAll(testAst => testAst is BinaryExpressionAst, false); foreach (BinaryExpressionAst binExpressionAst in binExpressionAsts) { if ((binExpressionAst.Operator.Equals(TokenKind.Equals) || binExpressionAst.Operator.Equals(TokenKind.Ceq) || binExpressionAst.Operator.Equals(TokenKind.Cne) || binExpressionAst.Operator.Equals(TokenKind.Ine) || binExpressionAst.Operator.Equals(TokenKind.Ieq)) && binExpressionAst.Right.Extent.Text.Equals("$null", StringComparison.OrdinalIgnoreCase)) { if (IncorrectComparisonWithNull(binExpressionAst, ast)) { yield return new DiagnosticRecord(Strings.PossibleIncorrectComparisonWithNullError, binExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } IEnumerable<Ast> funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true).Union(ast.FindAll(item => item is FunctionMemberAst, true)); foreach (Ast funcAst in funcAsts) { IEnumerable<Ast> binAsts = funcAst.FindAll(item => item is BinaryExpressionAst, true); foreach (BinaryExpressionAst binAst in binAsts) { if (IncorrectComparisonWithNull(binAst, funcAst)) { yield return new DiagnosticRecord(Strings.PossibleIncorrectComparisonWithNullError, binAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } }
/// <summary> /// AnalyzeScript: Analyzes the ast to check that cmdlets that have a Credential parameter accept PSCredential. /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The script's file name</param> /// <returns>A List of diagnostic results of this rule</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> funcDefAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); IEnumerable<Ast> scriptBlockAsts = ast.FindAll(testAst => testAst is ScriptBlockAst, true); string funcName; foreach (FunctionDefinitionAst funcDefAst in funcDefAsts) { funcName = funcDefAst.Name; if (funcDefAst.Parameters != null) { foreach (ParameterAst parameter in funcDefAst.Parameters) { if (WrongCredentialUsage(parameter)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeError, funcName), funcDefAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } if (funcDefAst.Body.ParamBlock != null) { foreach (ParameterAst parameter in funcDefAst.Body.ParamBlock.Parameters) { if (WrongCredentialUsage(parameter)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeError, funcName), funcDefAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } foreach (ScriptBlockAst scriptBlockAst in scriptBlockAsts) { // check for the case where it's parent is function, in that case we already processed above if (scriptBlockAst.Parent != null && scriptBlockAst.Parent is FunctionDefinitionAst) { continue; } if (scriptBlockAst.ParamBlock != null && scriptBlockAst.ParamBlock.Parameters != null) { foreach (ParameterAst parameter in scriptBlockAst.ParamBlock.Parameters) { if (WrongCredentialUsage(parameter)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeErrorSB), scriptBlockAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } }
/// <summary> /// AnalyzeScript: Analyzes the ast to check that cmdlets that have a Credential parameter accept PSCredential. /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The script's file name</param> /// <returns>A List of diagnostic results of this rule</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> funcDefAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); IEnumerable<Ast> scriptBlockAsts = ast.FindAll(testAst => testAst is ScriptBlockAst, true); string funcName; foreach (FunctionDefinitionAst funcDefAst in funcDefAsts) { funcName = funcDefAst.Name; if (funcDefAst.Parameters != null) { foreach (ParameterAst parameter in funcDefAst.Parameters) { if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase) && parameter.StaticType != typeof(PSCredential)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeError, funcName), funcDefAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } if (funcDefAst.Body.ParamBlock != null) { foreach (ParameterAst parameter in funcDefAst.Body.ParamBlock.Parameters) { if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase) && parameter.StaticType != typeof(PSCredential)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeError, funcName), funcDefAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } foreach (ScriptBlockAst scriptBlockAst in scriptBlockAsts) { if (scriptBlockAst.ParamBlock != null && scriptBlockAst.ParamBlock.Parameters != null) { foreach (ParameterAst parameter in scriptBlockAst.ParamBlock.Parameters) { if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase) && parameter.StaticType != typeof(PSCredential)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeErrorSB), scriptBlockAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } }
/// <summary> /// AvoidUsingPlainTextForPassword: Check that switch parameter does not default to true. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all ParamAsts. IEnumerable<Ast> paramAsts = ast.FindAll(testAst => testAst is ParameterAst, true); // Iterates all ParamAsts and check if any are switch. foreach (ParameterAst paramAst in paramAsts) { if (paramAst.Attributes.Any(attr => attr.TypeName.GetReflectionType() == typeof(System.Management.Automation.SwitchParameter)) && paramAst.DefaultValue != null && String.Equals(paramAst.DefaultValue.Extent.Text, "$true", StringComparison.OrdinalIgnoreCase)) { if (String.IsNullOrWhiteSpace(fileName)) { yield return new DiagnosticRecord( String.Format(CultureInfo.CurrentCulture, Strings.AvoidDefaultValueSwitchParameterErrorScriptDefinition), paramAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } else { yield return new DiagnosticRecord( String.Format(CultureInfo.CurrentCulture, Strings.AvoidDefaultValueSwitchParameterError, System.IO.Path.GetFileName(fileName)), paramAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } }
/// <summary> /// AnalyzeScript: Analyze the script to check if cmdlet alias is used. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all CommandAsts. IEnumerable<Ast> foundAsts = ast.FindAll(testAst => testAst is CommandAst, true); // Iterates all CommandAsts and check the command name. foreach (Ast foundAst in foundAsts) { CommandAst cmdAst = (CommandAst)foundAst; string aliasName = cmdAst.GetCommandName(); // Handles the exception caused by commands like, {& $PLINK $args 2> $TempErrorFile}. // You can also review the remark section in following document, // MSDN: CommandAst.GetCommandName Method if (aliasName == null) { continue; } string cmdletName = Helper.Instance.GetCmdletNameFromAlias(aliasName); if (!String.IsNullOrEmpty(cmdletName)) { yield return new DiagnosticRecord( string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingCmdletAliasesError, aliasName, cmdletName), cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, aliasName, suggestedCorrections: GetCorrectionExtent(cmdAst, cmdletName)); } } }
/// <summary> /// AnalyzeScript: Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Rule is applicable only when PowerShell Version is < 3.0, since CIM cmdlet was introduced in 3.0 int majorPSVersion = GetPSMajorVersion(ast); if (!(3 > majorPSVersion && 0 < majorPSVersion)) { // Finds all CommandAsts. IEnumerable<Ast> commandAsts = ast.FindAll(testAst => testAst is CommandAst, true); // Iterate all CommandAsts and check the command name foreach (CommandAst cmdAst in commandAsts) { if (cmdAst.GetCommandName() != null && (String.Equals(cmdAst.GetCommandName(), "get-wmiobject", StringComparison.OrdinalIgnoreCase) || String.Equals(cmdAst.GetCommandName(), "remove-wmiobject", StringComparison.OrdinalIgnoreCase) || String.Equals(cmdAst.GetCommandName(), "invoke-wmimethod", StringComparison.OrdinalIgnoreCase) || String.Equals(cmdAst.GetCommandName(), "register-wmievent", StringComparison.OrdinalIgnoreCase) || String.Equals(cmdAst.GetCommandName(), "set-wmiinstance", StringComparison.OrdinalIgnoreCase)) ) { yield return new DiagnosticRecord(String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMICmdletError, System.IO.Path.GetFileName(fileName)), cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } }
private static List<string> GetNodeLevelRequiredModules(Ast ast) { IEnumerable<CommandAst> importAsts = ast.FindAll(IsCommandImportDscResource, true).OfType<CommandAst>(); List<string> modules = new List<string>(); foreach (CommandAst importAst in importAsts) { // TODO: refactor code to avoid calling a script, just use StaticBindingResult directly, // once System.Management.Automation.dll version will be updated from 3.0.0.0. using (PowerShell powerShell = PowerShell.Create()) { powerShell.AddScript( @"function BindArguments($ast, $out) { $dic = ([System.Management.Automation.Language.StaticParameterBinder]::BindCommand($ast)).BoundParameters foreach ($binding in $dic.GetEnumerator()) { if ($binding.Key -like ""[N]*"") { $out.Add( (Get-DscResource $binding.Value.Value.Value).Module.Name ) } else {if ($binding.Key -like ""[M]*"") { $out.Add( $binding.Value.Value.Value ) }} } }"); powerShell.Invoke(); powerShell.Commands.Clear(); powerShell.AddCommand("BindArguments").AddParameter("ast", importAst).AddParameter("out", modules); powerShell.Invoke(); } } return modules; }
/// <summary> /// AnalyzeScript: Check that cmdlets are invoked with the correct mandatory parameter /// </summary> /// <param name="ast"></param> /// <param name="fileName"></param> /// <returns></returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all CommandAsts. IEnumerable<Ast> foundAsts = ast.FindAll(testAst => testAst is CommandAst, true); // Iterates all CommandAsts and check the command name. foreach (Ast foundAst in foundAsts) { CommandAst cmdAst = (CommandAst)foundAst; // Handles the exception caused by commands like, {& $PLINK $args 2> $TempErrorFile}. // You can also review the remark section in following document, // MSDN: CommandAst.GetCommandName Method if (cmdAst.GetCommandName() == null) continue; // Checks mandatory parameters. if (!IsMandatoryParameterExisted(cmdAst)) { yield return new DiagnosticRecord(String.Format(CultureInfo.CurrentCulture, Strings.UseCmdletCorrectlyError, cmdAst.GetCommandName()), cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } }
/// <summary> /// AnalyzeScript: Analyzes the script to check if any non-constant members have been invoked. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> memberExpression = ast.FindAll(testAst => testAst is MemberExpressionAst, true); foreach (MemberExpressionAst member in memberExpression) { string context = member.Member.Extent.ToString(); if (context.Contains("(")) { //check if parenthesis and have non-constant members IEnumerable<Ast> binaryExpression = member.FindAll( binaryAst => binaryAst is BinaryExpressionAst, true); if (binaryExpression.Any()) { foreach (BinaryExpressionAst bin in binaryExpression) { if (!bin.Operator.Equals(null)) { yield return new DiagnosticRecord( string.Format(CultureInfo.CurrentCulture, Strings.AvoidInvokingEmptyMembersError, context), member.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } } }
/// <summary> /// AnalyzeScript: Analyzes the ast to check for reserved parameters in function definitions. /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The script's file name</param> /// <returns>A List of diagnostic results of this rule</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true); List<string> commonParamNames = typeof(CommonParameters).GetProperties().Select(param => param.Name).ToList(); foreach (FunctionDefinitionAst funcAst in funcAsts) { // this rule only applies to function with param block if (funcAst.Body != null && funcAst.Body.ParamBlock != null && funcAst.Body.ParamBlock.Attributes != null && funcAst.Body.ParamBlock.Parameters != null) { // no cmdlet binding if (!funcAst.Body.ParamBlock.Attributes.Any(attr => attr.TypeName.GetReflectionType() == typeof(CmdletBindingAttribute))) { continue; } foreach (ParameterAst paramAst in funcAst.Body.ParamBlock.Parameters) { string paramName = paramAst.Name.VariablePath.UserPath; if (commonParamNames.Contains(paramName, StringComparer.OrdinalIgnoreCase)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReservedParamsError, funcAst.Name, paramName), paramAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } }
/// <summary> /// AnalyzeScript: Check if any uninitialized variable is used. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all functionAst IEnumerable<Ast> functionAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); foreach (FunctionDefinitionAst funcAst in functionAsts) { if (funcAst.Body != null && funcAst.Body.ParamBlock != null && funcAst.Body.ParamBlock.Attributes != null && funcAst.Body.ParamBlock.Parameters != null) { // only raise this rule for function with cmdletbinding if (!funcAst.Body.ParamBlock.Attributes.Any(attr => attr.TypeName.GetReflectionType() == typeof(CmdletBindingAttribute))) { continue; } foreach (var paramAst in funcAst.Body.ParamBlock.Parameters) { bool mandatory = false; // check that param is mandatory foreach (var paramAstAttribute in paramAst.Attributes) { if (paramAstAttribute is AttributeAst) { var namedArguments = (paramAstAttribute as AttributeAst).NamedArguments; if (namedArguments != null) { foreach (NamedAttributeArgumentAst namedArgument in namedArguments) { if (String.Equals(namedArgument.ArgumentName, "mandatory", StringComparison.OrdinalIgnoreCase)) { // 2 cases: [Parameter(Mandatory)] and [Parameter(Mandatory=$true)] if (namedArgument.ExpressionOmitted || (!namedArgument.ExpressionOmitted && String.Equals(namedArgument.Argument.Extent.Text, "$true", StringComparison.OrdinalIgnoreCase))) { mandatory = true; break; } } } } } } if (!mandatory) { break; } if (paramAst.DefaultValue != null) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.AvoidDefaultValueForMandatoryParameterError, paramAst.Name.VariablePath.UserPath), paramAst.Name.Extent, GetName(), DiagnosticSeverity.Warning, fileName, paramAst.Name.VariablePath.UserPath); } } } } }
/// <summary> /// AnalyzeDSCResource: Analyzes given DSC Resource /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The name of the script file being analyzed</param> /// <returns>The results of the analysis</returns> public IEnumerable<DiagnosticRecord> AnalyzeDSCResource(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Expected TargetResource functions in the DSC Resource module List<string> expectedTargetResourceFunctionNames = new List<string>(new string[] { "Get-TargetResource", "Set-TargetResource", "Test-TargetResource" }); // Retrieve a list of Asts where the function name contains TargetResource IEnumerable<Ast> functionDefinitionAsts = (ast.FindAll(dscAst => dscAst is FunctionDefinitionAst && ((dscAst as FunctionDefinitionAst).Name.IndexOf("targetResource", StringComparison.CurrentCultureIgnoreCase) != -1), true)); List<string> targetResourceFunctionNamesInAst = new List<string>(); foreach (FunctionDefinitionAst functionDefinitionAst in functionDefinitionAsts) { targetResourceFunctionNamesInAst.Add(functionDefinitionAst.Name); } foreach (string expectedTargetResourceFunctionName in expectedTargetResourceFunctionNames) { // If the Ast does not contain the expected functions, provide a Rule violation message if (!targetResourceFunctionNamesInAst.Contains(expectedTargetResourceFunctionName, StringComparer.CurrentCultureIgnoreCase)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UseStandardDSCFunctionsInResourceError, expectedTargetResourceFunctionName), ast.Extent, GetName(), DiagnosticSeverity.Error, fileName); } } }
/// <summary> /// Checks that all defined cmdlet use singular noun /// </summary> /// <param name="ast"></param> /// <param name="fileName"></param> /// <returns></returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullCommandInfoError); IEnumerable<Ast> funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true); char[] funcSeperator = { '-' }; string[] funcNamePieces = new string[2]; foreach (FunctionDefinitionAst funcAst in funcAsts) { if (funcAst.Name != null && funcAst.Name.Contains('-')) { funcNamePieces = funcAst.Name.Split(funcSeperator); String noun = funcNamePieces[1]; var ps = System.Data.Entity.Design.PluralizationServices.PluralizationService.CreateService(CultureInfo.GetCultureInfo("en-us")); if (!ps.IsSingular(noun) && ps.IsPlural(noun)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UseSingularNounsError, funcAst.Name), funcAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } }
/// <summary> /// AnalyzeDSCClass: Analyzes dsc classes and the file and check that they have get, set and test /// </summary> /// <param name="ast"></param> /// <param name="fileName"></param> /// <returns></returns> public IEnumerable<DiagnosticRecord> AnalyzeDSCClass(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); List<string> resourceFunctionNames = new List<string>(new string[] {"Test", "Get", "Set"}); IEnumerable<Ast> dscClasses = ast.FindAll(item => item is TypeDefinitionAst && ((item as TypeDefinitionAst).IsClass) && (item as TypeDefinitionAst).Attributes.Any(attr => String.Equals("DSCResource", attr.TypeName.FullName, StringComparison.OrdinalIgnoreCase)), true); foreach (TypeDefinitionAst dscClass in dscClasses) { IEnumerable<Ast> functions = dscClass.Members.Where(member => member is FunctionMemberAst); foreach (string resourceFunctionName in resourceFunctionNames) { if (!functions.Any(function => String.Equals(resourceFunctionName, (function as FunctionMemberAst).Name))) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UseStandardDSCFunctionsInClassError, resourceFunctionName), dscClass.Extent, GetName(), DiagnosticSeverity.Error, fileName); } } } }
/// <summary> /// Analyze ast to check that all the cmdlet does not use reserved char /// </summary> /// <param name="ast"></param> /// <param name="fileName"></param> /// <returns></returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true); string reservedChars = Strings.ReserverCmdletChars; HashSet<string> exportedFunction = Helper.Instance.GetExportedFunction(ast); foreach (FunctionDefinitionAst funcAst in funcAsts) { if (funcAst.Body != null && funcAst.Body.ParamBlock != null && funcAst.Body.ParamBlock.Attributes != null) { // only raise this rule for function with cmdletbinding if (!funcAst.Body.ParamBlock.Attributes.Any(attr => attr.TypeName.GetReflectionType() == typeof(CmdletBindingAttribute))) { continue; } string funcName = Helper.Instance.FunctionNameWithoutScope(funcAst.Name); // only raise if the function is exported if (funcName != null && funcName.Intersect(reservedChars).Count() > 0 && (exportedFunction.Contains(funcAst.Name) || exportedFunction.Contains(funcName))) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReservedCmdletCharError, funcAst.Name), funcAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } }
/// <summary> /// AvoidUsingPlainTextForPassword: Check that parameter "password", "passphrase" and do not use plaintext. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all ParamAsts. IEnumerable<Ast> paramAsts = ast.FindAll(testAst => testAst is ParameterAst, true); List<String> passwords = new List<String>() {"Password", "Passphrase", "Auth", "Cred", "Credential"}; // Iterrates all ParamAsts and check if their names are on the list. foreach (ParameterAst paramAst in paramAsts) { TypeInfo paramType = (TypeInfo) paramAst.StaticType; bool hasPwd = false; String paramName = paramAst.Name.VariablePath.ToString(); foreach (String password in passwords) { if (paramName.IndexOf(password, StringComparison.OrdinalIgnoreCase) != -1) { hasPwd = true; break; } } if (hasPwd && ((!paramType.IsArray && (paramType == typeof(String) || paramType == typeof(object))) || (paramType.IsArray && (paramType.GetElementType() == typeof(String) || paramType.GetElementType() == typeof(object))))) { yield return new DiagnosticRecord( String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingPlainTextForPasswordError, paramAst.Name), paramAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } }
/// <summary> /// AnalyzeScript: Check that a function does not use both username /// and password parameters. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all functionAst IEnumerable<Ast> functionAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); List<String> passwords = new List<String>() {"Password", "Passphrase"}; List<String> usernames = new List<String>() { "Username", "User"}; foreach (FunctionDefinitionAst funcAst in functionAsts) { bool hasPwd = false; bool hasUserName = false; // Finds all ParamAsts. IEnumerable<Ast> paramAsts = funcAst.FindAll(testAst => testAst is ParameterAst, true); // Iterrates all ParamAsts and check if their names are on the list. foreach (ParameterAst paramAst in paramAsts) { TypeInfo paramType = (TypeInfo)paramAst.StaticType; String paramName = paramAst.Name.VariablePath.ToString(); if (paramType == typeof(PSCredential) || (paramType.IsArray && paramType.GetElementType() == typeof (PSCredential))) { continue; } foreach (String password in passwords) { if (paramName.IndexOf(password, StringComparison.OrdinalIgnoreCase) != -1) { hasPwd = true; break; } } foreach (String username in usernames) { if (paramName.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1) { hasUserName = true; break; } } } if (hasUserName && hasPwd) { yield return new DiagnosticRecord( String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsernameAndPasswordParamsError, funcAst.Name), funcAst.Extent, GetName(), DiagnosticSeverity.Error, fileName); } } }
/// <summary> /// AvoidShouldContinueWithoutForceCheck that if ShouldContinue is used, /// the function should have a boolean force parameter /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all ParamAsts. IEnumerable<Ast> funcAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); // Iterates all ParamAsts and check if there are any force. foreach (FunctionDefinitionAst funcAst in funcAsts) { IEnumerable<Ast> paramAsts = funcAst.FindAll(testAst => testAst is ParameterAst, true); bool hasForce = false; foreach (ParameterAst paramAst in paramAsts) { if (String.Equals(paramAst.Name.VariablePath.ToString(), "force", StringComparison.OrdinalIgnoreCase) && (String.Equals(paramAst.StaticType.FullName, "System.Boolean", StringComparison.OrdinalIgnoreCase) || String.Equals(paramAst.StaticType.FullName, "System.Management.Automation.SwitchParameter", StringComparison.OrdinalIgnoreCase))) { hasForce = true; break; } } if (hasForce) { continue; } IEnumerable<Ast> imeAsts = funcAst.FindAll(testAst => testAst is InvokeMemberExpressionAst, true); foreach (InvokeMemberExpressionAst imeAst in imeAsts) { VariableExpressionAst typeAst = imeAst.Expression as VariableExpressionAst; if (typeAst == null) continue; if (String.Equals(typeAst.VariablePath.UserPath, "pscmdlet", StringComparison.OrdinalIgnoreCase) && (String.Equals(imeAst.Member.Extent.Text, "shouldcontinue", StringComparison.OrdinalIgnoreCase))) { if (String.IsNullOrWhiteSpace(fileName)) { yield return new DiagnosticRecord( String.Format(CultureInfo.CurrentCulture, Strings.AvoidShouldContinueWithoutForceErrorScriptDefinition, funcAst.Name), imeAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } else { yield return new DiagnosticRecord( String.Format(CultureInfo.CurrentCulture, Strings.AvoidShouldContinueWithoutForceError, funcAst.Name, System.IO.Path.GetFileName(fileName)), imeAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } }
/// <summary> /// AnalyzeScript: Check if any uninitialized variable is used. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all functionAst IEnumerable<Ast> functionAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); // Checks whether this is a dsc resource file (we don't raise this rule for get, set and test-target resource bool isDscResourceFile = Helper.Instance.IsDscResourceModule(fileName); List<string> targetResourcesFunctions = new List<string>(new string[] { "get-targetresource", "set-targetresource", "test-targetresource" }); foreach (FunctionDefinitionAst funcAst in functionAsts) { // Finds all ParamAsts. IEnumerable<Ast> varAsts = funcAst.FindAll(testAst => testAst is VariableExpressionAst, true); // Iterrates all ParamAsts and check if their names are on the list. HashSet<string> dscVariables = new HashSet<string>(); if (isDscResourceFile && targetResourcesFunctions.Contains(funcAst.Name, StringComparer.OrdinalIgnoreCase)) { // don't raise the rules for variables in the param block. if (funcAst.Body != null && funcAst.Body.ParamBlock != null && funcAst.Body.ParamBlock.Parameters != null) { dscVariables.UnionWith(funcAst.Body.ParamBlock.Parameters.Select(paramAst => paramAst.Name.VariablePath.UserPath)); } } // only raise the rules for variables in the param block. if (funcAst.Body != null && funcAst.Body.ParamBlock != null && funcAst.Body.ParamBlock.Parameters != null) { foreach (var paramAst in funcAst.Body.ParamBlock.Parameters) { if (Helper.Instance.IsUninitialized(paramAst.Name, funcAst) && !dscVariables.Contains(paramAst.Name.VariablePath.UserPath)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ProvideDefaultParameterValueError, paramAst.Name.VariablePath.UserPath), paramAst.Name.Extent, GetName(), DiagnosticSeverity.Warning, fileName, paramAst.Name.VariablePath.UserPath); } } } if (funcAst.Parameters != null) { foreach (var paramAst in funcAst.Parameters) { if (Helper.Instance.IsUninitialized(paramAst.Name, funcAst) && !dscVariables.Contains(paramAst.Name.VariablePath.UserPath)) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ProvideDefaultParameterValueError, paramAst.Name.VariablePath.UserPath), paramAst.Name.Extent, GetName(), DiagnosticSeverity.Warning, fileName, paramAst.Name.VariablePath.UserPath); } } } } }
/// <summary> /// AnalyzeScript: Checks that objects return in a cmdlet have their types declared in OutputType Attribute /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The name of the script</param> /// <returns>A List of diagnostic results of this rule</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); DiagnosticRecords.Clear(); this.fileName = fileName; _classes = ast.FindAll(item => item is TypeDefinitionAst && ((item as TypeDefinitionAst).IsClass), true).Cast<TypeDefinitionAst>(); ast.Visit(this); return DiagnosticRecords; }
/// <summary> /// AnalyzeDSCResource: Analyzes given DSC Resource /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The name of the script file being analyzed</param> /// <returns>The results of the analysis</returns> public IEnumerable<DiagnosticRecord> AnalyzeDSCResource(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // TODO: Add logic for DSC Resources IEnumerable<Ast> functionDefinitionAsts = Helper.Instance.DscResourceFunctions(ast); IEnumerable<TypeDefinitionAst> classes = ast.FindAll(item => item is TypeDefinitionAst && ((item as TypeDefinitionAst).IsClass), true).Cast<TypeDefinitionAst>(); foreach (FunctionDefinitionAst func in functionDefinitionAsts) { List<Tuple<string, StatementAst>> outputTypes = FindPipelineOutput.OutputTypes(func, classes); if (String.Equals(func.Name, "Set-TargetResource", StringComparison.OrdinalIgnoreCase)) { foreach (Tuple<string, StatementAst> outputType in outputTypes) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReturnCorrectTypesForSetTargetResourceFunctionsDSCError), outputType.Item2.Extent, GetName(), DiagnosticSeverity.Information, fileName); } } else { Dictionary<string, string> returnTypes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); returnTypes["Get-TargetResource"] = typeof(System.Collections.Hashtable).FullName; returnTypes["Test-TargetResource"] = typeof(bool).FullName; foreach (Tuple<string, StatementAst> outputType in outputTypes) { string type = outputType.Item1; if (String.IsNullOrEmpty(type) || String.Equals(typeof(Unreached).FullName, type, StringComparison.OrdinalIgnoreCase) || String.Equals(typeof(Undetermined).FullName, type, StringComparison.OrdinalIgnoreCase) || String.Equals(typeof(object).FullName, type, StringComparison.OrdinalIgnoreCase) || String.Equals(type, returnTypes[func.Name], StringComparison.OrdinalIgnoreCase)) { continue; } else { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReturnCorrectTypesForGetTestTargetResourceFunctionsDSCResourceError, func.Name, returnTypes[func.Name], type), outputType.Item2.Extent, GetName(), DiagnosticSeverity.Information, fileName); } } } } }
/// <summary> /// AnalyzeScript: Analyzes the ast to check if ShouldProcess is included in Advanced functions if the Verb of the function could change system state. /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The script's file name</param> /// <returns>A List of diagnostic results of this rule</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> funcDefAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); string supportsShouldProcess = "SupportsShouldProcess"; string trueString = "$true"; foreach (FunctionDefinitionAst funcDefAst in funcDefAsts) { string funcName = funcDefAst.Name; bool hasShouldProcessAttribute = false; if (funcName.StartsWith("Restart-", StringComparison.OrdinalIgnoreCase) || funcName.StartsWith("Stop-", StringComparison.OrdinalIgnoreCase)|| funcName.StartsWith("New-", StringComparison.OrdinalIgnoreCase) || funcName.StartsWith("Set-", StringComparison.OrdinalIgnoreCase) || funcName.StartsWith("Update-", StringComparison.OrdinalIgnoreCase) || funcName.StartsWith("Reset-", StringComparison.OrdinalIgnoreCase)) { IEnumerable<Ast> attributeAsts = funcDefAst.FindAll(testAst => testAst is NamedAttributeArgumentAst, true); if (funcDefAst.Body != null && funcDefAst.Body.ParamBlock != null && funcDefAst.Body.ParamBlock.Attributes != null && funcDefAst.Body.ParamBlock.Parameters != null) { if (!funcDefAst.Body.ParamBlock.Attributes.Any(attr => attr.TypeName.GetReflectionType() == typeof (CmdletBindingAttribute))) { continue; } foreach (NamedAttributeArgumentAst attributeAst in attributeAsts) { if (attributeAst.ArgumentName.Equals(supportsShouldProcess, StringComparison.OrdinalIgnoreCase)) { if((attributeAst.Argument.Extent.Text.Equals(trueString, StringComparison.OrdinalIgnoreCase)) && !attributeAst.ExpressionOmitted || attributeAst.ExpressionOmitted) { hasShouldProcessAttribute = true; } } } if (!hasShouldProcessAttribute) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture,Strings.UseShouldProcessForStateChangingFunctionsError, funcName),funcDefAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } } }
private static FunctionDefinitionAst FindDefinition(CommandAst ast, Ast parentAst) { if (ast == null) throw new ArgumentNullException("ast"); if (parentAst == null) return null; var definitions = parentAst.FindAll( m => m is FunctionDefinitionAst && ((FunctionDefinitionAst) m).Name.Equals(ast.GetCommandName()), false).ToList(); if (definitions.Any()) { return definitions.Last() as FunctionDefinitionAst; } return FindDefinition(ast, parentAst.Parent); }
/// <summary> /// AnalyzeScript: Analyzes the ast to check if ShouldProcess is included in Advanced functions if the Verb of the function could change system state. /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The script's file name</param> /// <returns>A List of diagnostic results of this rule</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) { throw new ArgumentNullException(Strings.NullAstErrorMessage); } IEnumerable<Ast> funcDefWithNoShouldProcessAttrAsts = ast.FindAll(IsStateChangingFunctionWithNoShouldProcessAttribute, true); foreach (FunctionDefinitionAst funcDefAst in funcDefWithNoShouldProcessAttrAsts) { yield return new DiagnosticRecord( string.Format(CultureInfo.CurrentCulture, Strings.UseShouldProcessForStateChangingFunctionsError, funcDefAst.Name), Helper.Instance.GetScriptExtentForFunctionName(funcDefAst), this.GetName(), DiagnosticSeverity.Warning, fileName); } }
/// <summary> /// Analyze ast to check that all the cmdlet does not use reserved char /// </summary> /// <param name="ast"></param> /// <param name="fileName"></param> /// <returns></returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true); string reservedChars = Strings.ReserverCmdletChars; foreach (FunctionDefinitionAst funcAst in funcAsts) { if (funcAst.Name != null && funcAst.Name.Intersect(reservedChars).Count() > 0) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReservedCmdletCharError, funcAst.Name), funcAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } }
/// <summary> /// GetPSMajorVersion: Retrieves Major PowerShell Version when supplied using #requires keyword in the script /// </summary> /// <returns>The name of this rule</returns> private int GetPSMajorVersion(Ast ast) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> scriptBlockAsts = ast.FindAll(testAst => testAst is ScriptBlockAst, true); foreach (ScriptBlockAst scriptBlockAst in scriptBlockAsts) { if (null != scriptBlockAst.ScriptRequirements && null != scriptBlockAst.ScriptRequirements.RequiredPSVersion) { return scriptBlockAst.ScriptRequirements.RequiredPSVersion.Major; } } // return a non valid Major version if #requires -Version is not supplied in the Script return -1; }
// Static Method to parse a script file public static List <Node> ParseFile(string file) { string script = File.ReadAllText(file); FileInfo ScriptFileInfo = new FileInfo(file); ScriptBlock scriptblock = ScriptBlock.Create(script); Ast NamedBlock = scriptblock.Ast.Find(Args => Args is NamedBlockAst, false); // IEnumerable<Ast> enumerable = NamedBlock.FindAll(Args => Args is Ast && FlowChartCore.Utility.GetValidTypes().Contains(Args.GetType()) && Args.Parent == NamedBlock, false); IEnumerable <Ast> enumerable = NamedBlock.FindAll(Args => Args is Ast && Args.Parent == NamedBlock, false); int Position = 1; List <Node> Nodes = new List <Node>(); Tree Arbre = new Tree(Nodes, scriptblock.Ast, NodesOrigin.File, ScriptFileInfo); bool tmp = true; foreach (var block in enumerable) { if (FlowChartCore.Utility.GetValidTypes().Contains(block.GetType())) { // valid type found Node tmpNode = block.CreateNode(0, Position, null, Arbre); // tmpNode.Origin = NodesOrigin.File; // tmpNode.FileInfo = ScriptFileInfo; Nodes.Add(tmpNode); Position++; // reset tmp tmp = true; } else if (tmp) { // not a valid type, and tmp is false, create code node tmp = false; Node tmpNode = new CodeNode(0, Position, null, Arbre); // tmpNode.Origin = NodesOrigin.File; // tmpNode.FileInfo = ScriptFileInfo; Nodes.Add(tmpNode); Position++; } } return(Arbre.Nodes); }
/// <summary> /// Analyze script to check that all defined functions use approved verbs /// </summary> /// <param name="ast"></param> /// <param name="fileName"></param> /// <returns></returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); List<string> approvedVerbs = typeof(VerbsCommon).GetFields().Concat<FieldInfo>( typeof(VerbsCommunications).GetFields()).Concat<FieldInfo>( typeof(VerbsData).GetFields()).Concat<FieldInfo>( typeof(VerbsDiagnostic).GetFields()).Concat<FieldInfo>( typeof(VerbsLifecycle).GetFields()).Concat<FieldInfo>( typeof(VerbsSecurity).GetFields()).Concat<FieldInfo>( typeof(VerbsOther).GetFields()).Select<FieldInfo, String>( item => item.Name).ToList(); string funcName; char[] funcSeperator = { '-' }; string[] funcNamePieces = new string[2]; string verb; IEnumerable<Ast> funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true); foreach (FunctionDefinitionAst funcAst in funcAsts) { funcName = Helper.Instance.FunctionNameWithoutScope(funcAst.Name); if (funcName != null && funcName.Contains('-')) { funcNamePieces = funcName.Split(funcSeperator); verb = funcNamePieces[0]; if (!approvedVerbs.Contains(verb, StringComparer.OrdinalIgnoreCase)) { IScriptExtent extent = Helper.Instance.GetScriptExtentForFunctionName(funcAst); if (null == extent) { extent = funcAst.Extent; } yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UseApprovedVerbsError, funcName), extent, GetName(), DiagnosticSeverity.Warning, fileName); } } } }
/// <summary> /// AnalyzeScript: Analyze the script to check if any empty catch block is used. /// </summary> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); // Finds all CommandAsts. IEnumerable<Ast> foundAsts = ast.FindAll(testAst => testAst is CatchClauseAst, true); // Iterrates all CatchClauseAst and check the statements count. foreach (Ast foundAst in foundAsts) { CatchClauseAst catchAst = (CatchClauseAst)foundAst; if (catchAst.Body.Statements.Count == 0) { yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.AvoidEmptyCatchBlockError), catchAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); } } }
private static List <string> GetRequiredModulesFromAst(Ast ast) { List <string> modules = new List <string>(); // We use System.Management.Automation.Language.Parser to extract required modules from ast, // but format of ast is a bit tricky and have changed in time. // // There are two place where 'Import-DscResource' keyword can appear: // 1) // Configuration Foo { // Import-DscResource .... # outside node // Node Bar {...} // } // 2) // Configuration Foo { // Node Bar { // Import-DscResource .... # inside node // ... // } // } // // The old version of System.Management.Automation.Language.Parser produces slightly different AST for the first case. // In new version, Configuration corresponds to ConfigurationDefinitionAst. // In old version is's a generic CommandAst with specific commandElements which capture top-level Imports (case 1). // In new version all imports correspond to their own CommandAsts, same for case 2 in old version. // Old version, case 1: IEnumerable <CommandAst> legacyConfigurationAsts = ast.FindAll(IsLegacyAstConfiguration, true).Select(x => (CommandAst)x); foreach (var legacyConfigurationAst in legacyConfigurationAsts) { // Example: Import-DscResource -Module xPSDesiredStateConfiguration modules.AddRange(GetLegacyTopLevelParametersFromAst(legacyConfigurationAst, "ModuleDefinition")); // Example: Import-DscResource -Name MSFT_xComputer modules.AddRange(GetLegacyTopLevelParametersFromAst(legacyConfigurationAst, "ResourceDefinition").Select(GetModuleNameForDscResource)); } // Both cases in new version and 2 case in old version: modules.AddRange(GetNodeLevelRequiredModules(ast)); return(modules.Distinct().ToList()); }
/// <summary> /// AnalyzeScript: Analyzes the ast to check that global variables are not used. From the ILintScriptRule interface. /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The script's file name</param> /// <returns>A List of diagnostic results of this rule</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); IEnumerable<Ast> varAsts = ast.FindAll(testAst => testAst is VariableExpressionAst, true); if (varAsts != null) { foreach (VariableExpressionAst varAst in varAsts) { if (Helper.Instance.IsVariableGlobal(varAst)) { yield return new DiagnosticRecord( string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalVarsError, varAst.VariablePath.UserPath), varAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, varAst.VariablePath.UserPath); } } } }
/// <summary> /// AnalyzeScript: Analyzes the given Ast and returns DiagnosticRecords based on the analysis. /// </summary> /// <param name="ast">The script's ast</param> /// <param name="fileName">The name of the script file being analyzed</param> /// <returns>The results of the analysis</returns> public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException("ast"); // Finds all CommandAsts. IEnumerable<Ast> commandAsts = ast.FindAll(testAst => testAst is CommandAst, true); List<String> cmdletNameAndAliases = Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper.Instance.CmdletNameAndAliases(GetCmdletName()); // Iterates all CommandAsts and check the command name. foreach (CommandAst cmdAst in commandAsts) { if (cmdAst.GetCommandName() == null) continue; if (cmdletNameAndAliases.Contains(cmdAst.GetCommandName(), StringComparer.OrdinalIgnoreCase)) { yield return new DiagnosticRecord(GetError(fileName), cmdAst.Extent, GetName(), GetDiagnosticSeverity(), fileName); } } }
/// <summary> /// AnalyzeScript: Analyze the script to check if cmdlet alias is used. /// </summary> public IEnumerable <DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) { if (ast == null) { throw new ArgumentNullException(Strings.NullAstErrorMessage); } if (!isPropertiesSet) { SetProperties(); } // Finds all CommandAsts. IEnumerable <Ast> foundAsts = ast.FindAll(testAst => testAst is CommandAst, true); // Iterates all CommandAsts and check the command name. foreach (Ast foundAst in foundAsts) { CommandAst cmdAst = (CommandAst)foundAst; string aliasName = cmdAst.GetCommandName(); // Handles the exception caused by commands like, {& $PLINK $args 2> $TempErrorFile}. // You can also review the remark section in following document, // MSDN: CommandAst.GetCommandName Method if (aliasName == null || whiteList.Contains(aliasName)) { continue; } string cmdletName = Helper.Instance.GetCmdletNameFromAlias(aliasName); if (!String.IsNullOrEmpty(cmdletName)) { yield return(new DiagnosticRecord( string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingCmdletAliasesError, aliasName, cmdletName), cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, aliasName, suggestedCorrections: GetCorrectionExtent(cmdAst, cmdletName))); } } }