private object GetExpressionValue(ExpressionAst exprAst, bool isTrustedInput)
 {
     // be sure that there's a context at hand
     if (_context == null)
     {
         var rs = RunspaceFactory.CreateRunspace(InitialSessionState.Create());
         rs.Open();
         _context = rs.ExecutionContext;
     }
     if (!isTrustedInput) // if it's not trusted, call the safe value visitor
     {
         return(GetSafeValueVisitor.GetSafeValue(exprAst, _context, GetSafeValueVisitor.SafeValueContext.GetPowerShell));
     }
     return(Compiler.GetExpressionValue(exprAst, isTrustedInput, _context, _usingValueMap));
 }
Beispiel #2
0
        private void ConvertCommand(CommandAst commandAst, bool isTrustedInput)
        {
            // First need command name.
            var commandName = GetCommandName(commandAst.CommandElements[0], isTrustedInput);

            var command = new Command(commandName, isScript: false, useLocalScope: _createLocalScope);

            // Handle redirections, if any (there can really be just 0 or 1).
            if (commandAst.Redirections.Count > 0)
            {
                Diagnostics.Assert(commandAst.Redirections.Count == 1, "only 1 kind of redirection is supported");
                Diagnostics.Assert(commandAst.Redirections[0] is MergingRedirectionAst, "unexpected redirection type");

                PipelineResultTypes toType = PipelineResultTypes.Output;
                PipelineResultTypes fromType;
                switch (commandAst.Redirections[0].FromStream)
                {
                case RedirectionStream.Error:
                    fromType = PipelineResultTypes.Error;
                    break;

                case RedirectionStream.Warning:
                    fromType = PipelineResultTypes.Warning;
                    break;

                case RedirectionStream.Verbose:
                    fromType = PipelineResultTypes.Verbose;
                    break;

                case RedirectionStream.Debug:
                    fromType = PipelineResultTypes.Debug;
                    break;

                case RedirectionStream.Information:
                    fromType = PipelineResultTypes.Information;
                    break;

                case RedirectionStream.All:
                    fromType = PipelineResultTypes.All;
                    break;

                default:
                    // Default to Error->Output to be compatible with V2.
                    fromType = PipelineResultTypes.Error;
                    break;
                }

                command.MergeMyResults(fromType, toType);
            }

            _powershell.AddCommand(command);

            // Now the parameters and arguments.
            foreach (var ast in commandAst.CommandElements.Skip(1))
            {
                var exprAst = ast as ExpressionAst;
                if (exprAst != null)
                {
                    VariableExpressionAst variableAst = null;

                    var usingExprAst = ast as UsingExpressionAst;
                    if (usingExprAst != null)
                    {
                        string usingAstKey = PsUtils.GetUsingExpressionKey(usingExprAst);
                        object usingValue  = _usingValueMap[usingAstKey];
                        variableAst = usingExprAst.SubExpression as VariableExpressionAst;
                        if (variableAst != null && variableAst.Splatted)
                        {
                            // Support the splatting of a dictionary
                            var parameters = usingValue as System.Collections.IDictionary;
                            if (parameters != null)
                            {
                                _powershell.AddParameters(parameters);
                            }
                            else
                            {
                                // Support the splatting of an array
                                var arguments = usingValue as System.Collections.IEnumerable;
                                if (arguments != null)
                                {
                                    foreach (object argument in arguments)
                                    {
                                        _powershell.AddArgument(argument);
                                    }
                                }
                                else
                                {
                                    // Splat the object directly.
                                    _powershell.AddArgument(usingValue);
                                }
                            }
                        }
                        else
                        {
                            _powershell.AddArgument(usingValue);
                        }

                        continue;
                    }

                    variableAst = ast as VariableExpressionAst;
                    if (variableAst != null && variableAst.Splatted)
                    {
                        GetSplattedVariable(variableAst);
                    }
                    else
                    {
                        var    constantExprAst = ast as ConstantExpressionAst;
                        object argument;
                        if (constantExprAst != null && LanguagePrimitives.IsNumeric(LanguagePrimitives.GetTypeCode(constantExprAst.StaticType)))
                        {
                            var commandArgumentText = constantExprAst.Extent.Text;
                            argument = constantExprAst.Value;
                            if (!commandArgumentText.Equals(constantExprAst.Value.ToString(), StringComparison.Ordinal))
                            {
                                // The wrapped number will actually return a PSObject which could end holding a reference to
                                // a typetable, making the object runspace specific.  We should find a better way to avoid
                                // any possibility of sharing problems, though this is unlikely to cause problems.
                                argument = ParserOps.WrappedNumber(argument, commandArgumentText);
                            }
                        }
                        else
                        {
                            if (!isTrustedInput)
                            {
                                try
                                {
                                    argument = GetSafeValueVisitor.GetSafeValue(exprAst, _context, GetSafeValueVisitor.SafeValueContext.GetPowerShell);
                                }
                                catch (System.Exception)
                                {
                                    throw new ScriptBlockToPowerShellNotSupportedException(
                                              "CantConvertWithDynamicExpression",
                                              null,
                                              AutomationExceptions.CantConvertWithDynamicExpression,
                                              exprAst.Extent.Text);
                                }
                            }
                            else
                            {
                                argument = GetExpressionValue(exprAst, isTrustedInput);
                            }
                        }

                        _powershell.AddArgument(argument);
                    }
                }
                else
                {
                    AddParameter((CommandParameterAst)ast, isTrustedInput);
                }
            }
        }
Beispiel #3
0
        // This method does parameter binding for a very limited set of scenarios, specifically
        // for New-Alias, Set-Alias, Import-Module, and Export-ModuleMember.  It might not even
        // correctly handle these cmdlets if new parameters are added.
        //
        // It also only populates the bound parameters for a limited set of parameters needed
        // for module analysis.
        private Hashtable DoPsuedoParameterBinding(CommandAst commandAst, string commandName)
        {
            var result = new Hashtable(StringComparer.OrdinalIgnoreCase);

            var parameterBindingInfo = s_parameterBindingInfoTable[commandName].parameterInfo;

            int positionsBound = 0;

            for (int i = 1; i < commandAst.CommandElements.Count; i++)
            {
                var element            = commandAst.CommandElements[i];
                var specifiedParameter = element as CommandParameterAst;
                if (specifiedParameter != null)
                {
                    bool boundParameter     = false;
                    var  specifiedParamName = specifiedParameter.ParameterName;
                    foreach (var parameterInfo in parameterBindingInfo)
                    {
                        if (parameterInfo.name.StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase))
                        {
                            if (parameterInfo.position != -1)
                            {
                                positionsBound |= 1 << parameterInfo.position;
                            }

                            var argumentAst = specifiedParameter.Argument;
                            if (argumentAst is null)
                            {
                                argumentAst = commandAst.CommandElements[i] as ExpressionAst;
                                if (argumentAst != null)
                                {
                                    i += 1;
                                }
                            }

                            if (argumentAst != null)
                            {
                                boundParameter             = true;
                                result[parameterInfo.name] =
                                    GetSafeValueVisitor.GetSafeValue(argumentAst, null, GetSafeValueVisitor.SafeValueContext.ModuleAnalysis);
                            }

                            break;
                        }
                    }

                    if (boundParameter || specifiedParameter.Argument != null)
                    {
                        continue;
                    }

                    if (!"PassThru".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"Force".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"Confirm".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"Global".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"AsCustomObject".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"Verbose".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"Debug".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"DisableNameChecking".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase) &&
                        !"NoClobber".StartsWith(specifiedParamName, StringComparison.OrdinalIgnoreCase))
                    {
                        // Named parameter, skip the argument (except for specific switch parameters
                        i += 1;
                    }
                }
                else
                {
                    // Positional argument, find which position we want to bind
                    int pos = 0;
                    for (; pos < 10; pos++)
                    {
                        if ((positionsBound & (1 << pos)) == 0)
                        {
                            break;
                        }
                    }

                    positionsBound |= 1 << pos;

                    // Now see if we care (we probably do, but if the user did something odd, like specify too many, then we don't really)
                    foreach (var parameterInfo in parameterBindingInfo)
                    {
                        if (parameterInfo.position == pos)
                        {
                            result[parameterInfo.name] = GetSafeValueVisitor.GetSafeValue(
                                commandAst.CommandElements[i], null,
                                GetSafeValueVisitor.SafeValueContext.ModuleAnalysis);
                        }
                    }
                }
            }

            return(result);
        }
Beispiel #4
0
        // Visit one the other variations:
        //  - Dotting scripts
        //  - Setting aliases
        //  - Importing modules
        //  - Exporting module members
        public override AstVisitAction VisitCommand(CommandAst commandAst)
        {
            string commandName =
                commandAst.GetCommandName() ??
                GetSafeValueVisitor.GetSafeValue(commandAst.CommandElements[0], null, GetSafeValueVisitor.SafeValueContext.ModuleAnalysis) as string;

            if (commandName is null)
            {
                return(AstVisitAction.SkipChildren);
            }

            // They are trying to dot a script
            if (commandAst.InvocationOperator == TokenKind.Dot)
            {
                // . Foo-Bar4.ps1
                // . $psScriptRoot\Foo-Bar.ps1 -Bing Baz
                // . ""$psScriptRoot\Support Files\Foo-Bar2.ps1"" -Bing Baz
                // . '$psScriptRoot\Support Files\Foo-Bar3.ps1' -Bing Baz

                DiscoveredModules.Add(
                    new RequiredModuleInfo {
                    Name = commandName, CommandsToPostFilter = new List <string>()
                });
                ModuleIntrinsics.Tracer.WriteLine("Module dots {0}", commandName);
            }

            // They are setting an alias.
            if (string.Equals(commandName, "New-Alias", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "Microsoft.PowerShell.Utility\\New-Alias", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "Set-Alias", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "Microsoft.PowerShell.Utility\\Set-Alias", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "nal", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "sal", StringComparison.OrdinalIgnoreCase))
            {
                // Set-Alias Foo-Bar5 Foo-Bar
                // Set-Alias -Name Foo-Bar6 -Value Foo-Bar
                // sal Foo-Bar7 Foo-Bar
                // sal -Value Foo-Bar -Name Foo-Bar8

                var boundParameters = DoPsuedoParameterBinding(commandAst, commandName);

                var name = boundParameters["Name"] as string;
                if (!string.IsNullOrEmpty(name))
                {
                    var value = boundParameters["Value"] as string;
                    if (!string.IsNullOrEmpty(value))
                    {
                        // These aren't stored in DiscoveredExports, as they are only
                        // exported after the user calls Export-ModuleMember.
                        DiscoveredAliases[name] = value;
                        ModuleIntrinsics.Tracer.WriteLine("Module defines alias: {0} = {1}", name, value);
                    }
                }

                return(AstVisitAction.SkipChildren);
            }

            // They are importing a module
            if (string.Equals(commandName, "Import-Module", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "ipmo", StringComparison.OrdinalIgnoreCase))
            {
                // Import-Module Module1
                // Import-Module Module2 -Function Foo-Module2*, Foo-Module2Second* -Cmdlet Foo-Module2Cmdlet,Foo-Module2Cmdlet*
                // Import-Module Module3 -Function Foo-Module3Command1, Foo-Module3Command2
                // Import-Module Module4,
                //    Module5
                // Import-Module -Name Module6,
                //    Module7 -Global

                var boundParameters = DoPsuedoParameterBinding(commandAst, commandName);

                List <string> commandsToPostFilter = new List <string>();

                Action <string> onEachCommand = importedCommandName =>
                {
                    commandsToPostFilter.Add(importedCommandName);
                };

                // Process any exports from the module that we determine from
                // the -Function, -Cmdlet, or -Alias parameters
                ProcessCmdletArguments(boundParameters["Function"], onEachCommand);
                ProcessCmdletArguments(boundParameters["Cmdlet"], onEachCommand);
                ProcessCmdletArguments(boundParameters["Alias"], onEachCommand);

                // Now, go through all of the discovered modules on Import-Module
                // and register them for deeper investigation.
                Action <string> onEachModule = moduleName =>
                {
                    ModuleIntrinsics.Tracer.WriteLine("Discovered module import: {0}", moduleName);
                    DiscoveredModules.Add(
                        new RequiredModuleInfo
                    {
                        Name = moduleName,
                        CommandsToPostFilter = commandsToPostFilter
                    });
                };
                ProcessCmdletArguments(boundParameters["Name"], onEachModule);

                return(AstVisitAction.SkipChildren);
            }

            // They are exporting a module member
            if (string.Equals(commandName, "Export-ModuleMember", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "Microsoft.PowerShell.Core\\Export-ModuleMember", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(commandName, "$script:ExportModuleMember", StringComparison.OrdinalIgnoreCase))
            {
                // Export-ModuleMember *
                // Export-ModuleMember Exported-UnNamedModuleMember
                // Export-ModuleMember -Function Exported-FunctionModuleMember1, Exported-FunctionModuleMember2 -Cmdlet Exported-CmdletModuleMember `
                //    -Alias Exported-AliasModuleMember
                // & $script:ExportModuleMember -Function (...)

                var boundParameters = DoPsuedoParameterBinding(commandAst, commandName);

                Action <string> onEachFunction = exportedCommandName =>
                {
                    DiscoveredCommandFilters.Add(exportedCommandName);
                    ModuleIntrinsics.Tracer.WriteLine("Discovered explicit export: {0}", exportedCommandName);

                    // If the export doesn't contain wildcards, then add it to the
                    // discovered commands as well. It is likely that they created
                    // the command dynamically
                    if ((!WildcardPattern.ContainsWildcardCharacters(exportedCommandName)) &&
                        (!DiscoveredExports.Contains(exportedCommandName)))
                    {
                        DiscoveredExports.Add(exportedCommandName);
                    }
                };
                ProcessCmdletArguments(boundParameters["Function"], onEachFunction);
                ProcessCmdletArguments(boundParameters["Cmdlet"], onEachFunction);

                Action <string> onEachAlias = exportedAlias =>
                {
                    DiscoveredCommandFilters.Add(exportedAlias);

                    // If the export doesn't contain wildcards, then add it to the
                    // discovered commands as well. It is likely that they created
                    // the command dynamically
                    if (!WildcardPattern.ContainsWildcardCharacters(exportedAlias))
                    {
                        DiscoveredAliases[exportedAlias] = null;
                    }
                };
                ProcessCmdletArguments(boundParameters["Alias"], onEachAlias);

                return(AstVisitAction.SkipChildren);
            }

            // They are exporting a module member using our advanced 'public' function
            // that we've presented in many demos
            if ((string.Equals(commandName, "public", StringComparison.OrdinalIgnoreCase)) &&
                (commandAst.CommandElements.Count > 2))
            {
                // public function Publicly-ExportedFunction
                // public alias Publicly-ExportedAlias
                string publicCommandName = commandAst.CommandElements[2].ToString().Trim();
                DiscoveredExports.Add(publicCommandName);
                DiscoveredCommandFilters.Add(publicCommandName);
            }

            return(AstVisitAction.SkipChildren);
        }