/// <summary>
        /// Get using values as dictionary for the Foreach-Object parallel cmdlet.
        /// Ignore any using expressions that are associated with inner nested Foreach-Object parallel calls,
        /// since they are only effective in the nested call scope and not the current outer scope.
        /// </summary>
        /// <param name = "scriptBlock">Scriptblock to search.</param>
        /// <param name = "isTrustedInput">True when input is trusted.</param>
        /// <param name = "context">Execution context.</param>
        /// <param name = "foreachNames">List of foreach command names and aliases.</param>
        /// <returns>Dictionary of using variable map.</returns>
        internal static Dictionary <string, object> GetUsingValuesForEachParallel(
            ScriptBlock scriptBlock,
            bool isTrustedInput,
            ExecutionContext context,
            string[] foreachNames)
        {
            // Using variables for Foreach-Object -Parallel use are restricted to be within the
            // Foreach-Object -Parallel call scope. This will filter the using variable map to variables
            // only within the current (outer) Foreach-Object -Parallel call scope.
            var usingAsts = UsingExpressionAstSearcher.FindAllUsingExpressions(scriptBlock.Ast).ToList();
            UsingExpressionAst usingAst = null;
            var     usingValueMap       = new Dictionary <string, object>(usingAsts.Count);
            Version oldStrictVersion    = null;

            try
            {
                if (context != null)
                {
                    oldStrictVersion = context.EngineSessionState.CurrentScope.StrictModeVersion;
                    context.EngineSessionState.CurrentScope.StrictModeVersion = PSVersionInfo.PSVersion;
                }

                for (int i = 0; i < usingAsts.Count; ++i)
                {
                    usingAst = (UsingExpressionAst)usingAsts[i];
                    if (IsInForeachParallelCallingScope(usingAst, foreachNames))
                    {
                        var    value       = Compiler.GetExpressionValue(usingAst.SubExpression, isTrustedInput, context);
                        string usingAstKey = PsUtils.GetUsingExpressionKey(usingAst);
                        usingValueMap.TryAdd(usingAstKey, value);
                    }
                }
            }
            catch (RuntimeException rte)
            {
                if (rte.ErrorRecord.FullyQualifiedErrorId.Equals("VariableIsUndefined", StringComparison.Ordinal))
                {
                    throw InterpreterError.NewInterpreterException(
                              targetObject: null,
                              exceptionType: typeof(RuntimeException),
                              errorPosition: usingAst.Extent,
                              resourceIdAndErrorId: "UsingVariableIsUndefined",
                              resourceString: AutomationExceptions.UsingVariableIsUndefined,
                              args: rte.ErrorRecord.TargetObject);
                }
            }
            finally
            {
                if (context != null)
                {
                    context.EngineSessionState.CurrentScope.StrictModeVersion = oldStrictVersion;
                }
            }

            return(usingValueMap);
        }
예제 #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);
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Collect values for UsingExpressions, in the form of a dictionary and an array.
        ///  - The dictionary form is used when the remote server is PSv5 and later version for handling UsingExpression in Invoke-Command/Start-Job
        ///  - The array form is used when the remote server is PSv3 and PSv4 for handling UsingExpression in Invoke-Command.
        /// </summary>
        /// <remarks>
        /// We still keep the array-form using values because we want to avoid any breaking changes when running Invoke-Command
        /// targeting PSv3 or PSv4 remote end -- if UsingExpressions are all in the same scope, then we still pass an array of using
        /// values to the remote end; otherwise, we will handle UsingExpression as if the remote end is PSv2.
        /// </remarks>
        /// <returns>
        /// A tuple of the dictionary-form and the array-form using values.
        /// If the array-form using value is null, then there are UsingExpressions used in different scopes.
        /// </returns>
        private static Tuple <Dictionary <string, object>, object[]> GetUsingValues(Ast body, bool isTrustedInput, ExecutionContext context, Dictionary <string, object> variables, bool filterNonUsingVariables)
        {
            Diagnostics.Assert(context != null || variables != null, "can't retrieve variables with no context and no variables");

            var usingAsts                  = UsingExpressionAstSearcher.FindAllUsingExpressionExceptForWorkflow(body).ToList();
            var usingValueArray            = new object[usingAsts.Count];
            var usingValueMap              = new Dictionary <string, object>(usingAsts.Count);
            HashSet <string> usingVarNames = (variables != null && filterNonUsingVariables) ? new HashSet <string>() : null;

            // Used to check if the PSv3/PSv4 way of handling UsingExpression can continue to be used.
            bool           hasUsingExprInDifferentScope = false;
            ScriptBlockAst sbClosestToPreUsingExpr      = null;

            UsingExpressionAst usingAst         = null;
            Version            oldStrictVersion = null;

            try
            {
                if (context != null)
                {
                    oldStrictVersion = context.EngineSessionState.CurrentScope.StrictModeVersion;
                    context.EngineSessionState.CurrentScope.StrictModeVersion = PSVersionInfo.PSVersion;
                }

                for (int i = 0; i < usingAsts.Count; ++i)
                {
                    usingAst = (UsingExpressionAst)usingAsts[i];
                    object value = null;

                    // This happens only when GetUsingValues gets called outside the ScriptBlockToPowerShellConverter class
                    if (!hasUsingExprInDifferentScope && HasUsingExpressionsInDifferentScopes(usingAst, body, ref sbClosestToPreUsingExpr))
                    {
                        // If there are UsingExpressions in different scopes, the array-form using values will not be useful
                        // even if the remote end is PSv3 or PSv4, because the way we handle using expression in PSv3 and PSv4
                        // doesn't support UsingExpression in different scopes. In this case, we will set the array-form using
                        // value to be null before return.
                        //
                        // Note that this check only affect array-form using value. In PSv5, we change the way to handle UsingExpression
                        // on both client and server sides. The dictionary-form using values is used and UsingExpression in different
                        // scope is supported.
                        hasUsingExprInDifferentScope = true;
                    }

                    if (variables != null)
                    {
                        var variableAst = usingAst.SubExpression as VariableExpressionAst;
                        if (variableAst == null)
                        {
                            throw InterpreterError.NewInterpreterException(null, typeof(RuntimeException),
                                                                           usingAst.Extent, "CantGetUsingExpressionValueWithSpecifiedVariableDictionary", AutomationExceptions.CantGetUsingExpressionValueWithSpecifiedVariableDictionary, usingAst.Extent.Text);
                        }

                        string varName = variableAst.VariablePath.UserPath;
                        if (varName != null && variables.TryGetValue(varName, out value) && usingVarNames != null)
                        {
                            usingVarNames.Add(varName);
                        }
                    }
                    else
                    {
                        value = Compiler.GetExpressionValue(usingAst.SubExpression, isTrustedInput, context);
                    }

                    // Collect UsingExpression value as an array
                    usingValueArray[i] = value;

                    // Collect UsingExpression value as a dictionary
                    string usingAstKey = PsUtils.GetUsingExpressionKey(usingAst);
                    usingValueMap.TryAdd(usingAstKey, value);
                }
            }
            catch (RuntimeException rte)
            {
                if (rte.ErrorRecord.FullyQualifiedErrorId.Equals("VariableIsUndefined", StringComparison.Ordinal))
                {
                    throw InterpreterError.NewInterpreterException(null, typeof(RuntimeException),
                                                                   usingAst.Extent, "UsingVariableIsUndefined", AutomationExceptions.UsingVariableIsUndefined, rte.ErrorRecord.TargetObject);
                }
                else if (rte.ErrorRecord.FullyQualifiedErrorId.Equals("CantGetUsingExpressionValueWithSpecifiedVariableDictionary", StringComparison.Ordinal))
                {
                    throw;
                }
            }
            finally
            {
                if (context != null)
                {
                    context.EngineSessionState.CurrentScope.StrictModeVersion = oldStrictVersion;
                }
            }

            if (usingVarNames != null)
            {
                string[] keys = variables.Keys.ToArray();
                foreach (string key in keys)
                {
                    if (!usingVarNames.Contains(key))
                    {
                        variables.Remove(key);
                    }
                }
            }

            if (hasUsingExprInDifferentScope)
            {
                usingValueArray = null;
            }

            return(Tuple.Create(usingValueMap, usingValueArray));
        }