MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4//5// This file contains all of the publicly visible parts of the PowerShell abstract syntax tree.6// Any private/internal methods or properties are found in the file AstCompile.cs.7//8 9using System.Collections;10using System.Diagnostics.CodeAnalysis;11using System.Globalization;12using System.Collections.ObjectModel;13using System.Collections.Generic;14using System.Linq;15using System.Linq.Expressions;16using System.Reflection;17using System.Text;18using System.Threading;19using Microsoft.PowerShell;20using Microsoft.PowerShell.Commands;21 22#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings23 24namespace System.Management.Automation.Language25{26 using KeyValuePair = Tuple<ExpressionAst, StatementAst>;27 using IfClause = Tuple<PipelineBaseAst, StatementBlockAst>;28 using SwitchClause = Tuple<ExpressionAst, StatementBlockAst>;29 using System.Runtime.CompilerServices;30 using System.Reflection.Emit;31 32#nullable enable33 34 internal interface ISupportsAssignment35 {36 IAssignableValue GetAssignableValue();37 }38 39 internal interface IAssignableValue40 {41 /// <summary>42 /// GetValue is only called for pre/post increment/decrement or for read/modify/write assignment operators (+=, -=, etc.)43 /// It returns the expressions that holds the value of the ast. It may append the exprs or temps lists if the return44 /// value relies on temps and other expressions.45 /// </summary>46 Expression? GetValue(Compiler compiler, List<Expression> exprs, List<ParameterExpression> temps);47 48 /// <summary>49 /// SetValue is called to set the result of an assignment (=) or to write back the result of50 /// a pre/post increment/decrement. It needs to use potentially cached temps if GetValue was called first.51 /// </summary>52 Expression SetValue(Compiler compiler, Expression rhs);53 }54#nullable restore55 56 internal interface IParameterMetadataProvider57 {58 bool HasAnyScriptBlockAttributes();59 60 RuntimeDefinedParameterDictionary GetParameterMetadata(bool automaticPositions, ref bool usesCmdletBinding);61 62 IEnumerable<Attribute> GetScriptBlockAttributes();63 64 IEnumerable<ExperimentalAttribute> GetExperimentalAttributes();65 66 bool UsesCmdletBinding();67 68 ReadOnlyCollection<ParameterAst> Parameters { get; }69 70 ScriptBlockAst Body { get; }71 72 #region Remoting/Invoke Command73 74 PowerShell GetPowerShell(ExecutionContext context, Dictionary<string, object> variables, bool isTrustedInput,75 bool filterNonUsingVariables, bool? createLocalScope, params object[] args);76 77 string GetWithInputHandlingForInvokeCommand();78 79 /// <summary>80 /// Return value is Tuple[paramText, scriptBlockText]81 /// </summary>82 Tuple<string, string> GetWithInputHandlingForInvokeCommandWithUsingExpression(Tuple<List<VariableExpressionAst>, string> usingVariablesTuple);83 84 #endregion Remoting/Invoke Command85 }86 87 /// <summary>88 /// The abstract base class for all PowerShell abstract syntax tree nodes.89 /// </summary>90 [SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces")]91 public abstract class Ast92 {93 /// <summary>94 /// Initialize the common fields of an ast.95 /// </summary>96 /// <param name="extent">The extent of the expression.</param>97 /// <exception cref="PSArgumentNullException">98 /// If <paramref name="extent"/> is null.99 /// </exception>100 protected Ast(IScriptExtent extent)101 {102 if (extent == null)103 {104 throw PSTraceSource.NewArgumentNullException(nameof(extent));105 }106 107 this.Extent = extent;108 }109 110 /// <summary>111 /// The extent in the source this ast represents.112 /// </summary>113 public IScriptExtent Extent { get; }114 115 /// <summary>116 /// The parent tree for this node.117 /// </summary>118 public Ast Parent { get; private set; }119 120 /// <summary>121 /// Visit the Ast using a visitor that can choose how the tree traversal is performed. This visit method is122 /// for advanced uses of the visitor pattern where an <see cref="AstVisitor"/> is insufficient.123 /// </summary>124 /// <param name="astVisitor">The visitor.</param>125 /// <returns>Returns the value returned by the visitor.</returns>126 public object Visit(ICustomAstVisitor astVisitor)127 {128 if (astVisitor == null)129 {130 throw PSTraceSource.NewArgumentNullException(nameof(astVisitor));131 }132 133 return this.Accept(astVisitor);134 }135 136 /// <summary>137 /// Visit each node in the Ast, calling the methods in <paramref name="astVisitor"/> for each node in the ast.138 /// </summary>139 /// <param name="astVisitor">The visitor.</param>140 public void Visit(AstVisitor astVisitor)141 {142 if (astVisitor == null)143 {144 throw PSTraceSource.NewArgumentNullException(nameof(astVisitor));145 }146 147 this.InternalVisit(astVisitor);148 }149 150 /// <summary>151 /// Traverse the entire Ast, returning all nodes in the tree for which <paramref name="predicate"/> returns true.152 /// </summary>153 /// <param name="predicate">The predicate function.</param>154 /// <param name="searchNestedScriptBlocks">Search nested functions and script block expressions.</param>155 /// <returns>A possibly empty collection of matching Ast nodes.</returns>156 public IEnumerable<Ast> FindAll(Func<Ast, bool> predicate, bool searchNestedScriptBlocks)157 {158 if (predicate == null)159 {160 throw PSTraceSource.NewArgumentNullException(nameof(predicate));161 }162 163 return AstSearcher.FindAll(this, predicate, searchNestedScriptBlocks);164 }165 166 /// <summary>167 /// Traverse the entire Ast, returning the first node in the tree for which <paramref name="predicate"/> returns true.168 /// </summary>169 /// <param name="predicate">The predicate.</param>170 /// <param name="searchNestedScriptBlocks">Search nested functions and script block expressions.</param>171 /// <returns>The first matching node, or null if there is no match.</returns>172 public Ast Find(Func<Ast, bool> predicate, bool searchNestedScriptBlocks)173 {174 if (predicate == null)175 {176 throw PSTraceSource.NewArgumentNullException(nameof(predicate));177 }178 179 return AstSearcher.FindFirst(this, predicate, searchNestedScriptBlocks);180 }181 182 /// <summary>183 /// Formats the ast and returns a string.184 /// </summary>185 public override string ToString()186 {187 return Extent.Text;188 }189 190 /// <summary>191 /// Duplicates the AST, allowing it to be composed into other ASTs.192 /// </summary>193 /// <returns>A copy of the AST, with the link to the previous parent removed.</returns>194 public abstract Ast Copy();195 196 /// <summary>197 /// Constructs the resultant object from the AST and returns it if it is safe.198 /// </summary>199 /// <returns>The object represented by the AST as a safe object.</returns>200 /// <exception cref="InvalidOperationException">201 /// If <paramref name="extent"/> is deemed unsafe202 /// </exception>203 public object SafeGetValue()204 {205 return SafeGetValue(skipHashtableSizeCheck: false);206 }207 208 /// <summary>209 /// Constructs the resultant object from the AST and returns it if it is safe.210 /// </summary>211 /// <param name="skipHashtableSizeCheck">Set to skip hashtable limit validation.</param>212 /// <returns>The object represented by the AST as a safe object.</returns>213 /// <exception cref="InvalidOperationException">214 /// If <paramref name="extent"/> is deemed unsafe.215 /// </exception>216 public object SafeGetValue(bool skipHashtableSizeCheck)217 {218 try219 {220 ExecutionContext context = null;221 if (System.Management.Automation.Runspaces.Runspace.DefaultRunspace != null)222 {223 context = System.Management.Automation.Runspaces.Runspace.DefaultRunspace.ExecutionContext;224 }225 226 return GetSafeValueVisitor.GetSafeValue(this, context, skipHashtableSizeCheck ? GetSafeValueVisitor.SafeValueContext.SkipHashtableSizeCheck : GetSafeValueVisitor.SafeValueContext.Default);227 }228 catch229 {230 throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, AutomationExceptions.CantConvertWithDynamicExpression, this.Extent.Text));231 }232 }233 234 /// <summary>235 /// Copy a collection of AST elements.236 /// </summary>237 /// <typeparam name="T">The actual AST type</typeparam>238 /// <param name="elements">Collection of ASTs.</param>239 /// <returns></returns>240 internal static T[] CopyElements<T>(ReadOnlyCollection<T> elements) where T : Ast241 {242 if (elements == null || elements.Count == 0) { return null; }243 244 var result = new T[elements.Count];245 for (int i = 0; i < result.Length; i++)246 {247 result[i] = (T)elements[i].Copy();248 }249 250 return result;251 }252 253 /// <summary>254 /// Copy a single AST element.255 /// </summary>256 /// <typeparam name="T">The actual AST type</typeparam>257 /// <param name="element">An AST instance.</param>258 /// <returns></returns>259 internal static T CopyElement<T>(T element) where T : Ast260 {261 if (element == null) { return null; }262 263 return (T)element.Copy();264 }265 266 // Should be protected AND internal, but C# doesn't support that.267 internal void SetParents<T>(ReadOnlyCollection<T> children)268 where T : Ast269 {270 for (int index = 0; index < children.Count; index++)271 {272 var child = children[index];273 SetParent(child);274 }275 }276 277 // Should be protected AND internal, but C# doesn't support that.278 internal void SetParents<T1, T2>(ReadOnlyCollection<Tuple<T1, T2>> children)279 where T1 : Ast280 where T2 : Ast281 {282 for (int index = 0; index < children.Count; index++)283 {284 var child = children[index];285 SetParent(child.Item1);286 SetParent(child.Item2);287 }288 }289 290 // Should be protected AND internal, but C# doesn't support that.291 internal void SetParent(Ast child)292 {293 if (child.Parent != null)294 {295 throw new InvalidOperationException(ParserStrings.AstIsReused);296 }297 298 Diagnostics.Assert(child.Parent == null, "Parent can only be set once");299 child.Parent = this;300 }301 302 internal void ClearParent()303 {304 this.Parent = null;305 }306 307 internal abstract object Accept(ICustomAstVisitor visitor);308 309 internal abstract AstVisitAction InternalVisit(AstVisitor visitor);310 311 internal static readonly PSTypeName[] EmptyPSTypeNameArray = Array.Empty<PSTypeName>();312 313 internal bool IsInWorkflow()314 {315 // Scan up the AST's parents, looking for a script block that is either316 // a workflow, or has a job definition attribute.317 // Stop scanning when we encounter a FunctionDefinitionAst318 Ast current = this;319 bool stopScanning = false;320 321 while (current != null && !stopScanning)322 {323 if (current is ScriptBlockAst scriptBlock)324 {325 // See if this uses the workflow keyword326 if (scriptBlock.Parent is FunctionDefinitionAst functionDefinition)327 {328 stopScanning = true;329 if (functionDefinition.IsWorkflow)330 {331 return true;332 }333 }334 }335 336 if (current is CommandAst commandAst &&337 string.Equals(TokenKind.InlineScript.Text(), commandAst.GetCommandName(), StringComparison.OrdinalIgnoreCase) &&338 this != commandAst)339 {340 return false;341 }342 343 current = current.Parent;344 }345 346 return false;347 }348 349 internal bool HasSuspiciousContent { get; set; }350 351 #region Search Ancestor Ast352 353 internal static ConfigurationDefinitionAst GetAncestorConfigurationDefinitionAstAndDynamicKeywordStatementAst(354 Ast ast,355 out DynamicKeywordStatementAst keywordAst)356 {357 ConfigurationDefinitionAst configAst = null;358 keywordAst = GetAncestorAst<DynamicKeywordStatementAst>(ast);359 configAst = (keywordAst != null) ? GetAncestorAst<ConfigurationDefinitionAst>(keywordAst) : GetAncestorAst<ConfigurationDefinitionAst>(ast);360 return configAst;361 }362 363 internal static HashtableAst GetAncestorHashtableAst(Ast ast, out Ast lastChildOfHashtable)364 {365 HashtableAst hashtableAst = null;366 lastChildOfHashtable = null;367 while (ast != null)368 {369 hashtableAst = ast as HashtableAst;370 if (hashtableAst != null)371 break;372 lastChildOfHashtable = ast;373 ast = ast.Parent;374 }375 376 return hashtableAst;377 }378 379 internal static TypeDefinitionAst GetAncestorTypeDefinitionAst(Ast ast)380 {381 TypeDefinitionAst typeDefinitionAst = null;382 383 while (ast != null)384 {385 typeDefinitionAst = ast as TypeDefinitionAst;386 if (typeDefinitionAst != null)387 break;388 389 // Nested function isn't really a member of the type so stop looking390 // Anonymous script blocks are though391 if (ast is FunctionDefinitionAst functionDefinitionAst && functionDefinitionAst.Parent is not FunctionMemberAst)392 break;393 ast = ast.Parent;394 }395 396 return typeDefinitionAst;397 }398 399 /// <summary>400 /// Get ancestor Ast of the given type of the given ast.401 /// </summary>402 /// <param name="ast"></param>403 /// <returns></returns>404 internal static T GetAncestorAst<T>(Ast ast) where T : Ast405 {406 T targetAst = null;407 var parent = ast;408 while (parent != null)409 {410 targetAst = parent as T;411 if (targetAst != null)412 break;413 parent = parent.Parent;414 }415 416 return targetAst;417 }418 419 #endregion420 }421 422 // A dummy class to hold an extent for open/close curlies so we can step in the debugger.423 // This Ast is never produced by the parser, only from the compiler.424 internal class SequencePointAst : Ast425 {426 public SequencePointAst(IScriptExtent extent)427 : base(extent)428 {429 }430 431 /// <summary>432 /// Copy the SequencePointAst instance.433 /// </summary>434 public override Ast Copy()435 {436 Diagnostics.Assert(false, "code should be unreachable");437 return null;438 }439 440 internal override object Accept(ICustomAstVisitor visitor)441 {442 Diagnostics.Assert(false, "code should be unreachable");443 return null;444 }445 446 internal override AstVisitAction InternalVisit(AstVisitor visitor)447 {448 Diagnostics.Assert(false, "code should be unreachable");449 return visitor.CheckForPostAction(this, AstVisitAction.Continue);450 }451 }452 453 /// <summary>454 /// A placeholder statement used when there are syntactic errors in the source script.455 /// </summary>456 public class ErrorStatementAst : PipelineBaseAst457 {458 internal ErrorStatementAst(IScriptExtent extent, IEnumerable<Ast> nestedAsts = null)459 : base(extent)460 {461 if (nestedAsts != null && nestedAsts.Any())462 {463 NestedAst = new ReadOnlyCollection<Ast>(nestedAsts.ToArray());464 SetParents(NestedAst);465 }466 }467 468 internal ErrorStatementAst(IScriptExtent extent, Token kind, IEnumerable<Ast> nestedAsts = null)469 : base(extent)470 {471 if (kind == null)472 {473 throw PSTraceSource.NewArgumentNullException(nameof(kind));474 }475 476 Kind = kind;477 if (nestedAsts != null && nestedAsts.Any())478 {479 NestedAst = new ReadOnlyCollection<Ast>(nestedAsts.ToArray());480 SetParents(NestedAst);481 }482 }483 484 internal ErrorStatementAst(IScriptExtent extent, Token kind, IEnumerable<KeyValuePair<string, Tuple<Token, Ast>>> flags, IEnumerable<Ast> conditions, IEnumerable<Ast> bodies)485 : base(extent)486 {487 if (kind == null)488 {489 throw PSTraceSource.NewArgumentNullException(nameof(kind));490 }491 492 Kind = kind;493 if (flags != null && flags.Any())494 {495 Flags = new Dictionary<string, Tuple<Token, Ast>>(StringComparer.OrdinalIgnoreCase);496 foreach (KeyValuePair<string, Tuple<Token, Ast>> entry in flags)497 {498 if (Flags.ContainsKey(entry.Key))499 continue;500 501 Flags.Add(entry.Key, entry.Value);502 if (entry.Value.Item2 != null)503 {504 SetParent(entry.Value.Item2);505 }506 }507 }508 509 if (conditions != null && conditions.Any())510 {511 Conditions = new ReadOnlyCollection<Ast>(conditions.ToArray());512 SetParents(Conditions);513 }514 515 if (bodies != null && bodies.Any())516 {517 Bodies = new ReadOnlyCollection<Ast>(bodies.ToArray());518 SetParents(Bodies);519 }520 }521 522 /// <summary>523 /// Indicate the kind of the ErrorStatement. e.g. Kind == Switch means that this error statement is generated524 /// when parsing a switch statement.525 /// </summary>526 public Token Kind { get; }527 528 /// <summary>529 /// The flags specified and their value. The value is null if it's not specified.530 /// e.g. switch -regex -file c:\demo.txt ---> regex -- null531 /// file -- { c:\demo.txt }532 /// </summary>533 /// TODO, Changing this to an IDictionary because ReadOnlyDictionary is available only in .NET 4.5534 /// This is a temporary workaround and will be fixed later. Tracked by Win8: 354135535 [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]536 public Dictionary<string, Tuple<Token, Ast>> Flags { get; }537 538 /// <summary>539 /// The conditions specified.540 /// </summary>541 public ReadOnlyCollection<Ast> Conditions { get; }542 543 /// <summary>544 /// The bodies specified.545 /// </summary>546 public ReadOnlyCollection<Ast> Bodies { get; }547 548 /// <summary>549 /// Sometimes a valid ast is parsed successfully within the extent that this error statement represents. Those550 /// asts are contained in this collection. This collection may contain other error asts. This collection may551 /// be null when no asts were successfully constructed within the extent of this error ast.552 /// </summary>553 public ReadOnlyCollection<Ast> NestedAst { get; }554 555 /// <summary>556 /// Copy the ErrorStatementAst instance.557 /// </summary>558 public override Ast Copy()559 {560 if (this.Kind == null)561 {562 var newNestedAst = CopyElements(this.NestedAst);563 return new ErrorStatementAst(this.Extent, newNestedAst);564 }565 else if (Flags != null || Conditions != null || Bodies != null)566 {567 var newConditions = CopyElements(this.Conditions);568 var newBodies = CopyElements(this.Bodies);569 Dictionary<string, Tuple<Token, Ast>> newFlags = null;570 571 if (this.Flags != null)572 {573 newFlags = new Dictionary<string, Tuple<Token, Ast>>(StringComparer.OrdinalIgnoreCase);574 foreach (KeyValuePair<string, Tuple<Token, Ast>> entry in this.Flags)575 {576 var newAst = CopyElement(entry.Value.Item2);577 newFlags.Add(entry.Key, new Tuple<Token, Ast>(entry.Value.Item1, newAst));578 }579 }580 581 return new ErrorStatementAst(this.Extent, this.Kind, newFlags, newConditions, newBodies);582 }583 else584 {585 var newNestedAst = CopyElements(this.NestedAst);586 return new ErrorStatementAst(this.Extent, this.Kind, newNestedAst);587 }588 }589 590 #region Visitors591 592 internal override object Accept(ICustomAstVisitor visitor)593 {594 return visitor.VisitErrorStatement(this);595 }596 597 internal override AstVisitAction InternalVisit(AstVisitor visitor)598 {599 var action = visitor.VisitErrorStatement(this);600 if (action == AstVisitAction.SkipChildren)601 return visitor.CheckForPostAction(this, AstVisitAction.Continue);602 if (action == AstVisitAction.Continue && NestedAst != null)603 {604 for (int index = 0; index < NestedAst.Count; index++)605 {606 var ast = NestedAst[index];607 action = ast.InternalVisit(visitor);608 if (action != AstVisitAction.Continue) break;609 }610 }611 612 if (action == AstVisitAction.Continue && Flags != null)613 {614 foreach (var tuple in Flags.Values)615 {616 if (tuple.Item2 == null)617 continue;618 619 action = tuple.Item2.InternalVisit(visitor);620 if (action != AstVisitAction.Continue) break;621 }622 }623 624 if (action == AstVisitAction.Continue && Conditions != null)625 {626 for (int index = 0; index < Conditions.Count; index++)627 {628 var ast = Conditions[index];629 action = ast.InternalVisit(visitor);630 if (action != AstVisitAction.Continue) break;631 }632 }633 634 if (action == AstVisitAction.Continue && Bodies != null)635 {636 for (int index = 0; index < Bodies.Count; index++)637 {638 var ast = Bodies[index];639 action = ast.InternalVisit(visitor);640 if (action != AstVisitAction.Continue) break;641 }642 }643 644 return visitor.CheckForPostAction(this, action);645 }646 647 #endregion Visitors648 }649 650 /// <summary>651 /// A placeholder expression used when there are syntactic errors in the source script.652 /// </summary>653 public class ErrorExpressionAst : ExpressionAst654 {655 internal ErrorExpressionAst(IScriptExtent extent, IEnumerable<Ast> nestedAsts = null)656 : base(extent)657 {658 if (nestedAsts != null && nestedAsts.Any())659 {660 NestedAst = new ReadOnlyCollection<Ast>(nestedAsts.ToArray());661 SetParents(NestedAst);662 }663 }664 665 /// <summary>666 /// Sometimes a valid ast is parsed successfully within the extent that this error expression represents. Those667 /// asts are contained in this collection. This collection may contain other error asts. This collection may668 /// be null when no asts were successfully constructed within the extent of this error ast.669 /// </summary>670 public ReadOnlyCollection<Ast> NestedAst { get; }671 672 /// <summary>673 /// Copy the ErrorExpressionAst instance.674 /// </summary>675 public override Ast Copy()676 {677 var newNestedAst = CopyElements(this.NestedAst);678 return new ErrorExpressionAst(this.Extent, newNestedAst);679 }680 681 #region Visitors682 683 internal override object Accept(ICustomAstVisitor visitor)684 {685 return visitor.VisitErrorExpression(this);686 }687 688 internal override AstVisitAction InternalVisit(AstVisitor visitor)689 {690 var action = visitor.VisitErrorExpression(this);691 if (action == AstVisitAction.SkipChildren)692 return visitor.CheckForPostAction(this, AstVisitAction.Continue);693 if (action == AstVisitAction.Continue && NestedAst != null)694 {695 for (int index = 0; index < NestedAst.Count; index++)696 {697 var ast = NestedAst[index];698 action = ast.InternalVisit(visitor);699 if (action != AstVisitAction.Continue) break;700 }701 }702 703 return visitor.CheckForPostAction(this, action);704 }705 706 #endregion Visitors707 }708 709 #region Script Blocks710 711 /// <summary>712 /// </summary>713 public class ScriptRequirements714 {715 internal static readonly ReadOnlyCollection<PSSnapInSpecification> EmptySnapinCollection =716 Utils.EmptyReadOnlyCollection<PSSnapInSpecification>();717 718 internal static readonly ReadOnlyCollection<string> EmptyAssemblyCollection =719 Utils.EmptyReadOnlyCollection<string>();720 721 internal static readonly ReadOnlyCollection<ModuleSpecification> EmptyModuleCollection =722 Utils.EmptyReadOnlyCollection<ModuleSpecification>();723 724 internal static readonly ReadOnlyCollection<string> EmptyEditionCollection =725 Utils.EmptyReadOnlyCollection<string>();726 727 /// <summary>728 /// The application id this script requires, specified like:729 /// <code>#requires -Shellid Shell</code>730 /// If no application id has been specified, this property is null.731 /// </summary>732 public string RequiredApplicationId { get; internal set; }733 734 /// <summary>735 /// The PowerShell version this script requires, specified like:736 /// <code>#requires -Version 3</code>737 /// If no version has been specified, this property is null.738 /// </summary>739 public Version RequiredPSVersion { get; internal set; }740 741 /// <summary>742 /// The PowerShell Edition this script requires, specified like:743 /// <code>#requires -PSEdition Desktop</code>744 /// If no PSEdition has been specified, this property is an empty collection.745 /// </summary>746 public ReadOnlyCollection<string> RequiredPSEditions { get; internal set; }747 748 /// <summary>749 /// The modules this script requires, specified like:750 /// <code>#requires -Module NetAdapter</code>751 /// <code>#requires -Module @{Name="NetAdapter"; Version="1.0.0.0"}</code>752 /// If no modules are required, this property is an empty collection.753 /// </summary>754 public ReadOnlyCollection<ModuleSpecification> RequiredModules { get; internal set; }755 756 /// <summary>757 /// The assemblies this script requires, specified like:758 /// <code>#requires -Assembly path\to\foo.dll</code>759 /// <code>#requires -Assembly "System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"</code>760 /// If no assemblies are required, this property is an empty collection.761 /// </summary>762 public ReadOnlyCollection<string> RequiredAssemblies { get; internal set; }763 764 /// <summary>765 /// Specifies if this script requires elevated privileges, specified like:766 /// <code>#requires -RunAsAdministrator</code>767 /// If nothing is specified, this property is false.768 /// </summary>769 public bool IsElevationRequired { get; internal set; }770 }771 772 /// <summary>773 /// A ScriptBlockAst is the root ast node for a complete script.774 /// </summary>775 public class ScriptBlockAst : Ast, IParameterMetadataProvider776 {777 private static readonly ReadOnlyCollection<AttributeAst> s_emptyAttributeList =778 Utils.EmptyReadOnlyCollection<AttributeAst>();779 780 private static readonly ReadOnlyCollection<UsingStatementAst> s_emptyUsingStatementList =781 Utils.EmptyReadOnlyCollection<UsingStatementAst>();782 783 internal bool HadErrors { get; set; }784 785 internal bool IsConfiguration { get; private set; }786 787 internal bool PostParseChecksPerformed { get; set; }788 789 /// <summary>790 /// Construct a ScriptBlockAst that uses explicitly named begin/process/end blocks.791 /// </summary>792 /// <param name="extent">The extent of the script block.</param>793 /// <param name="usingStatements">The list of using statements, may be null.</param>794 /// <param name="attributes">The set of attributes for the script block.</param>795 /// <param name="paramBlock">The ast for the param block, may be null.</param>796 /// <param name="beginBlock">The ast for the begin block, may be null.</param>797 /// <param name="processBlock">The ast for the process block, may be null.</param>798 /// <param name="endBlock">The ast for the end block, may be null.</param>799 /// <param name="dynamicParamBlock">The ast for the dynamicparam block, may be null.</param>800 /// <exception cref="PSArgumentNullException">801 /// If <paramref name="extent"/> is null.802 /// </exception>803 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]804 public ScriptBlockAst(IScriptExtent extent,805 IEnumerable<UsingStatementAst> usingStatements,806 IEnumerable<AttributeAst> attributes,807 ParamBlockAst paramBlock,808 NamedBlockAst beginBlock,809 NamedBlockAst processBlock,810 NamedBlockAst endBlock,811 NamedBlockAst dynamicParamBlock)812 : this(813 extent,814 usingStatements,815 attributes,816 paramBlock,817 beginBlock,818 processBlock,819 endBlock,820 cleanBlock: null,821 dynamicParamBlock)822 {823 }824 825 /// <summary>826 /// Initializes a new instance of the <see cref="ScriptBlockAst"/> class.827 /// This construction uses explicitly named begin/process/end/clean blocks.828 /// </summary>829 /// <param name="extent">The extent of the script block.</param>830 /// <param name="usingStatements">The list of using statements, may be null.</param>831 /// <param name="attributes">The set of attributes for the script block.</param>832 /// <param name="paramBlock">The ast for the param block, may be null.</param>833 /// <param name="beginBlock">The ast for the begin block, may be null.</param>834 /// <param name="processBlock">The ast for the process block, may be null.</param>835 /// <param name="endBlock">The ast for the end block, may be null.</param>836 /// <param name="cleanBlock">The ast for the clean block, may be null.</param>837 /// <param name="dynamicParamBlock">The ast for the dynamicparam block, may be null.</param>838 /// <exception cref="PSArgumentNullException">839 /// If <paramref name="extent"/> is null.840 /// </exception>841 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]842 public ScriptBlockAst(843 IScriptExtent extent,844 IEnumerable<UsingStatementAst> usingStatements,845 IEnumerable<AttributeAst> attributes,846 ParamBlockAst paramBlock,847 NamedBlockAst beginBlock,848 NamedBlockAst processBlock,849 NamedBlockAst endBlock,850 NamedBlockAst cleanBlock,851 NamedBlockAst dynamicParamBlock)852 : base(extent)853 {854 SetUsingStatements(usingStatements);855 856 if (attributes != null)857 {858 this.Attributes = new ReadOnlyCollection<AttributeAst>(attributes.ToArray());859 SetParents(Attributes);860 }861 else862 {863 this.Attributes = s_emptyAttributeList;864 }865 866 if (paramBlock != null)867 {868 this.ParamBlock = paramBlock;869 SetParent(paramBlock);870 }871 872 if (beginBlock != null)873 {874 this.BeginBlock = beginBlock;875 SetParent(beginBlock);876 }877 878 if (processBlock != null)879 {880 this.ProcessBlock = processBlock;881 SetParent(processBlock);882 }883 884 if (endBlock != null)885 {886 this.EndBlock = endBlock;887 SetParent(endBlock);888 }889 890 if (cleanBlock != null)891 {892 this.CleanBlock = cleanBlock;893 SetParent(cleanBlock);894 }895 896 if (dynamicParamBlock != null)897 {898 this.DynamicParamBlock = dynamicParamBlock;899 SetParent(dynamicParamBlock);900 }901 }902 903 /// <summary>904 /// Construct a ScriptBlockAst that uses explicitly named begin/process/end blocks.905 /// </summary>906 /// <param name="extent">The extent of the script block.</param>907 /// <param name="usingStatements">The list of using statements, may be null.</param>908 /// <param name="paramBlock">The ast for the param block, may be null.</param>909 /// <param name="beginBlock">The ast for the begin block, may be null.</param>910 /// <param name="processBlock">The ast for the process block, may be null.</param>911 /// <param name="endBlock">The ast for the end block, may be null.</param>912 /// <param name="dynamicParamBlock">The ast for the dynamicparam block, may be null.</param>913 /// <exception cref="PSArgumentNullException">914 /// If <paramref name="extent"/> is null.915 /// </exception>916 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]917 public ScriptBlockAst(IScriptExtent extent,918 IEnumerable<UsingStatementAst> usingStatements,919 ParamBlockAst paramBlock,920 NamedBlockAst beginBlock,921 NamedBlockAst processBlock,922 NamedBlockAst endBlock,923 NamedBlockAst dynamicParamBlock)924 : this(extent, usingStatements, null, paramBlock, beginBlock, processBlock, endBlock, dynamicParamBlock)925 {926 }927 928 /// <summary>929 /// Initializes a new instance of the <see cref="ScriptBlockAst"/> class.930 /// This construction uses explicitly named begin/process/end/clean blocks.931 /// </summary>932 /// <param name="extent">The extent of the script block.</param>933 /// <param name="usingStatements">The list of using statements, may be null.</param>934 /// <param name="paramBlock">The ast for the param block, may be null.</param>935 /// <param name="beginBlock">The ast for the begin block, may be null.</param>936 /// <param name="processBlock">The ast for the process block, may be null.</param>937 /// <param name="endBlock">The ast for the end block, may be null.</param>938 /// <param name="cleanBlock">The ast for the clean block, may be null.</param>939 /// <param name="dynamicParamBlock">The ast for the dynamicparam block, may be null.</param>940 /// <exception cref="PSArgumentNullException">941 /// If <paramref name="extent"/> is null.942 /// </exception>943 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]944 public ScriptBlockAst(945 IScriptExtent extent,946 IEnumerable<UsingStatementAst> usingStatements,947 ParamBlockAst paramBlock,948 NamedBlockAst beginBlock,949 NamedBlockAst processBlock,950 NamedBlockAst endBlock,951 NamedBlockAst cleanBlock,952 NamedBlockAst dynamicParamBlock)953 : this(extent, usingStatements, null, paramBlock, beginBlock, processBlock, endBlock, cleanBlock, dynamicParamBlock)954 {955 }956 957 /// <summary>958 /// Construct a ScriptBlockAst that uses explicitly named begin/process/end blocks.959 /// </summary>960 /// <param name="extent">The extent of the script block.</param>961 /// <param name="paramBlock">The ast for the param block, may be null.</param>962 /// <param name="beginBlock">The ast for the begin block, may be null.</param>963 /// <param name="processBlock">The ast for the process block, may be null.</param>964 /// <param name="endBlock">The ast for the end block, may be null.</param>965 /// <param name="dynamicParamBlock">The ast for the dynamicparam block, may be null.</param>966 /// <exception cref="PSArgumentNullException">967 /// If <paramref name="extent"/> is null.968 /// </exception>969 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]970 public ScriptBlockAst(IScriptExtent extent,971 ParamBlockAst paramBlock,972 NamedBlockAst beginBlock,973 NamedBlockAst processBlock,974 NamedBlockAst endBlock,975 NamedBlockAst dynamicParamBlock)976 : this(extent, null, paramBlock, beginBlock, processBlock, endBlock, dynamicParamBlock)977 {978 }979 980 /// <summary>981 /// Initializes a new instance of the <see cref="ScriptBlockAst"/> class.982 /// This construction uses explicitly named begin/process/end/clean blocks.983 /// </summary>984 /// <param name="extent">The extent of the script block.</param>985 /// <param name="paramBlock">The ast for the param block, may be null.</param>986 /// <param name="beginBlock">The ast for the begin block, may be null.</param>987 /// <param name="processBlock">The ast for the process block, may be null.</param>988 /// <param name="endBlock">The ast for the end block, may be null.</param>989 /// <param name="cleanBlock">The ast for the clean block, may be null.</param>990 /// <param name="dynamicParamBlock">The ast for the dynamicparam block, may be null.</param>991 /// <exception cref="PSArgumentNullException">992 /// If <paramref name="extent"/> is null.993 /// </exception>994 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]995 public ScriptBlockAst(996 IScriptExtent extent,997 ParamBlockAst paramBlock,998 NamedBlockAst beginBlock,999 NamedBlockAst processBlock,1000 NamedBlockAst endBlock,1001 NamedBlockAst cleanBlock,1002 NamedBlockAst dynamicParamBlock)1003 : this(extent, null, paramBlock, beginBlock, processBlock, endBlock, cleanBlock, dynamicParamBlock)1004 {1005 }1006 1007 /// <summary>1008 /// Construct a ScriptBlockAst that does not use explicitly named blocks.1009 /// </summary>1010 /// <param name="extent">The extent of the script block.</param>1011 /// <param name="usingStatements">The list of using statements, may be null.</param>1012 /// <param name="paramBlock">The ast for the param block, may be null.</param>1013 /// <param name="statements">1014 /// The statements that go in the end block if <paramref name="isFilter"/> is false, or the1015 /// process block if <paramref name="isFilter"/> is true.1016 /// </param>1017 /// <param name="isFilter">True if the script block is a filter, false if it is a function or workflow.</param>1018 /// <exception cref="PSArgumentNullException">1019 /// If <paramref name="extent"/> or <paramref name="statements"/> is null.1020 /// </exception>1021 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]1022 public ScriptBlockAst(IScriptExtent extent, List<UsingStatementAst> usingStatements, ParamBlockAst paramBlock, StatementBlockAst statements, bool isFilter)1023 : this(extent, usingStatements, null, paramBlock, statements, isFilter, false)1024 {1025 }1026 1027 /// <summary>1028 /// Construct a ScriptBlockAst that does not use explicitly named blocks.1029 /// </summary>1030 /// <param name="extent">The extent of the script block.</param>1031 /// <param name="paramBlock">The ast for the param block, may be null.</param>1032 /// <param name="statements">1033 /// The statements that go in the end block if <paramref name="isFilter"/> is false, or the1034 /// process block if <paramref name="isFilter"/> is true.1035 /// </param>1036 /// <param name="isFilter">True if the script block is a filter, false if it is a function or workflow.</param>1037 /// <exception cref="PSArgumentNullException">1038 /// If <paramref name="extent"/> or <paramref name="statements"/> is null.1039 /// </exception>1040 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]1041 public ScriptBlockAst(IScriptExtent extent, ParamBlockAst paramBlock, StatementBlockAst statements, bool isFilter)1042 : this(extent, null, null, paramBlock, statements, isFilter, false)1043 {1044 }1045 1046 /// <summary>1047 /// Construct a ScriptBlockAst that does not use explicitly named blocks.1048 /// </summary>1049 /// <param name="extent">The extent of the script block.</param>1050 /// <param name="paramBlock">The ast for the param block, may be null.</param>1051 /// <param name="statements">1052 /// The statements that go in the end block if <paramref name="isFilter"/> is false, or the1053 /// process block if <paramref name="isFilter"/> is true.1054 /// </param>1055 /// <param name="isFilter">True if the script block is a filter, false if it is a function or workflow.</param>1056 /// <param name="isConfiguration">True if the script block is a configuration.</param>1057 /// <exception cref="PSArgumentNullException">1058 /// If <paramref name="extent"/> or <paramref name="statements"/> is null.1059 /// </exception>1060 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]1061 public ScriptBlockAst(IScriptExtent extent, ParamBlockAst paramBlock, StatementBlockAst statements, bool isFilter, bool isConfiguration)1062 : this(extent, null, null, paramBlock, statements, isFilter, isConfiguration)1063 {1064 }1065 1066 /// <summary>1067 /// Construct a ScriptBlockAst that does not use explicitly named blocks.1068 /// </summary>1069 /// <param name="extent">The extent of the script block.</param>1070 /// <param name="usingStatements">The list of using statements, may be null.</param>1071 /// <param name="paramBlock">The ast for the param block, may be null.</param>1072 /// <param name="statements">1073 /// The statements that go in the end block if <paramref name="isFilter"/> is false, or the1074 /// process block if <paramref name="isFilter"/> is true.1075 /// </param>1076 /// <param name="isFilter">True if the script block is a filter, false if it is a function or workflow.</param>1077 /// <param name="isConfiguration">True if the script block is a configuration.</param>1078 /// <exception cref="PSArgumentNullException">1079 /// If <paramref name="extent"/> or <paramref name="statements"/> is null.1080 /// </exception>1081 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]1082 public ScriptBlockAst(IScriptExtent extent, IEnumerable<UsingStatementAst> usingStatements, ParamBlockAst paramBlock, StatementBlockAst statements, bool isFilter, bool isConfiguration)1083 : this(extent, usingStatements, null, paramBlock, statements, isFilter, isConfiguration)1084 {1085 }1086 1087 /// <summary>1088 /// Construct a ScriptBlockAst that does not use explicitly named blocks.1089 /// </summary>1090 /// <param name="extent">The extent of the script block.</param>1091 /// <param name="attributes">The attributes for the script block.</param>1092 /// <param name="paramBlock">The ast for the param block, may be null.</param>1093 /// <param name="statements">1094 /// The statements that go in the end block if <paramref name="isFilter"/> is false, or the1095 /// process block if <paramref name="isFilter"/> is true.1096 /// </param>1097 /// <param name="isFilter">True if the script block is a filter, false if it is a function or workflow.</param>1098 /// <param name="isConfiguration">True if the script block is a configuration.</param>1099 /// <exception cref="PSArgumentNullException">1100 /// If <paramref name="extent"/> or <paramref name="statements"/> is null.1101 /// </exception>1102 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]1103 public ScriptBlockAst(IScriptExtent extent, IEnumerable<AttributeAst> attributes, ParamBlockAst paramBlock, StatementBlockAst statements, bool isFilter, bool isConfiguration)1104 : this(extent, null, attributes, paramBlock, statements, isFilter, isConfiguration)1105 {1106 }1107 1108 /// <summary>1109 /// Construct a ScriptBlockAst that does not use explicitly named blocks.1110 /// </summary>1111 /// <param name="extent">The extent of the script block.</param>1112 /// <param name="usingStatements">The list of using statements, may be null.</param>1113 /// <param name="attributes">The attributes for the script block.</param>1114 /// <param name="paramBlock">The ast for the param block, may be null.</param>1115 /// <param name="statements">1116 /// The statements that go in the end block if <paramref name="isFilter"/> is false, or the1117 /// process block if <paramref name="isFilter"/> is true.1118 /// </param>1119 /// <param name="isFilter">True if the script block is a filter, false if it is a function or workflow.</param>1120 /// <param name="isConfiguration">True if the script block is a configuration.</param>1121 /// <exception cref="PSArgumentNullException">1122 /// If <paramref name="extent"/> or <paramref name="statements"/> is null.1123 /// </exception>1124 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "param")]1125 public ScriptBlockAst(IScriptExtent extent, IEnumerable<UsingStatementAst> usingStatements, IEnumerable<AttributeAst> attributes, ParamBlockAst paramBlock, StatementBlockAst statements, bool isFilter, bool isConfiguration)1126 : base(extent)1127 {1128 SetUsingStatements(usingStatements);1129 1130 if (attributes != null)1131 {1132 this.Attributes = new ReadOnlyCollection<AttributeAst>(attributes.ToArray());1133 SetParents(Attributes);1134 }1135 else1136 {1137 this.Attributes = s_emptyAttributeList;1138 }1139 1140 if (statements == null)1141 {1142 throw PSTraceSource.NewArgumentNullException(nameof(statements));1143 }1144 1145 if (paramBlock != null)1146 {1147 this.ParamBlock = paramBlock;1148 SetParent(paramBlock);1149 }1150 1151 if (isFilter)1152 {1153 this.ProcessBlock = new NamedBlockAst(statements.Extent, TokenKind.Process, statements, true);1154 SetParent(ProcessBlock);1155 }1156 else1157 {1158 this.EndBlock = new NamedBlockAst(statements.Extent, TokenKind.End, statements, true);1159 this.IsConfiguration = isConfiguration;1160 SetParent(EndBlock);1161 }1162 }1163 1164 private void SetUsingStatements(IEnumerable<UsingStatementAst> usingStatements)1165 {1166 if (usingStatements != null)1167 {1168 this.UsingStatements = new ReadOnlyCollection<UsingStatementAst>(usingStatements.ToArray());1169 SetParents(UsingStatements);1170 }1171 else1172 {1173 this.UsingStatements = s_emptyUsingStatementList;1174 }1175 }1176 1177 /// <summary>1178 /// The asts for attributes (such as [DscLocalConfigurationManager()]) used before the scriptblock.1179 /// This property is never null.1180 /// </summary>1181 public ReadOnlyCollection<AttributeAst> Attributes { get; }1182 1183 /// <summary>1184 /// The asts for any using statements. This property is never null.1185 /// Elements of the collection are instances of either <see cref="UsingStatementAst"/>1186 /// or (only in error cases) <see cref="ErrorStatementAst"/>.1187 /// </summary>1188 public ReadOnlyCollection<UsingStatementAst> UsingStatements { get; private set; }1189 1190 /// <summary>1191 /// The ast representing the parameters for a script block, or null if no param block was specified.1192 /// </summary>1193 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Param")]1194 public ParamBlockAst ParamBlock { get; }1195 1196 /// <summary>1197 /// The ast representing the begin block for a script block, or null if no begin block was specified.1198 /// </summary>1199 public NamedBlockAst BeginBlock { get; }1200 