private static bool FindForEachInCommand(CommandAst commandAst) { // Command name is always the first element in the CommandAst. // e.g., 'foreach -parallel {}' var commandNameElement = (commandAst.CommandElements.Count > 0) ? commandAst.CommandElements[0] : null; if (commandNameElement is StringConstantExpressionAst commandName) { bool found = false; foreach (var foreachName in forEachNames) { if (commandName.Value.Equals(foreachName, StringComparison.OrdinalIgnoreCase)) { found = true; break; } } if (found) { // Verify this is foreach-object with parallel parameter set. var bindingResult = StaticParameterBinder.BindCommand(commandAst); if (bindingResult.BoundParameters.ContainsKey("Parallel")) { return(true); } } } return(false); }
private StaticBindingResult GetStaticBindingResult(Dictionary <object, object> dict) { var attrib = typeof(NewSensorFactoryDefinition).GetCustomAttribute <CmdletAttribute>(); var cmdletName = $"{attrib.VerbName}-{attrib.NounName}"; var commandElements = new List <CommandElementAst> { AstFactory.StringConstantExpression(cmdletName, StringConstantType.BareWord) }; foreach (var item in dict) { commandElements.Add(AstFactory.CommandParameter(item.Key.ToString(), null, new EmptyScriptExtent(true))); commandElements.Add(AstFactory.ConstantExpression(item.Value)); } var commandPipeline = AstFactory.Pipeline( AstFactory.CommandExpression( AstFactory.VariableExpression("sensors") ), AstFactory.Command(commandElements) ); var bindingResult = StaticParameterBinder.BindCommand((CommandAst)commandPipeline.PipelineElements[1]); if (bindingResult.BindingExceptions.Count > 0) { var exception = bindingResult.BindingExceptions.First().Value.BindingException; throw new ParameterBindingException($"Failed to parse hashtable '{PrettyPrintHashtable(dict)}': {exception.Message.EnsurePeriod()}", exception); } return(bindingResult); }
/// <summary> /// Analyzes a CommandAst, if it is a New-Alias command, the AST is further analyzed. /// </summary> /// <param name="commandAst">The CommandAst to be analyzed</param> /// <returns>AstVisitAction to continue to analyze the ast's children</returns> public override AstVisitAction VisitCommand(CommandAst commandAst) { if (IsNewAliasCmdlet(commandAst)) { // check the parameters of the New-Alias cmdlet for scope var parameterBindings = StaticParameterBinder.BindCommand(commandAst); if (parameterBindings.BoundParameters.ContainsKey("Scope")) { var scopeValue = parameterBindings.BoundParameters["Scope"].ConstantValue; if ((scopeValue != null) && (scopeValue.ToString().Equals("Global", StringComparison.OrdinalIgnoreCase))) { records.Add(new DiagnosticRecord( string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesError), commandAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName)); } } } return(AstVisitAction.SkipChildren); }
/// <summary> /// Walks the using Ast to verify it is used within a foreach-object -parallel command /// and parameter set scope, and not from within a nested foreach-object -parallel call. /// </summary> /// <param name="usingAst">Using Ast to check.</param> /// <param name-"foreachNames">List of foreach-object command names.</param> /// <returns>True if using expression is in current call scope.</returns> private static bool IsInForeachParallelCallingScope( UsingExpressionAst usingAst, string[] foreachNames) { /* * Example: * $Test1 = "Hello" * 1 | ForEach-Object -Parallel { * $using:Test1 * $Test2 = "Goodbye" * 1 | ForEach-Object -Parallel { * $using:Test1 # Invalid using scope * $using:Test2 # Valid using scope * } * } */ Diagnostics.Assert(usingAst != null, "usingAst argument cannot be null."); // Search up the parent Ast chain for 'Foreach-Object -Parallel' commands. Ast currentParent = usingAst.Parent; int foreachNestedCount = 0; while (currentParent != null) { // Look for Foreach-Object outer commands if (currentParent is CommandAst commandAst) { foreach (var commandElement in commandAst.CommandElements) { if (commandElement is StringConstantExpressionAst commandName) { bool found = false; foreach (var foreachName in foreachNames) { if (commandName.Value.Equals(foreachName, StringComparison.OrdinalIgnoreCase)) { found = true; break; } } if (found) { // Verify this is foreach-object with parallel parameter set. var bindingResult = StaticParameterBinder.BindCommand(commandAst); if (bindingResult.BoundParameters.ContainsKey("Parallel")) { foreachNestedCount++; break; } } } } } if (foreachNestedCount > 1) { // This using expression Ast is outside the original calling scope. return(false); } currentParent = currentParent.Parent; } return(foreachNestedCount == 1); }