Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SessionState.cs557 linesDownload Raw Back to engine
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics;8using System.Diagnostics.CodeAnalysis;9using System.Management.Automation.Internal;10using System.Management.Automation.Language;11using System.Management.Automation.Runspaces;12using System.Security;13 14using Dbg = System.Management.Automation;15 16namespace System.Management.Automation17{18    /// <summary>19    /// Holds the state of a Monad Shell session.20    /// </summary>21    [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "This is a bridge class between internal classes and a public interface. It requires this much coupling.")]22    internal sealed partial class SessionStateInternal23    {24        #region tracer25 26        /// <summary>27        /// An instance of the PSTraceSource class used for trace output28        /// using "SessionState" as the category.29        /// </summary>30        [Dbg.TraceSource(31             "SessionState",32             "SessionState Class")]33        private static readonly Dbg.PSTraceSource s_tracer =34            Dbg.PSTraceSource.GetTracer("SessionState",35             "SessionState Class");36 37        #endregion tracer38 39        #region Constructor40 41        /// <summary>42        /// Constructor for session state object.43        /// </summary>44        /// <param name="context">45        /// The context for the runspace to which this session state object belongs.46        /// </param>47        /// <exception cref="ArgumentNullException">48        /// if <paramref name="context"/> is null.49        /// </exception>50        internal SessionStateInternal(ExecutionContext context) : this(null, false, context)51        {52        }53 54        internal SessionStateInternal(SessionStateInternal parent, bool linkToGlobal, ExecutionContext context)55        {56            if (context == null)57            {58                throw PSTraceSource.NewArgumentNullException(nameof(context));59            }60 61            ExecutionContext = context;62 63            // Create the working directory stack. This64            // is used for the pushd and popd commands65 66            _workingLocationStack = new Dictionary<string, Stack<PathInfo>>(StringComparer.OrdinalIgnoreCase);67 68            // Conservative choice to limit the Set-Location history in order to limit memory impact in case of a regression.69            const int locationHistoryLimit = 20;70            _setLocationHistory = new HistoryStack<PathInfo>(locationHistoryLimit);71 72            GlobalScope = new SessionStateScope(null);73            ModuleScope = GlobalScope;74            _currentScope = GlobalScope;75 76            InitializeSessionStateInternalSpecialVariables(false);77 78            // Create the push the global scope on as79            // the starting script scope.  That way, if you dot-source a script80            // that uses variables qualified by script: it works.81            GlobalScope.ScriptScope = GlobalScope;82 83            if (parent != null)84            {85                GlobalScope.Parent = parent.GlobalScope;86 87                // Copy the drives and providers from the parent...88                CopyProviders(parent);89                // During loading of core modules, providers are not populated.90                // We set the drive information later91                if (Providers != null && Providers.Count > 0)92                {93                    CurrentDrive = parent.CurrentDrive;94                }95 96                // Link it to the global scope...97                if (linkToGlobal)98                {99                    GlobalScope = parent.GlobalScope;100                }101            }102            else103            {104                _currentScope.LocalsTuple = MutableTuple.MakeTuple(Compiler.DottedLocalsTupleType, Compiler.DottedLocalsNameIndexMap);105            }106        }107 108        /// <summary>109        /// Add any special variables to the session state variable table. This routine110        /// must be called at construction time or if the variable table is reset.111        /// </summary>112        internal void InitializeSessionStateInternalSpecialVariables(bool clearVariablesTable)113        {114            if (clearVariablesTable)115            {116                // Clear the variable table117                GlobalScope.Variables.Clear();118 119                // Add in the per-scope default variables.120                GlobalScope.AddSessionStateScopeDefaultVariables();121            }122 123            // Set variable $Error124            PSVariable errorvariable = new PSVariable("Error", new ArrayList(), ScopedItemOptions.Constant);125            GlobalScope.SetVariable(errorvariable.Name, errorvariable, false, false, this, fastPath: true);126 127            // Set variable $PSDefaultParameterValues128            Collection<Attribute> attributes = new Collection<Attribute>();129            attributes.Add(new ArgumentTypeConverterAttribute(typeof(System.Management.Automation.DefaultParameterDictionary)));130            PSVariable psDefaultParameterValuesVariable = new PSVariable(SpecialVariables.PSDefaultParameterValues,131                                                                         new DefaultParameterDictionary(),132                                                                         ScopedItemOptions.None, attributes,133                                                                         RunspaceInit.PSDefaultParameterValuesDescription);134            GlobalScope.SetVariable(psDefaultParameterValuesVariable.Name, psDefaultParameterValuesVariable, false, false, this, fastPath: true);135        }136 137        #endregion Constructor138 139        #region Private data140 141        /// <summary>142        /// Provides all the path manipulation and globbing for Monad paths.143        /// </summary>144        internal LocationGlobber Globber145        {146            get { return _globberPrivate ??= ExecutionContext.LocationGlobber; }147        }148 149        private LocationGlobber _globberPrivate;150 151        /// <summary>152        /// The context of the runspace to which this session state object belongs.153        /// </summary>154        internal ExecutionContext ExecutionContext { get; }155 156        /// <summary>157        /// Returns the public session state facade object for this session state instance.158        /// </summary>159        internal SessionState PublicSessionState160        {161            get { return _publicSessionState ??= new SessionState(this); }162 163            set { _publicSessionState = value; }164        }165 166        private SessionState _publicSessionState;167 168        /// <summary>169        /// Gets the engine APIs to access providers.170        /// </summary>171        internal ProviderIntrinsics InvokeProvider172        {173            get { return _invokeProvider ??= new ProviderIntrinsics(this); }174        }175 176        private ProviderIntrinsics _invokeProvider;177 178        /// <summary>179        /// The module info object associated with this session state.180        /// </summary>181        internal PSModuleInfo Module { get; set; } = null;182 183        // This is used to maintain the order in which modules were imported.184        // This is used by Get-Command -All to order by last imported185        internal List<string> ModuleTableKeys = new List<string>();186 187        /// <summary>188        /// The private module table for this session state object...189        /// </summary>190        internal Dictionary<string, PSModuleInfo> ModuleTable { get; } = new Dictionary<string, PSModuleInfo>(StringComparer.OrdinalIgnoreCase);191 192        /// <summary>193        /// Get/set constraints for this execution environment.194        /// </summary>195        internal PSLanguageMode LanguageMode196        {197            get198            {199                return ExecutionContext.LanguageMode;200            }201 202            set203            {204                ExecutionContext.LanguageMode = value;205            }206        }207 208        /// <summary>209        /// If true the PowerShell debugger will use FullLanguage mode, otherwise it will use the current language mode.210        /// </summary>211        internal bool UseFullLanguageModeInDebugger212        {213            get214            {215                return ExecutionContext.UseFullLanguageModeInDebugger;216            }217        }218 219        /// <summary>220        /// The list of scripts that are allowed to be run. If the name "*"221        /// is in the list, then all scripts can be run. (This is the default.)222        /// </summary>223        public List<string> Scripts { get; } = new List<string>(new string[] { "*" });224 225        /// <summary>226        /// See if a script is allowed to be run.227        /// </summary>228        /// <param name="scriptPath">Path to check.</param>229        /// <returns>True if script is allowed.</returns>230        internal SessionStateEntryVisibility CheckScriptVisibility(string scriptPath)231        {232            return checkPathVisibility(Scripts, scriptPath);233        }234 235        /// <summary>236        /// The list of applications that are allowed to be run. If the name "*"237        /// is in the list, then all applications can be run. (This is the default.)238        /// </summary>239        public List<string> Applications { get; } = new List<string>(new string[] { "*" });240 241        /// <summary>242        /// List of functions/filters to export from this session state object...243        /// </summary>244        internal List<CmdletInfo> ExportedCmdlets { get; } = new List<CmdletInfo>();245 246        /// <summary>247        /// Defines the default command visibility for this session state. Binding an InitialSessionState instance248        /// with private members will set this to Private.249        /// </summary>250        internal SessionStateEntryVisibility DefaultCommandVisibility = SessionStateEntryVisibility.Public;251 252        /// <summary>253        /// Add an new SessionState cmdlet entry to this session state object...254        /// </summary>255        /// <param name="entry">The entry to add.</param>256        internal void AddSessionStateEntry(SessionStateCmdletEntry entry)257        {258            AddSessionStateEntry(entry, /*local*/false);259        }260 261        /// <summary>262        /// Add an new SessionState cmdlet entry to this session state object...263        /// </summary>264        /// <param name="entry">The entry to add.</param>265        /// <param name="local">If local, add cmdlet to current scope. Else, add to module scope.</param>266        internal void AddSessionStateEntry(SessionStateCmdletEntry entry, bool local)267        {268            ExecutionContext.CommandDiscovery.AddSessionStateCmdletEntryToCache(entry, local);269        }270 271        /// <summary>272        /// Add an new SessionState cmdlet entry to this session state object...273        /// </summary>274        /// <param name="entry">The entry to add.</param>275        internal void AddSessionStateEntry(SessionStateApplicationEntry entry)276        {277            this.Applications.Add(entry.Path);278        }279 280        /// <summary>281        /// Add an new SessionState cmdlet entry to this session state object...282        /// </summary>283        /// <param name="entry">The entry to add.</param>284        internal void AddSessionStateEntry(SessionStateScriptEntry entry)285        {286            this.Scripts.Add(entry.Path);287        }288 289        /// <summary>290        /// Add the variables that must always be present in a SessionState instance...291        /// </summary>292        internal void InitializeFixedVariables()293        {294            //295            // BUGBUG296            //297            // String resources for aliases are currently associated with Runspace init298            //299 300            // $Host301            PSVariable v = new PSVariable(302                    SpecialVariables.Host,303                    ExecutionContext.EngineHostInterface,304                    ScopedItemOptions.Constant | ScopedItemOptions.AllScope,305                    RunspaceInit.PSHostDescription);306            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);307 308            // $HOME - indicate where a user's home directory is located in the file system.309            //    -- %USERPROFILE% on windows310            //    -- %HOME% on unix311            string home = Environment.GetEnvironmentVariable(Platform.CommonEnvVariableNames.Home) ?? string.Empty;312            v = new PSVariable(SpecialVariables.Home,313                    home,314                    ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope,315                    RunspaceInit.HOMEDescription);316            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);317 318            // $ExecutionContext319            v = new PSVariable(SpecialVariables.ExecutionContext,320                    ExecutionContext.EngineIntrinsics,321                    ScopedItemOptions.Constant | ScopedItemOptions.AllScope,322                    RunspaceInit.ExecutionContextDescription);323            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);324 325            // $PSVersionTable326            v = new PSVariable(SpecialVariables.PSVersionTable,327                    PSVersionInfo.GetPSVersionTable(),328                    ScopedItemOptions.Constant | ScopedItemOptions.AllScope,329                    RunspaceInit.PSVersionTableDescription);330            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);331 332            // $PSEdition333            v = new PSVariable(SpecialVariables.PSEdition,334                    PSVersionInfo.PSEditionValue,335                    ScopedItemOptions.Constant | ScopedItemOptions.AllScope,336                    RunspaceInit.PSEditionDescription);337            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);338 339            // $PID340            v = new PSVariable(341                    SpecialVariables.PID,342                    Environment.ProcessId,343                    ScopedItemOptions.Constant | ScopedItemOptions.AllScope,344                    RunspaceInit.PIDDescription);345            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);346 347            // $PSCulture348            v = new PSCultureVariable();349            this.GlobalScope.SetVariableForce(v, this);350 351            // $PSUICulture352            v = new PSUICultureVariable();353            this.GlobalScope.SetVariableForce(v, this);354 355            // $?356            v = new QuestionMarkVariable(this.ExecutionContext);357            this.GlobalScope.SetVariableForce(v, this);358 359            // $ShellId - if there is no runspace config, use the default string360            string shellId = ExecutionContext.ShellID;361            v = new PSVariable(SpecialVariables.ShellId, shellId,362                   ScopedItemOptions.Constant | ScopedItemOptions.AllScope,363                    RunspaceInit.MshShellIdDescription);364            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);365 366            // $PSHOME367            string applicationBase = Utils.DefaultPowerShellAppBase;368            v = new PSVariable(SpecialVariables.PSHome, applicationBase,369                    ScopedItemOptions.Constant | ScopedItemOptions.AllScope,370                    RunspaceInit.PSHOMEDescription);371            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);372 373            // $EnabledExperimentalFeatures374            v = new PSVariable(SpecialVariables.EnabledExperimentalFeatures,375                               ExperimentalFeature.EnabledExperimentalFeatureNames,376                               ScopedItemOptions.Constant | ScopedItemOptions.AllScope,377                               RunspaceInit.EnabledExperimentalFeatures);378            this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);379        }380 381        /// <summary>382        /// Check to see if an application is allowed to be run.383        /// </summary>384        /// <param name="applicationPath">The path to the application to check.</param>385        /// <returns>True if application is permitted.</returns>386        internal SessionStateEntryVisibility CheckApplicationVisibility(string applicationPath)387        {388            return checkPathVisibility(Applications, applicationPath);389        }390 391        private static SessionStateEntryVisibility checkPathVisibility(List<string> list, string path)392        {393            if (list == null || list.Count == 0)394            {395                return SessionStateEntryVisibility.Private;396            }397 398            if (string.IsNullOrEmpty(path))399            {400                return SessionStateEntryVisibility.Private;401            }402 403            if (list.Contains("*"))404            {405                return SessionStateEntryVisibility.Public;406            }407 408            foreach (string p in list)409            {410                if (string.Equals(p, path, StringComparison.OrdinalIgnoreCase))411                {412                    return SessionStateEntryVisibility.Public;413                }414 415                if (WildcardPattern.ContainsWildcardCharacters(p))416                {417                    WildcardPattern pattern = WildcardPattern.Get(p, WildcardOptions.IgnoreCase);418                    if (pattern.IsMatch(path))419                    {420                        return SessionStateEntryVisibility.Public;421                    }422                }423            }424 425            return SessionStateEntryVisibility.Private;426        }427 428        #endregion Private data429 430        /// <summary>431        /// Notification for SessionState to do cleanup432        /// before runspace is closed.433        /// </summary>434        internal void RunspaceClosingNotification()435        {436            if (this != ExecutionContext.TopLevelSessionState && Providers.Count > 0)437            {438                // Remove all providers at the top level...439 440                CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);441 442                foreach (string providerName in Providers.Keys)443                {444                    // All errors are ignored.445 446                    RemoveProvider(providerName, true, context);447                }448            }449        }450 451        #region Errors452 453        /// <summary>454        /// Constructs a new instance of a ProviderInvocationException455        /// using the specified data.456        /// </summary>457        /// <param name="resourceId">458        /// The resource ID to use as the format message for the error.459        /// </param>460        /// <param name="resourceStr">461        /// This is the message template string.462        /// </param>463        /// <param name="provider">464        /// The provider information used when formatting the error message.465        /// </param>466        /// <param name="path">467        /// The path used when formatting the error message.468        /// </param>469        /// <param name="e">470        /// The exception that was thrown by the provider. This will be set as471        /// the ProviderInvocationException's InnerException and the message will472        /// be used when formatting the error message.473        /// </param>474        /// <returns>475        /// A new instance of a ProviderInvocationException.476        /// </returns>477        /// <exception cref="ProviderInvocationException">478        /// Wraps <paramref name="e"/> in a ProviderInvocationException479        /// and then throws it.480        /// </exception>481        internal ProviderInvocationException NewProviderInvocationException(482            string resourceId,483            string resourceStr,484            ProviderInfo provider,485            string path,486            Exception e)487        {488            return NewProviderInvocationException(resourceId, resourceStr, provider, path, e, true);489        }490 491        /// <summary>492        /// Constructs a new instance of a ProviderInvocationException493        /// using the specified data.494        /// </summary>495        /// <param name="resourceId">496        /// The resource ID to use as the format message for the error.497        /// </param>498        /// <param name="resourceStr">499        /// This is the message template string.500        /// </param>501        /// <param name="provider">502        /// The provider information used when formatting the error message.503        /// </param>504        /// <param name="path">505        /// The path used when formatting the error message.506        /// </param>507        /// <param name="e">508        /// The exception that was thrown by the provider. This will be set as509        /// the ProviderInvocationException's InnerException and the message will510        /// be used when formatting the error message.511        /// </param>512        /// <param name="useInnerExceptionErrorMessage">513        /// If true, the error record from the inner exception will be used if it contains one.514        /// If false, the error message specified by the resourceId will be used.515        /// </param>516        /// <returns>517        /// A new instance of a ProviderInvocationException.518        /// </returns>519        /// <exception cref="ProviderInvocationException">520        /// Wraps <paramref name="e"/> in a ProviderInvocationException521        /// and then throws it.522        /// </exception>523        internal ProviderInvocationException NewProviderInvocationException(524            string resourceId,525            string resourceStr,526            ProviderInfo provider,527            string path,528            Exception e,529            bool useInnerExceptionErrorMessage)530        {531            //  If the innerException was itself thrown by532            //  ProviderBase.ThrowTerminatingError, it is already a533            //  ProviderInvocationException, and we don't want to534            //  re-wrap it.535            ProviderInvocationException pie = e as ProviderInvocationException;536            if (pie != null)537            {538                pie._providerInfo = provider;539                return pie;540            }541 542            pie = new ProviderInvocationException(resourceId, resourceStr, provider, path, e, useInnerExceptionErrorMessage);543 544            // Log a provider health event545 546            MshLog.LogProviderHealthEvent(547                ExecutionContext,548                provider.Name,549                pie,550                Severity.Warning);551 552            return pie;553        }554        #endregion Errors555    }556}557