/// <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)); }
private static object[] GetUsingValues(Ast body, ExecutionContext context, Dictionary <string, object> variables, bool filterNonUsingVariables) { List <Ast> list = UsingExpressionAstSearcher.FindAllUsingExpressionExceptForWorkflow(body).ToList <Ast>(); object[] objArray = new object[list.Count]; HashSet <string> set = ((variables != null) && filterNonUsingVariables) ? new HashSet <string>() : null; UsingExpressionAst usingExpr = null; Version strictModeVersion = null; try { if (context != null) { strictModeVersion = context.EngineSessionState.CurrentScope.StrictModeVersion; context.EngineSessionState.CurrentScope.StrictModeVersion = PSVersionInfo.PSVersion; } for (int i = 0; i < objArray.Length; i++) { usingExpr = (UsingExpressionAst)list[i]; if (IsUsingExpressionInFunction(usingExpr, body)) { throw InterpreterError.NewInterpreterException(null, typeof(RuntimeException), usingExpr.Extent, "UsingVariableNotSupportedInFunctionOrFilter", AutomationExceptions.UsingVariableNotSupportedInFunctionOrFilter, new object[] { usingExpr }); } object obj2 = null; if (variables != null) { VariableExpressionAst subExpression = usingExpr.SubExpression as VariableExpressionAst; if (subExpression == null) { throw InterpreterError.NewInterpreterException(null, typeof(RuntimeException), usingExpr.Extent, "CantGetUsingExpressionValueWithSpecifiedVariableDictionary", AutomationExceptions.CantGetUsingExpressionValueWithSpecifiedVariableDictionary, new object[] { usingExpr.Extent.Text }); } string userPath = subExpression.VariablePath.UserPath; if (((userPath != null) && variables.TryGetValue(userPath, out obj2)) && (set != null)) { set.Add(userPath); } } else { obj2 = Compiler.GetExpressionValue(usingExpr.SubExpression, context, (IList)null); } objArray[i] = obj2; usingExpr.RuntimeUsingIndex = i; } } catch (RuntimeException exception) { if (exception.ErrorRecord.FullyQualifiedErrorId.Equals("VariableIsUndefined", StringComparison.Ordinal)) { throw InterpreterError.NewInterpreterException(null, typeof(RuntimeException), usingExpr.Extent, "UsingVariableIsUndefined", AutomationExceptions.UsingVariableIsUndefined, new object[] { exception.ErrorRecord.TargetObject }); } if (exception.ErrorRecord.FullyQualifiedErrorId.Equals("UsingVariableNotSupportedInFunctionOrFilter", StringComparison.Ordinal) || exception.ErrorRecord.FullyQualifiedErrorId.Equals("CantGetUsingExpressionValueWithSpecifiedVariableDictionary", StringComparison.Ordinal)) { throw; } } finally { if (context != null) { context.EngineSessionState.CurrentScope.StrictModeVersion = strictModeVersion; } } if (set != null) { foreach (string str2 in variables.Keys.ToArray <string>()) { if (!set.Contains(str2)) { variables.Remove(str2); } } } return(objArray); }