Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
CompiledScriptBlock.cs2552 linesDownload Raw Back to runtime
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Concurrent;6using System.Collections.Generic;7using System.Diagnostics;8using System.Linq;9using System.Management.Automation.Configuration;10using System.Management.Automation.Internal;11using System.Management.Automation.Language;12using System.Management.Automation.Runspaces;13using System.Management.Automation.Security;14using System.Management.Automation.Tracing;15using System.Reflection;16using System.Runtime.Serialization;17using System.Security.Cryptography.X509Certificates;18using System.Text;19#if LEGACYTELEMETRY20using Microsoft.PowerShell.Telemetry.Internal;21#endif22 23namespace System.Management.Automation24{25    internal enum CompileInterpretChoice26    {27        NeverCompile,28        AlwaysCompile,29        CompileOnDemand30    }31 32    internal enum ScriptBlockClauseToInvoke33    {34        Begin,35        Process,36        End,37        Clean,38        ProcessBlockOnly,39    }40 41    internal class CompiledScriptBlockData42    {43        internal CompiledScriptBlockData(IParameterMetadataProvider ast, bool isFilter)44        {45            _ast = ast;46            this.IsFilter = isFilter;47            this.Id = Guid.NewGuid();48        }49 50        internal CompiledScriptBlockData(string scriptText, bool isProductCode)51        {52            _isProductCode = isProductCode;53            _scriptText = scriptText;54            this.Id = Guid.NewGuid();55        }56 57        internal bool Compile(bool optimized)58        {59            if (_attributes == null)60            {61                InitializeMetadata();62            }63 64            // We need the name to index map to check if any allscope variables are assigned.  If they65            // are, we can't run the optimized version, so we'll compile once more unoptimized and run that.66            if (optimized && NameToIndexMap == null)67            {68                CompileOptimized();69            }70 71            optimized = optimized && !VariableAnalysis.AnyVariablesCouldBeAllScope(NameToIndexMap);72 73            if (!optimized && !_compiledUnoptimized)74            {75                CompileUnoptimized();76            }77            else if (optimized && !_compiledOptimized)78            {79                CompileOptimized();80            }81 82            return optimized;83        }84 85        private void InitializeMetadata()86        {87            lock (this)88            {89                if (_attributes != null)90                {91                    // Another thread must have initialized the metadata.92                    return;93                }94 95                Attribute[] attributes;96                CmdletBindingAttribute cmdletBindingAttribute = null;97                if (!Ast.HasAnyScriptBlockAttributes())98                {99                    attributes = Array.Empty<Attribute>();100                }101                else102                {103                    attributes = Ast.GetScriptBlockAttributes().ToArray();104                    foreach (var attribute in attributes)105                    {106                        if (attribute is CmdletBindingAttribute c)107                        {108                            cmdletBindingAttribute ??= c;109                        }110                        else if (attribute is DebuggerHiddenAttribute)111                        {112                            DebuggerHidden = true;113                        }114                        else if (attribute is DebuggerStepThroughAttribute || attribute is DebuggerNonUserCodeAttribute)115                        {116                            DebuggerStepThrough = true;117                        }118                    }119 120                    _usesCmdletBinding = cmdletBindingAttribute != null;121                }122 123                bool automaticPosition = cmdletBindingAttribute == null || cmdletBindingAttribute.PositionalBinding;124                var runtimeDefinedParameterDictionary =125                    Ast.GetParameterMetadata(automaticPosition, ref _usesCmdletBinding);126 127                // Initialize these fields last - if there were any exceptions, we don't want the partial results cached.128                _attributes = attributes;129                _runtimeDefinedParameterDictionary = runtimeDefinedParameterDictionary;130            }131        }132 133        private void CompileUnoptimized()134        {135            lock (this)136            {137                if (_compiledUnoptimized)138                {139                    // Another thread must have compiled while we were waiting on the lock.140                    return;141                }142 143                ReallyCompile(false);144                _compiledUnoptimized = true;145            }146        }147 148        private void CompileOptimized()149        {150            lock (this)151            {152                if (_compiledOptimized)153                {154                    // Another thread must have compiled while we were waiting on the lock.155                    return;156                }157 158                ReallyCompile(true);159                _compiledOptimized = true;160            }161        }162 163        private void ReallyCompile(bool optimize)164        {165#if LEGACYTELEMETRY166            var sw = new Stopwatch();167            sw.Start();168#endif169            bool etwEnabled = ParserEventSource.Log.IsEnabled();170            if (etwEnabled)171            {172                var extent = _ast.Body.Extent;173                var text = extent.Text;174                ParserEventSource.Log.CompileStart(175                    FileName: ParserEventSource.GetFileOrScript(extent.File, text),176                    text.Length,177                    optimize);178            }179 180            PerformSecurityChecks();181 182            Compiler compiler = new Compiler();183            compiler.Compile(this, optimize);184 185#if LEGACYTELEMETRY186            if (!IsProductCode)187            {188                TelemetryAPI.ReportScriptTelemetry((Ast)_ast, !optimize, sw.ElapsedMilliseconds);189            }190#endif191            if (etwEnabled)192            {193                ParserEventSource.Log.CompileStop();194            }195        }196 197        private void PerformSecurityChecks()198        {199            if (Ast is not ScriptBlockAst scriptBlockAst)200            {201                // Checks are only needed at the top level.202                return;203            }204 205            var scriptExtent = scriptBlockAst.Extent;206            var scriptFile = scriptExtent.File;207 208            if (scriptFile != null209                && scriptFile.EndsWith(StringLiterals.PowerShellDataFileExtension, StringComparison.OrdinalIgnoreCase)210                && IsScriptBlockInFactASafeHashtable())211            {212                // Skip the scan for .psd1 files if their content is in fact a safe HashtableAst.213                return;214            }215 216            // Call the AMSI API to determine if the script block has malicious content217            var amsiResult = AmsiUtils.ScanContent(scriptExtent.Text, scriptFile);218 219            if (amsiResult == AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_DETECTED)220            {221                var parseError = new ParseError(222                    scriptExtent,223                    "ScriptContainedMaliciousContent",224                    ParserStrings.ScriptContainedMaliciousContent);225                throw new ParseException(new[] { parseError });226            }227            else if (amsiResult >= AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_BLOCKED_BY_ADMIN_BEGIN228                && amsiResult <= AmsiUtils.AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_BLOCKED_BY_ADMIN_END)229            {230                // Certain policies set by an administrator blocked this content on this machine231                var parseError = new ParseError(232                    scriptExtent,233                    "ScriptHasAdminBlockedContent",234                    StringUtil.Format(ParserStrings.ScriptHasAdminBlockedContent, amsiResult));235                throw new ParseException(new[] { parseError });236            }237 238            if (ScriptBlock.CheckSuspiciousContent(scriptBlockAst) != null)239            {240                HasSuspiciousContent = true;241            }242 243            // A local function to check if the ScriptBlockAst is in fact a safe HashtableAst.244            bool IsScriptBlockInFactASafeHashtable()245            {246                // NOTE: The code below depends on the current member structure of 'ScriptBlockAst'247                // to determine if the ScriptBlockAst is in fact just a HashtableAst. If AST types248                // are enhanced, such as new members added to 'ScriptBlockAst', the code here needs249                // to be reviewed and changed accordingly.250 251                if (scriptBlockAst.BeginBlock != null252                    || scriptBlockAst.ProcessBlock != null253                    || scriptBlockAst.CleanBlock != null254                    || scriptBlockAst.ParamBlock != null255                    || scriptBlockAst.DynamicParamBlock != null256                    || scriptBlockAst.ScriptRequirements != null257                    || scriptBlockAst.UsingStatements.Count > 0258                    || scriptBlockAst.Attributes.Count > 0)259                {260                    return false;261                }262 263                NamedBlockAst endBlock = scriptBlockAst.EndBlock;264                if (!endBlock.Unnamed || endBlock.Traps != null || endBlock.Statements.Count != 1)265                {266                    return false;267                }268 269                if (endBlock.Statements[0] is not PipelineAst pipelineAst)270                {271                    return false;272                }273 274                if (pipelineAst.GetPureExpression() is not HashtableAst hashtableAst)275                {276                    return false;277                }278 279                // After the above steps, we know the ScriptBlockAst is in fact just a HashtableAst,280                // now we need to check if the HashtableAst is safe.281                return IsSafeValueVisitor.Default.IsAstSafe(hashtableAst);282            }283        }284 285        // We delay parsing scripts loaded on startup, so we save the text.286        private string _scriptText;287 288        internal IParameterMetadataProvider Ast { get => _ast ?? DelayParseScriptText(); }289 290        private IParameterMetadataProvider _ast;291 292        private IParameterMetadataProvider DelayParseScriptText()293        {294            lock (this)295            {296                if (_ast != null)297                {298                    return _ast;299                }300 301                ParseError[] errors;302                _ast = (new Parser()).Parse(null, _scriptText, null, out errors, ParseMode.Default);303                if (errors.Length != 0)304                {305                    throw new ParseException(errors);306                }307 308                _scriptText = null;309                return _ast;310            }311        }312 313        internal Type LocalsMutableTupleType { get; set; }314 315        internal Type UnoptimizedLocalsMutableTupleType { get; set; }316 317        internal Func<MutableTuple> LocalsMutableTupleCreator { get; set; }318 319        internal Func<MutableTuple> UnoptimizedLocalsMutableTupleCreator { get; set; }320 321        internal Dictionary<string, int> NameToIndexMap { get; set; }322 323        #region Named Blocks324 325        internal Action<FunctionContext> DynamicParamBlock { get; set; }326 327        internal Action<FunctionContext> UnoptimizedDynamicParamBlock { get; set; }328 329        internal Action<FunctionContext> BeginBlock { get; set; }330 331        internal Action<FunctionContext> UnoptimizedBeginBlock { get; set; }332 333        internal Action<FunctionContext> ProcessBlock { get; set; }334 335        internal Action<FunctionContext> UnoptimizedProcessBlock { get; set; }336 337        internal Action<FunctionContext> EndBlock { get; set; }338 339        internal Action<FunctionContext> UnoptimizedEndBlock { get; set; }340 341        internal Action<FunctionContext> CleanBlock { get; set; }342 343        internal Action<FunctionContext> UnoptimizedCleanBlock { get; set; }344 345        #endregion Named Blocks346 347        internal IScriptExtent[] SequencePoints { get; set; }348 349        private RuntimeDefinedParameterDictionary _runtimeDefinedParameterDictionary;350        private Attribute[] _attributes;351        private bool _usesCmdletBinding;352        private bool _compiledOptimized;353        private bool _compiledUnoptimized;354        private bool _hasSuspiciousContent;355        private bool? _isProductCode;356 357        internal bool DebuggerHidden { get; set; }358 359        internal bool DebuggerStepThrough { get; set; }360 361        internal Guid Id { get; private set; }362 363        internal bool HasLogged { get; set; }364 365        internal bool SkipLogging { get; set; }366 367        internal bool IsFilter { get; }368 369        internal bool IsProductCode370        {371            get372            {373                _isProductCode ??= SecuritySupport.IsProductBinary(((Ast)_ast).Extent.File);374 375                return _isProductCode.Value;376            }377        }378 379        internal bool GetIsConfiguration()380        {381            // Use _ast instead of Ast382            //  If we access Ast, we may parse a "delay parsed" script block unnecessarily383            //  if _ast is null - it can't be a configuration as there is no way to create a configuration that way384            var scriptBlockAst = _ast as ScriptBlockAst;385            return scriptBlockAst != null && scriptBlockAst.IsConfiguration;386        }387 388        internal bool HasSuspiciousContent389        {390            get391            {392                Diagnostics.Assert(393                    _compiledOptimized || _compiledUnoptimized,394                    "HasSuspiciousContent is not set correctly before being compiled");395                return _hasSuspiciousContent;396            }397 398            set => _hasSuspiciousContent = value;399        }400 401        private MergedCommandParameterMetadata _parameterMetadata;402 403        internal List<Attribute> GetAttributes()404        {405            if (_attributes == null)406            {407                InitializeMetadata();408            }409 410            Diagnostics.Assert(411                _attributes != null,412                "after initialization, attributes is never null, must be an empty list if no attributes.");413            return _attributes.ToList();414        }415 416        internal bool UsesCmdletBinding417        {418            get419            {420                if (_attributes != null)421                {422                    return _usesCmdletBinding;423                }424 425                return Ast.UsesCmdletBinding();426            }427        }428 429        internal RuntimeDefinedParameterDictionary RuntimeDefinedParameters430        {431            get432            {433                if (_runtimeDefinedParameterDictionary == null)434                {435                    InitializeMetadata();436                }437 438                return _runtimeDefinedParameterDictionary;439            }440        }441 442        internal CmdletBindingAttribute CmdletBindingAttribute443        {444            get445            {446                if (_runtimeDefinedParameterDictionary == null)447                {448                    InitializeMetadata();449                }450 451                return _usesCmdletBinding452                    ? (CmdletBindingAttribute)Array.Find(_attributes, static attr => attr is CmdletBindingAttribute)453                    : null;454            }455        }456 457        internal ObsoleteAttribute ObsoleteAttribute458        {459            get460            {461                if (_runtimeDefinedParameterDictionary == null)462                {463                    InitializeMetadata();464                }465 466                return (ObsoleteAttribute)Array.Find(_attributes, static attr => attr is ObsoleteAttribute);467            }468        }469 470        internal ExperimentalAttribute ExperimentalAttribute471        {472            get473            {474                if (_expAttribute == ExperimentalAttribute.None)475                {476                    lock (this)477                    {478                        if (_expAttribute == ExperimentalAttribute.None)479                        {480                            _expAttribute = Ast.GetExperimentalAttributes().FirstOrDefault();481                        }482                    }483                }484 485                return _expAttribute;486            }487        }488 489        private ExperimentalAttribute _expAttribute = ExperimentalAttribute.None;490 491        public MergedCommandParameterMetadata GetParameterMetadata(ScriptBlock scriptBlock)492        {493            if (_parameterMetadata == null)494            {495                lock (this)496                {497                    if (_parameterMetadata == null)498                    {499                        CommandMetadata metadata = new CommandMetadata(500                            scriptBlock,501                            string.Empty,502                            LocalPipeline.GetExecutionContextFromTLS());503                        _parameterMetadata = metadata.StaticCommandParameterMetadata;504                    }505                }506            }507 508            return _parameterMetadata;509        }510 511        public override string ToString()512        {513            if (_scriptText != null)514            {515                return _scriptText;516            }517 518            if (_ast is ScriptBlockAst sbAst)519            {520                return sbAst.ToStringForSerialization();521            }522 523            var generatedMemberFunctionAst = _ast as CompilerGeneratedMemberFunctionAst;524            if (generatedMemberFunctionAst != null)525            {526                return generatedMemberFunctionAst.Extent.Text;527            }528 529            var funcDefn = (FunctionDefinitionAst)_ast;530            if (funcDefn.Parameters == null)531            {532                return funcDefn.Body.ToStringForSerialization();533            }534 535            var sb = new StringBuilder();536            sb.Append(funcDefn.GetParamTextFromParameterList());537            sb.Append(funcDefn.Body.ToStringForSerialization());538            return sb.ToString();539        }540    }541 542    public partial class ScriptBlock543    {544        private readonly CompiledScriptBlockData _scriptBlockData;545 546        internal ScriptBlock(IParameterMetadataProvider ast, bool isFilter)547            : this(new CompiledScriptBlockData(ast, isFilter))548        {549        }550 551        private ScriptBlock(CompiledScriptBlockData scriptBlockData)552        {553            _scriptBlockData = scriptBlockData;554 555            // LanguageMode is a nullable PSLanguageMode enumeration because script blocks556            // need to inherit the language mode from the context in which they are executing.557            // We can't assume FullLanguage by default when there is no context, as there are558            // script blocks (such as the script blocks used in Workflow activities) that are559            // created by the host without a "current language mode" to inherit. They ultimately560            // get their language mode set when they are finally invoked in a constrained561            // language runspace.562            // Script blocks that should always be run under FullLanguage mode (i.e.: set in563            // InitialSessionState, etc.) should explicitly set the LanguageMode to FullLanguage564            // when they are created.565            ExecutionContext context = LocalPipeline.GetExecutionContextFromTLS();566            if (context != null)567            {568                this.LanguageMode = context.LanguageMode;569            }570        }571 572        /// <summary>573        /// Protected constructor to support ISerializable.574        /// </summary>575        [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")]576        protected ScriptBlock(SerializationInfo info, StreamingContext context)577        {578        }579 580        private static readonly ConcurrentDictionary<Tuple<string, string>, ScriptBlock> s_cachedScripts =581            new ConcurrentDictionary<Tuple<string, string>, ScriptBlock>();582 583        internal static ScriptBlock TryGetCachedScriptBlock(string fileName, string fileContents)584        {585            if (InternalTestHooks.IgnoreScriptBlockCache)586            {587                return null;588            }589 590            ScriptBlock scriptBlock;591            var key = Tuple.Create(fileName, fileContents);592            if (s_cachedScripts.TryGetValue(key, out scriptBlock))593            {594                Diagnostics.Assert(595                    scriptBlock.SessionStateInternal == null,596                    "A cached scriptblock should not have it's session state bound, that causes a memory leak.");597                return scriptBlock.Clone();598            }599 600            return null;601        }602 603        private static bool IsDynamicKeyword(Ast ast)604            => ast is CommandAst cmdAst && cmdAst.DefiningKeyword != null;605 606        private static bool IsUsingTypes(Ast ast)607            => ast is UsingStatementAst cmdAst && cmdAst.IsUsingModuleOrAssembly();608 609        internal static void CacheScriptBlock(ScriptBlock scriptBlock, string fileName, string fileContents)610        {611            if (InternalTestHooks.IgnoreScriptBlockCache)612            {613                return;614            }615 616            // Don't cache scriptblocks that have617            // a) dynamic keywords618            // b) 'using module' or 'using assembly'619            // The definition of the dynamic keyword could change, consequently changing how the source text should be parsed.620            // Exported types definitions from 'using module' could change, we need to do all parse-time checks again.621            // TODO(sevoroby): we can optimize it to ignore 'using' if there are no actual type usage in locally defined types.622 623            // using is always a top-level statements in scriptBlock, we don't need to search in child blocks.624            if (scriptBlock.Ast.Find(static ast => IsUsingTypes(ast), false) != null625                || scriptBlock.Ast.Find(static ast => IsDynamicKeyword(ast), true) != null)626            {627                return;628            }629 630            if (s_cachedScripts.Count > 1024)631            {632                s_cachedScripts.Clear();633            }634 635            var key = Tuple.Create(fileName, fileContents);636            s_cachedScripts.TryAdd(key, scriptBlock);637        }638 639        /// <summary>640        /// Clears the cached scriptblocks.641        /// </summary>642        internal static void ClearScriptBlockCache()643        {644            s_cachedScripts.Clear();645        }646 647        internal static readonly ScriptBlock EmptyScriptBlock =648            ScriptBlock.CreateDelayParsedScriptBlock(string.Empty, isProductCode: true);649 650        internal static ScriptBlock Create(Parser parser, string fileName, string fileContents)651        {652            var scriptBlock = TryGetCachedScriptBlock(fileName, fileContents);653            if (scriptBlock != null)654            {655                return scriptBlock;656            }657 658            var ast = parser.Parse(fileName, fileContents, null, out ParseError[] errors, ParseMode.Default);659            if (errors.Length != 0)660            {661                throw new ParseException(errors);662            }663 664            var result = new ScriptBlock(ast, isFilter: false);665            CacheScriptBlock(result, fileName, fileContents);666 667            // The value returned will potentially be bound to a session state.  We don't want668            // the cached script block to end up being bound to any session state, so clone669            // the return value to ensure the cached value has no session state.670            return result.Clone();671        }672 673        internal ScriptBlock Clone() => new ScriptBlock(_scriptBlockData);674 675        /// <summary>676        /// Returns the text of the script block.  The return value might not match the original text exactly.677        /// </summary>678        public override string ToString() => _scriptBlockData.ToString();679 680        /// <summary>681        /// Returns the text of the script block with the handling of $using expressions.682        /// </summary>683        internal string ToStringWithDollarUsingHandling(684            Tuple<List<VariableExpressionAst>, string> usingVariablesTuple)685        {686            FunctionDefinitionAst funcDefn = null;687            var sbAst = Ast as ScriptBlockAst;688            if (sbAst == null)689            {690                funcDefn = (FunctionDefinitionAst)Ast;691                sbAst = funcDefn.Body;692            }693 694            string sbText = sbAst.ToStringForSerialization(usingVariablesTuple, sbAst.Extent.StartOffset, sbAst.Extent.EndOffset);695            if (sbAst.ParamBlock != null)696            {697                return sbText;698            }699 700            string paramText;701            string additionalNewParams = usingVariablesTuple.Item2;702            if (funcDefn == null || funcDefn.Parameters == null)703            {704                paramText = "param(" + additionalNewParams + ")" + Environment.NewLine;705            }706            else707            {708                paramText = funcDefn.GetParamTextFromParameterList(usingVariablesTuple);709            }710 711            sbText = paramText + sbText;712            return sbText;713        }714 715        internal PowerShell GetPowerShellImpl(716            ExecutionContext context,717            Dictionary<string, object> variables,718            bool isTrustedInput,719            bool filterNonUsingVariables,720            bool? createLocalScope,721            params object[] args)722        {723            return AstInternal.GetPowerShell(724                context,725                variables,726                isTrustedInput,727                filterNonUsingVariables,728                createLocalScope,729                args);730        }731 732        internal SteppablePipeline GetSteppablePipelineImpl(CommandOrigin commandOrigin, object[] args)733        {734            var pipelineAst = GetSimplePipeline(735                resourceString => throw PSTraceSource.NewInvalidOperationException(resourceString));736            Diagnostics.Assert(pipelineAst != null, "This should be checked by GetSimplePipeline");737 738            if (pipelineAst.PipelineElements[0] is not CommandAst)739            {740                throw PSTraceSource.NewInvalidOperationException(AutomationExceptions.CantConvertEmptyPipeline);741            }742 743            return PipelineOps.GetSteppablePipeline(pipelineAst, commandOrigin, this, args);744        }745 746        private PipelineAst GetSimplePipeline(Func<string, PipelineAst> errorHandler)747        {748            errorHandler ??= (static _ => null);749 750            if (HasBeginBlock || HasProcessBlock || HasCleanBlock)751            {752                return errorHandler(AutomationExceptions.CanConvertOneClauseOnly);753            }754 755            var ast = AstInternal;756            var statements = ast.Body.EndBlock.Statements;757            if (statements.Count == 0)758            {759                return errorHandler(AutomationExceptions.CantConvertEmptyPipeline);760            }761 762            if (statements.Count > 1)763            {764                return errorHandler(AutomationExceptions.CanOnlyConvertOnePipeline);765            }766 767            if (ast.Body.EndBlock.Traps != null && ast.Body.EndBlock.Traps.Count > 0)768            {769                return errorHandler(AutomationExceptions.CantConvertScriptBlockWithTrap);770            }771 772            if (statements[0] is not PipelineAst pipeAst)773            {774                return errorHandler(AutomationExceptions.CanOnlyConvertOnePipeline);775            }776 777            // The old code checked for empty pipeline.778            // That can't happen in the new parser (validated in the constructors),779            // so the resource CantConvertEmptyPipeline is probably unused.780 781            return pipeAst;782        }783 784        internal List<Attribute> GetAttributes() => _scriptBlockData.GetAttributes();785 786        internal string GetFileName() => AstInternal.Body.Extent.File;787 788        // GetAttributes() is asserted never return null789        internal bool IsMetaConfiguration() => GetAttributes().OfType<DscLocalConfigurationManagerAttribute>().Any();790 791        internal PSToken GetStartPosition() => new PSToken(Ast.Extent);792 793        internal MergedCommandParameterMetadata ParameterMetadata794        {795            get => _scriptBlockData.GetParameterMetadata(this);796        }797 798        internal bool UsesCmdletBinding { get => _scriptBlockData.UsesCmdletBinding; }799 800        internal bool HasDynamicParameters { get => AstInternal.Body.DynamicParamBlock != null; }801 802        /// <summary>803        /// DebuggerHidden.804        /// </summary>805        public bool DebuggerHidden806        {807            get => _scriptBlockData.DebuggerHidden;808            set => _scriptBlockData.DebuggerHidden = value;809        }810 811        /// <summary>812        /// The unique ID of this script block.813        /// </summary>814        public Guid Id { get => _scriptBlockData.Id; }815 816        internal bool DebuggerStepThrough817        {818            get { return _scriptBlockData.DebuggerStepThrough; }819 820            set { _scriptBlockData.DebuggerStepThrough = value; }821        }822 823        internal RuntimeDefinedParameterDictionary RuntimeDefinedParameters824        {825            get => _scriptBlockData.RuntimeDefinedParameters;826        }827 828        internal bool HasLogged829        {830            get => _scriptBlockData.HasLogged;831            set => _scriptBlockData.HasLogged = value;832        }833 834        internal bool SkipLogging835        {836            get { return _scriptBlockData.SkipLogging; }837 838            set { _scriptBlockData.SkipLogging = value; }839        }840 841        internal Assembly AssemblyDefiningPSTypes { get; set; }842 843        internal HelpInfo GetHelpInfo(844            ExecutionContext context,845            CommandInfo commandInfo,846            bool dontSearchOnRemoteComputer,847            Dictionary<Ast, Token[]> scriptBlockTokenCache,848            out string helpFile,849            out string helpUriFromDotLink)850        {851            helpUriFromDotLink = null;852 853            var commentTokens = HelpCommentsParser.GetHelpCommentTokens(AstInternal, scriptBlockTokenCache);854            if (commentTokens != null)855            {856                return HelpCommentsParser.CreateFromComments(857                    context,858                    commandInfo,859                    commentTokens.Item1,860                    commentTokens.Item2,861                    dontSearchOnRemoteComputer,862                    out helpFile,863                    out helpUriFromDotLink);864            }865 866            helpFile = null;867            return null;868        }869 870        /// <summary>871        /// Check the script block to see if it uses any language constructs not allowed in restricted language mode.872        /// </summary>873        /// <param name="allowedCommands">The commands that are allowed.</param>874        /// <param name="allowedVariables">875        /// The variables allowed in this scriptblock. If this is null, then the default variable set876        /// will be allowed. If it is an empty list, no variables will be allowed. If it is "*" then877        /// any variable will be allowed.878        /// </param>879        /// <param name="allowEnvironmentVariables">The environment variables that are allowed.</param>880        public void CheckRestrictedLanguage(881            IEnumerable<string> allowedCommands,882            IEnumerable<string> allowedVariables,883            bool allowEnvironmentVariables)884        {885            Parser parser = new Parser();886 887            var ast = AstInternal;888            if (HasBeginBlock889                || HasProcessBlock890                || HasCleanBlock891                || ast.Body.ParamBlock is not null)892            {893                Ast errorAst = ast.Body.BeginBlock ?? (Ast)ast.Body.ProcessBlock ?? ast.Body.ParamBlock;894                parser.ReportError(895                    errorAst.Extent,896                    nameof(ParserStrings.InvalidScriptBlockInDataSection),897                    ParserStrings.InvalidScriptBlockInDataSection);898            }899 900            if (HasEndBlock)901            {902                var rlc = new RestrictedLanguageChecker(903                    parser,904                    allowedCommands,905                    allowedVariables,906                    allowEnvironmentVariables);907 908                StatementBlockAst.InternalVisit(909                    rlc,910                    ast.Body.EndBlock.Traps,911                    ast.Body.EndBlock.Statements,912                    AstVisitAction.Continue);913            }914 915            if (parser.ErrorList.Count > 0)916            {917                throw new ParseException(parser.ErrorList.ToArray());918            }919        }920 921        internal string GetWithInputHandlingForInvokeCommand() => AstInternal.GetWithInputHandlingForInvokeCommand();922 923        internal string GetWithInputHandlingForInvokeCommandWithUsingExpression(924            Tuple<List<VariableExpressionAst>, string> usingVariablesTuple)925        {926            Tuple<string, string> result =927                AstInternal.GetWithInputHandlingForInvokeCommandWithUsingExpression(usingVariablesTuple);928 929            // result.Item1 is ParamText; result.Item2 is ScriptBlockText930            return result.Item1 == null ? result.Item2 : result.Item1 + result.Item2;931        }932 933        internal bool IsUsingDollarInput() => AstSearcher.IsUsingDollarInput(this.Ast);934 935        internal void InvokeWithPipeImpl(936            bool createLocalScope,937            Dictionary<string, ScriptBlock> functionsToDefine,938            List<PSVariable> variablesToDefine,939            ErrorHandlingBehavior errorHandlingBehavior,940            object dollarUnder,941            object input,942            object scriptThis,943            Pipe outputPipe,944            InvocationInfo invocationInfo,945            params object[] args)946        {947            InvokeWithPipeImpl(948                ScriptBlockClauseToInvoke.ProcessBlockOnly,949                createLocalScope,950                functionsToDefine,951                variablesToDefine,952                errorHandlingBehavior,953                dollarUnder,954                input,955                scriptThis,956                outputPipe,957                invocationInfo,958                args);959        }960 961        internal void InvokeWithPipeImpl(962            ScriptBlockClauseToInvoke clauseToInvoke,963            bool createLocalScope,964            Dictionary<string, ScriptBlock> functionsToDefine,965            List<PSVariable> variablesToDefine,966            ErrorHandlingBehavior errorHandlingBehavior,967            object dollarUnder,968            object input,969            object scriptThis,970            Pipe outputPipe,971            InvocationInfo invocationInfo,972            params object[] args)973        {974            if (clauseToInvoke == ScriptBlockClauseToInvoke.Clean)975            {976                throw new PSNotSupportedException(ParserStrings.InvokingCleanBlockNotSupported);977            }978 979            if ((clauseToInvoke == ScriptBlockClauseToInvoke.Begin && !HasBeginBlock)980                || (clauseToInvoke == ScriptBlockClauseToInvoke.Process && !HasProcessBlock)981                || (clauseToInvoke == ScriptBlockClauseToInvoke.End && !HasEndBlock))982            {983                return;984            }985 986            ExecutionContext context = GetContextFromTLS();987            Diagnostics.Assert(988                SessionStateInternal == null || SessionStateInternal.ExecutionContext == context,989                "The scriptblock is being invoked in a runspace different than the one where it was created");990 991            if (context.CurrentPipelineStopping)992            {993                throw new PipelineStoppedException();994            }995 996            // Validate that the arguments are consistent. The only public API that gets you here never sets createLocalScope to false...997            Diagnostics.Assert(998                createLocalScope || functionsToDefine == null,999                "When calling ScriptBlock.InvokeWithContext(), if 'functionsToDefine' != null then 'createLocalScope' must be true");1000            Diagnostics.Assert(1001                createLocalScope || variablesToDefine == null,1002                "When calling ScriptBlock.InvokeWithContext(), if 'variablesToDefine' != null then 'createLocalScope' must be true");1003 1004            args ??= Array.Empty<object>();1005 1006            bool runOptimized = context._debuggingMode <= 0 && createLocalScope;1007            var codeToInvoke = GetCodeToInvoke(ref runOptimized, clauseToInvoke);1008            if (codeToInvoke == null)1009            {1010                return;1011            }1012 1013            // If we don't have a pipe to write to, we need to discard all results.1014            outputPipe ??= new Pipe { NullPipe = true };1015 1016            var locals = MakeLocalsTuple(runOptimized);1017 1018            if (dollarUnder != AutomationNull.Value)1019            {1020                locals.SetAutomaticVariable(AutomaticVariable.Underbar, dollarUnder, context);1021            }1022 1023            if (input != AutomationNull.Value)1024            {1025                locals.SetAutomaticVariable(AutomaticVariable.Input, input, context);1026            }1027 1028            if (scriptThis != AutomationNull.Value)1029            {1030                locals.SetAutomaticVariable(AutomaticVariable.This, scriptThis, context);1031            }1032 1033            SetPSScriptRootAndPSCommandPath(locals, context);1034 1035            var oldShellFunctionErrorOutputPipe = context.ShellFunctionErrorOutputPipe;1036            var oldExternalErrorOutput = context.ExternalErrorOutput;1037            var oldScopeOrigin = context.EngineSessionState.CurrentScope.ScopeOrigin;1038            var oldSessionState = context.EngineSessionState;1039 1040            // If the script block has a different language mode than the current context,1041            // change the language mode.1042            PSLanguageMode? oldLanguageMode = null;1043            PSLanguageMode? newLanguageMode = null;1044            if (this.LanguageMode.HasValue && this.LanguageMode != context.LanguageMode)1045            {1046                // Don't allow context: ConstrainedLanguage -> FullLanguage transition if1047                // this is dot sourcing into the current scope, unless it is within a trusted module scope.1048                if (this.LanguageMode != PSLanguageMode.FullLanguage1049                    || createLocalScope1050                    || context.EngineSessionState.Module?.LanguageMode == PSLanguageMode.FullLanguage)1051                {1052                    oldLanguageMode = context.LanguageMode;1053                    newLanguageMode = this.LanguageMode;1054                }1055                else if (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Audit)1056                {1057                    string scriptBlockId = this.GetFileName() ?? string.Empty;1058                    SystemPolicy.LogWDACAuditMessage(1059                        context: context,1060                        title: AutomationExceptions.WDACCompiledScriptBlockLogTitle,1061                        message: StringUtil.Format(AutomationExceptions.WDACCompiledScriptBlockLogMessage, scriptBlockId, this.LanguageMode, context.LanguageMode),1062                        fqid: "ScriptBlockDotSourceNotAllowed",1063                        dropIntoDebugger: true);1064 1065                    // Since we are in audit mode, go ahead and allow the language transition.1066                    oldLanguageMode = context.LanguageMode;1067                    newLanguageMode = this.LanguageMode;1068                }1069            }1070 1071            Dictionary<string, PSVariable> backupWhenDotting = null;1072            try1073            {1074                var myInvocationInfo = invocationInfo;1075                if (myInvocationInfo == null)1076                {1077                    var callerFrame = context.Debugger.GetCallStack().LastOrDefault();1078                    var extent = (callerFrame != null)1079                        ? callerFrame.FunctionContext.CurrentPosition1080                        : Ast.Extent;1081                    myInvocationInfo = new InvocationInfo(null, extent, context);1082                }1083 1084                locals.SetAutomaticVariable(AutomaticVariable.MyInvocation, myInvocationInfo, context);1085 1086                if (SessionStateInternal != null)1087                {1088                    context.EngineSessionState = SessionStateInternal;1089                }1090 1091                // If we don't want errors written, hide the error pipe.1092                switch (errorHandlingBehavior)1093                {1094                    case ErrorHandlingBehavior.WriteToCurrentErrorPipe:1095                        // no need to do anything1096                        break;1097                    case ErrorHandlingBehavior.WriteToExternalErrorPipe:1098                        context.ShellFunctionErrorOutputPipe = null;1099                        break;1100                    case ErrorHandlingBehavior.SwallowErrors:1101                        context.ShellFunctionErrorOutputPipe = null;1102                        context.ExternalErrorOutput = new DiscardingPipelineWriter();1103                        break;1104                }1105 1106                if (createLocalScope)1107                {1108                    var newScope = context.EngineSessionState.NewScope(false);1109                    context.EngineSessionState.CurrentScope = newScope;1110                    newScope.LocalsTuple = locals;1111                    // Inject passed in functions into the scope1112                    if (functionsToDefine != null)1113                    {1114                        foreach (var def in functionsToDefine)1115                        {1116                            if (string.IsNullOrWhiteSpace(def.Key))1117                            {1118                                PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException(1119                                    ParserStrings.EmptyFunctionNameInFunctionDefinitionDictionary);1120 1121                                e.SetErrorId("EmptyFunctionNameInFunctionDefinitionDictionary");1122                                throw e;1123                            }1124 1125                            if (def.Value == null)1126                            {1127                                PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException(1128                                    ParserStrings.NullFunctionBodyInFunctionDefinitionDictionary, def.Key);1129 1130                                e.SetErrorId("NullFunctionBodyInFunctionDefinitionDictionary");1131                                throw e;1132                            }1133 1134                            newScope.FunctionTable.Add(def.Key, new FunctionInfo(def.Key, def.Value, context));1135                        }1136                    }1137                    // Inject passed in variables into the scope1138                    if (variablesToDefine != null)1139                    {1140                        int index = 0;1141                        foreach (var psvar in variablesToDefine)1142                        {1143                            // Check for null entries.1144                            if (psvar == null)1145                            {1146                                PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException(1147                                    ParserStrings.NullEntryInVariablesDefinitionList, index);1148 1149                                e.SetErrorId("NullEntryInVariablesDefinitionList");1150                                throw e;1151                            }1152 1153                            string name = psvar.Name;1154                            Diagnostics.Assert(1155                                !(string.Equals(name, "this") || string.Equals(name, "_") || string.Equals(name, "input")),1156                                "The list of variables to set in the scriptblock's scope cannot contain 'this', '_' or 'input'. These variables should be removed before passing the collection to this routine.");1157                            index++;1158                            newScope.Variables.Add(name, psvar);1159                        }1160                    }1161                }1162                else1163                {1164                    if (context.EngineSessionState.CurrentScope.LocalsTuple == null)1165                    {1166                        // If the locals tuple is null, that means either:1167                        //     * we're invoking a script block for a module1168                        //     * something unexpected1169                        context.EngineSessionState.CurrentScope.LocalsTuple = locals;1170                    }1171                    else1172                    {1173                        context.EngineSessionState.CurrentScope.DottedScopes.Push(locals);1174                        backupWhenDotting = new Dictionary<string, PSVariable>();1175                    }1176                }1177 1178                // Set the language mode1179                if (newLanguageMode.HasValue)1180                {1181                    context.LanguageMode = newLanguageMode.Value;1182                }1183 1184                args = BindArgumentsForScriptblockInvoke(1185                    (RuntimeDefinedParameter[])RuntimeDefinedParameters.Data,1186                    args,1187                    context,1188                    !createLocalScope,1189                    backupWhenDotting,1190                    locals);1191                locals.SetAutomaticVariable(AutomaticVariable.Args, args, context);1192 1193                context.EngineSessionState.CurrentScope.ScopeOrigin = CommandOrigin.Internal;1194 1195                var functionContext = new FunctionContext1196                {1197                    _executionContext = context,1198                    _outputPipe = outputPipe,1199                    _localsTuple = locals,1200                    _scriptBlock = this,

Showing the first 1,200 of 2552 lines. Download the file for the rest.