public void AstParser()
        {
            ScriptBlockAst sb = System.Management.Automation.Language.Parser.ParseInput(sampleScript, out tokens, out ParseError[] errors);

            // AST type list https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.language?view=powershellsdk-1.1.0
            IEnumerable <Ast> astnodeList = sb.FindAll(delegate(Ast t)
                                                       { return(true); }
                                                       , true);


            foreach (var astnode in astnodeList)
            {
                asttypeList.Add(astnode.GetType().ToString());
            }
        }
Esempio n. 2
0
        public static ConfigurationParseResult ExtractConfigurationNames(string path)
        {
            // Get the resolved script path. This will throw an exception if the file is not found.
            string fullPath = Path.GetFullPath(path);

            Token[]      tokens;
            ParseError[] errors;
            // Parse the script into an AST, capturing parse errors. Note - even with errors, the
            // file may still successfully define one or more configurations.
            ScriptBlockAst           ast     = Parser.ParseFile(fullPath, out tokens, out errors);
            IEnumerable <CommandAst> configs = ast.FindAll(IsAstConfiguration, true).Select(x => (CommandAst)x);

            List <string> requiredModules = configs.Select(GetRequiredModulesFromAst).SelectMany(x => x).Distinct().ToList();

            return(new ConfigurationParseResult()
            {
                Path = fullPath,
                Errors = errors,
                RequiredModules = requiredModules,
            });
        }
Esempio n. 3
0
        /// <summary>
        /// Get the UsingExpressionAsts out of a script
        /// </summary>
        /// <param name="script"></param>
        /// <returns>a list of UsingExpressionAsts ordered by the StartOffset</returns>
        private static IEnumerable <Ast> GetUsingExpressionAsts(string script)
        {
            if (String.IsNullOrEmpty(script))
            {
                return(null);
            }

            ParseError[]   errors;
            Token[]        tokens;
            ScriptBlockAst scriptAst = Parser.ParseInput(script, out tokens, out errors);

            if (errors.Length != 0)
            {
                return(null);
            }

            var list = scriptAst.FindAll(ast => ast is UsingExpressionAst, searchNestedScriptBlocks: true).ToList();

            if (list.Count > 1)
            {
                return(list.OrderBy(a => a.Extent.StartOffset));
            }
            return(list);
        }
        protected static bool DiscoverPesterTests(string source, TestDescribeCollection tests, IMessageLogger logger)
        {
            if (!File.Exists(source))
            {
                return(false);
            }
            //SendMessage(TestMessageLevel.Informational, string.Format(Resources.SearchingForTestsFormat, source), logger);
            Token[]        tokens;
            ParseError[]   errors;
            ScriptBlockAst ast = Parser.ParseFile(source, out tokens, out errors);

            //if (errors.Any())
            //{
            //    foreach (var error in errors)
            //    {
            //        SendMessage(TestMessageLevel.Error, string.Format(Resources.ParserErrorFormat, error.Message), logger);
            //    }
            //    return;
            //}

            IEnumerable <Ast> testSuites =
                ast.FindAll(
                    m =>
                    (m is CommandAst) &&
                    string.Equals("describe", ((CommandAst)m).GetCommandName(), StringComparison.OrdinalIgnoreCase), true);

            foreach (Ast describeAst in testSuites)
            {
                string describeName = GetFunctionName(logger, describeAst, "describe");
                Dictionary <string, TestContext> contextByName = new Dictionary <string, TestContext>();

                //IEnumerable<string> tags = GetDescribeTags(logger, describeAst);

                IEnumerable <Ast> its = describeAst.FindAll(m => (m as CommandAst)?.GetCommandName()?.Equals("it", StringComparison.OrdinalIgnoreCase) == true, true);

                foreach (Ast test in its)
                {
                    CommandAst itAst       = (CommandAst)test;
                    string     itName      = GetFunctionName(logger, test, "it");
                    string     contextName = GetParentContextName(logger, test);

                    if (!contextByName.TryGetValue(contextName, out TestContext context))
                    {
                        context = new TestContext
                        {
                            Name = contextName,
                            Path = source
                        };
                        contextByName.Add(contextName, context);
                    }

                    // Didn't find the name for the test. Skip it.
                    if (string.IsNullOrEmpty(itName))
                    {
                        SendMessage(TestMessageLevel.Informational, "Test name was empty. Skipping test.", logger);
                        continue;
                    }

                    TestIt it = new TestIt
                    {
                        Name   = itName,
                        Ast    = itAst,
                        Path   = source,
                        LineNr = itAst.Extent.StartLineNumber
                    };

                    context.Its.Add(it);
                }
                if (contextByName.Count > 0)
                {
                    TestDescribe describe = new TestDescribe
                    {
                        Name   = describeName,
                        Ast    = describeAst,
                        Path   = source,
                        LineNr = describeAst.Extent.StartLineNumber
                    };
                    foreach (TestContext context in contextByName.Values)
                    {
                        describe.Contexts.Add(context);
                    }
                    tests.Add(describe);
                }
            }
            return(true);
        }
Esempio n. 5
0
        /// <summary>
        /// Checks if a variable is initialized and referenced in either its assignment or children scopes
        /// </summary>
        /// <param name="scriptBlockAst">Ast of type ScriptBlock</param>
        /// <param name="fileName">Name of file containing the ast</param>
        /// <returns>An enumerable containing diagnostic records</returns>
        private IEnumerable <DiagnosticRecord> AnalyzeScriptBlockAst(ScriptBlockAst scriptBlockAst, string fileName)
        {
            IEnumerable <Ast> assignmentAsts = scriptBlockAst.FindAll(testAst => testAst is AssignmentStatementAst, false);
            IEnumerable <Ast> varAsts        = scriptBlockAst.FindAll(testAst => testAst is VariableExpressionAst, true);
            IEnumerable <Ast> varsInAssignment;

            Dictionary <string, AssignmentStatementAst> assignments = new Dictionary <string, AssignmentStatementAst>(StringComparer.OrdinalIgnoreCase);

            string varKey;
            bool   inAssignment;

            if (assignmentAsts == null)
            {
                yield break;
            }

            foreach (AssignmentStatementAst assignmentAst in assignmentAsts)
            {
                // Only checks for the case where lhs is a variable. Ignore things like $foo.property
                VariableExpressionAst assignmentVarAst = assignmentAst.Left as VariableExpressionAst;

                if (assignmentVarAst != null)
                {
                    // Ignore if variable is global or environment variable or scope is function
                    if (!Helper.Instance.IsVariableGlobalOrEnvironment(assignmentVarAst, scriptBlockAst) &&
                        !assignmentVarAst.VariablePath.IsScript &&
                        !string.Equals(assignmentVarAst.VariablePath.DriveName, "function", StringComparison.OrdinalIgnoreCase))
                    {
                        string variableName = Helper.Instance.VariableNameWithoutScope(assignmentVarAst.VariablePath);

                        if (!assignments.ContainsKey(variableName))
                        {
                            assignments.Add(variableName, assignmentAst);
                        }
                    }
                }
            }

            if (varAsts != null)
            {
                foreach (VariableExpressionAst varAst in varAsts)
                {
                    varKey       = Helper.Instance.VariableNameWithoutScope(varAst.VariablePath);
                    inAssignment = false;

                    if (assignments.ContainsKey(varKey))
                    {
                        varsInAssignment = assignments[varKey].Left.FindAll(testAst => testAst is VariableExpressionAst, true);

                        // Checks if this variableAst is part of the logged assignment
                        foreach (VariableExpressionAst varInAssignment in varsInAssignment)
                        {
                            inAssignment |= varInAssignment.Equals(varAst);
                        }

                        if (!inAssignment)
                        {
                            assignments.Remove(varKey);
                        }

                        // Check if variable belongs to PowerShell built-in variables
                        if (Helper.Instance.HasSpecialVars(varKey))
                        {
                            assignments.Remove(varKey);
                        }
                    }
                }
            }

            foreach (string key in assignments.Keys)
            {
                yield return(new DiagnosticRecord(
                                 string.Format(CultureInfo.CurrentCulture, Strings.UseDeclaredVarsMoreThanAssignmentsError, key),
                                 assignments[key].Left.Extent,
                                 GetName(),
                                 DiagnosticSeverity.Warning,
                                 fileName,
                                 key));
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Checks if a variable is initialized and referenced in either its assignment or children scopes
        /// </summary>
        /// <param name="scriptBlockAst">Ast of type ScriptBlock</param>
        /// <param name="fileName">Name of file containing the ast</param>
        /// <returns>An enumerable containing diagnostic records</returns>
        private IEnumerable <DiagnosticRecord> AnalyzeScriptBlockAst(ScriptBlockAst scriptBlockAst, string fileName)
        {
            IEnumerable <Ast> assignmentAsts = scriptBlockAst.FindAll(testAst => testAst is AssignmentStatementAst, false);
            IEnumerable <Ast> varAsts        = scriptBlockAst.FindAll(testAst => testAst is VariableExpressionAst, true);
            IEnumerable <Ast> varsInAssignment;

            Dictionary <string, AssignmentStatementAst> assignmentsDictionary_OrdinalIgnoreCase = new Dictionary <string, AssignmentStatementAst>(StringComparer.OrdinalIgnoreCase);

            string varKey;
            bool   inAssignment;

            if (assignmentAsts == null)
            {
                yield break;
            }

            foreach (AssignmentStatementAst assignmentAst in assignmentAsts)
            {
                // Only checks for the case where lhs is a variable. Ignore things like $foo.property
                VariableExpressionAst assignmentVarAst = assignmentAst.Left as VariableExpressionAst;

                if (assignmentVarAst == null)
                {
                    // If the variable is declared in a strongly typed way, e.g. [string]$s = 'foo' then the type is ConvertExpressionAst.
                    // Therefore we need to the VariableExpressionAst from its Child property.
                    var assignmentVarAstAsConvertExpressionAst = assignmentAst.Left as ConvertExpressionAst;
                    if (assignmentVarAstAsConvertExpressionAst != null && assignmentVarAstAsConvertExpressionAst.Child != null)
                    {
                        assignmentVarAst = assignmentVarAstAsConvertExpressionAst.Child as VariableExpressionAst;
                    }
                }

                if (assignmentVarAst != null)
                {
                    // Ignore if variable is global or environment variable or scope is drive qualified variable
                    if (!Helper.Instance.IsVariableGlobalOrEnvironment(assignmentVarAst, scriptBlockAst) &&
                        !assignmentVarAst.VariablePath.IsScript &&
                        assignmentVarAst.VariablePath.DriveName == null)
                    {
                        string variableName = Helper.Instance.VariableNameWithoutScope(assignmentVarAst.VariablePath);

                        if (!assignmentsDictionary_OrdinalIgnoreCase.ContainsKey(variableName))
                        {
                            assignmentsDictionary_OrdinalIgnoreCase.Add(variableName, assignmentAst);
                        }
                    }
                }
            }

            if (varAsts != null)
            {
                foreach (VariableExpressionAst varAst in varAsts)
                {
                    varKey       = Helper.Instance.VariableNameWithoutScope(varAst.VariablePath);
                    inAssignment = false;

                    if (assignmentsDictionary_OrdinalIgnoreCase.ContainsKey(varKey))
                    {
                        varsInAssignment = assignmentsDictionary_OrdinalIgnoreCase[varKey].Left.FindAll(testAst => testAst is VariableExpressionAst, true);

                        // Checks if this variableAst is part of the logged assignment
                        foreach (VariableExpressionAst varInAssignment in varsInAssignment)
                        {
                            // Try casting to AssignmentStatementAst to be able to catch case where a variable is assigned more than once (https://github.com/PowerShell/PSScriptAnalyzer/issues/833)
                            var varInAssignmentAsStatementAst  = varInAssignment.Parent as AssignmentStatementAst;
                            var varAstAsAssignmentStatementAst = varAst.Parent as AssignmentStatementAst;
                            if (varAstAsAssignmentStatementAst != null)
                            {
                                if (varAstAsAssignmentStatementAst.Operator == TokenKind.Equals)
                                {
                                    if (varInAssignmentAsStatementAst != null)
                                    {
                                        inAssignment = varInAssignmentAsStatementAst.Left.Extent.Text.Equals(varAstAsAssignmentStatementAst.Left.Extent.Text, StringComparison.OrdinalIgnoreCase);
                                    }
                                    else
                                    {
                                        inAssignment = varInAssignment.Equals(varAst);
                                    }
                                }
                            }
                            else
                            {
                                inAssignment = varInAssignment.Equals(varAst);
                            }
                        }

                        if (!inAssignment)
                        {
                            assignmentsDictionary_OrdinalIgnoreCase.Remove(varKey);
                        }

                        // Check if variable belongs to PowerShell built-in variables
                        if (Helper.Instance.HasSpecialVars(varKey))
                        {
                            assignmentsDictionary_OrdinalIgnoreCase.Remove(varKey);
                        }
                    }
                }
            }

            // Detect usages of Get-Variable
            var getVariableCmdletNamesAndAliases     = Helper.Instance.CmdletNameAndAliases("Get-Variable");
            IEnumerable <Ast> getVariableCommandAsts = scriptBlockAst.FindAll(testAst => testAst is CommandAst commandAst &&
                                                                              getVariableCmdletNamesAndAliases.Contains(commandAst.GetCommandName(), StringComparer.OrdinalIgnoreCase), true);

            foreach (CommandAst getVariableCommandAst in getVariableCommandAsts)
            {
                var commandElements = getVariableCommandAst.CommandElements.ToList();
                // The following extracts the variable name only in the simplest possibe case 'Get-Variable variableName'
                if (commandElements.Count == 2 && commandElements[1] is StringConstantExpressionAst constantExpressionAst)
                {
                    var variableName = constantExpressionAst.Value;
                    if (assignmentsDictionary_OrdinalIgnoreCase.ContainsKey(variableName))
                    {
                        assignmentsDictionary_OrdinalIgnoreCase.Remove(variableName);
                    }
                }
            }

            foreach (string key in assignmentsDictionary_OrdinalIgnoreCase.Keys)
            {
                yield return(new DiagnosticRecord(
                                 string.Format(CultureInfo.CurrentCulture, Strings.UseDeclaredVarsMoreThanAssignmentsError, key),
                                 assignmentsDictionary_OrdinalIgnoreCase[key].Left.Extent,
                                 GetName(),
                                 DiagnosticSeverity.Warning,
                                 fileName,
                                 key));
            }
        }