MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using Dbg = System.Management.Automation;5 6#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings7#pragma warning disable 565008 9namespace System.Management.Automation10{11 /// <summary>12 /// Holds the state of a Monad Shell session.13 /// </summary>14 internal sealed partial class SessionStateInternal15 {16 /// <summary>17 /// The current scope. It is either the global scope or18 /// a nested scope within the global scope. The current19 /// scope is implied or can be accessed using $local in20 /// the shell.21 /// </summary>22 private SessionStateScope _currentScope;23 24 /// <summary>25 /// Cmdlet parameter name to return in the error message instead of "scopeID".26 /// </summary>27 internal const string ScopeParameterName = "Scope";28 29 /// <summary>30 /// Given a scope identifier, returns the proper session state scope.31 /// </summary>32 /// <param name="scopeID">33 /// A scope identifier that is either one of the "special" scopes like34 /// "global", "local", or "private, or a numeric ID of a relative scope35 /// to the current scope.36 /// </param>37 /// <returns>38 /// The scope identified by the scope ID or the current scope if the39 /// scope ID is not defined as a special or numeric scope identifier.40 /// </returns>41 /// <exception cref="ArgumentException">42 /// If <paramref name="scopeID"/> is less than zero, or not43 /// a number and not "script", "global", "local", or "private"44 /// </exception>45 /// <exception cref="ArgumentOutOfRangeException">46 /// If <paramref name="scopeID"/> is less than zero or greater than the number of currently47 /// active scopes.48 /// </exception>49 internal SessionStateScope GetScopeByID(string scopeID)50 {51 SessionStateScope result = _currentScope;52 53 if (!string.IsNullOrEmpty(scopeID))54 {55 if (string.Equals(56 scopeID,57 StringLiterals.Global,58 StringComparison.OrdinalIgnoreCase))59 {60 result = GlobalScope;61 }62 else if (string.Equals(63 scopeID,64 StringLiterals.Local,65 StringComparison.OrdinalIgnoreCase))66 {67 result = _currentScope;68 }69 else if (string.Equals(70 scopeID,71 StringLiterals.Private,72 StringComparison.OrdinalIgnoreCase))73 {74 result = _currentScope;75 }76 else if (string.Equals(77 scopeID,78 StringLiterals.Script,79 StringComparison.OrdinalIgnoreCase))80 {81 // Get the current script scope from the stack.82 result = _currentScope.ScriptScope;83 }84 else85 {86 // Since the scope is not any of the special scopes87 // try parsing it as an ID88 89 try90 {91 int scopeNumericID = Int32.Parse(scopeID, System.Globalization.CultureInfo.CurrentCulture);92 93 if (scopeNumericID < 0)94 {95 throw PSTraceSource.NewArgumentOutOfRangeException(ScopeParameterName, scopeID);96 }97 98 result = GetScopeByID(scopeNumericID) ?? _currentScope;99 }100 catch (FormatException)101 {102 throw PSTraceSource.NewArgumentException(ScopeParameterName, AutomationExceptions.InvalidScopeIdArgument, ScopeParameterName);103 }104 catch (OverflowException)105 {106 throw PSTraceSource.NewArgumentOutOfRangeException(ScopeParameterName, scopeID);107 }108 }109 }110 111 return result;112 }113 114 /// <summary>115 /// Given a scope ID, walks the scope list to the appropriate scope and returns it.116 /// </summary>117 /// <param name="scopeID">118 /// The numeric indexer to the scope relative to the current scope.119 /// </param>120 /// <returns>121 /// The scope at the index specified. The index is relative to the current122 /// scope.123 /// </returns>124 /// <exception cref="ArgumentOutOfRangeException">125 /// If <paramref name="scopeID"/> is less than zero or greater than the number of currently126 /// active scopes.127 /// </exception>128 internal SessionStateScope GetScopeByID(int scopeID)129 {130 SessionStateScope processingScope = _currentScope;131 int originalID = scopeID;132 133 while (scopeID > 0 && processingScope != null)134 {135 processingScope = processingScope.Parent;136 scopeID--;137 }138 139 if (processingScope == null && scopeID >= 0)140 {141 ArgumentOutOfRangeException outOfRange =142 PSTraceSource.NewArgumentOutOfRangeException(143 ScopeParameterName,144 originalID,145 SessionStateStrings.ScopeIDExceedsAvailableScopes,146 originalID);147 throw outOfRange;148 }149 150 return processingScope;151 }152 153 /// <summary>154 /// The global scope of session state. Can be accessed155 /// using $global in the shell.156 /// </summary>157 internal SessionStateScope GlobalScope { get; }158 159 /// <summary>160 /// The module scope of a session state. This is only used internally161 /// by the engine. There is no module scope qualifier.162 /// </summary>163 internal SessionStateScope ModuleScope { get; }164 165 /// <summary>166 /// Gets the session state current scope.167 /// </summary>168 internal SessionStateScope CurrentScope169 {170 get171 {172 return _currentScope;173 }174 175 set176 {177 Diagnostics.Assert(178 value != null,179 "A null scope should never be set");180#if DEBUG181 // This code is ifdef'd for DEBUG because it may pose a significant182 // performance hit and is only really required to validate our internal183 // code. There is no way anyone outside the Monad codebase can cause184 // these error conditions to be hit.185 186 // Need to make sure the new scope is in the global scope lineage187 188 SessionStateScope scope = value;189 bool inGlobalScopeLineage = false;190 191 while (scope != null)192 {193 if (scope == GlobalScope)194 {195 inGlobalScopeLineage = true;196 break;197 }198 199 scope = scope.Parent;200 }201 202 Diagnostics.Assert(203 inGlobalScopeLineage,204 "The scope specified to be set in CurrentScope is not in the global scope lineage. All scopes must originate from the global scope.");205#endif206 207 _currentScope = value;208 }209 }210 211 /// <summary>212 /// Gets the session state current script scope.213 /// </summary>214 internal SessionStateScope ScriptScope { get { return _currentScope.ScriptScope; } }215 216 /// <summary>217 /// Creates a new scope in the scope tree and assigns the parent218 /// and child scopes appropriately.219 /// </summary>220 /// <param name="isScriptScope">221 /// If true, the new scope is pushed on to the script scope stack and222 /// can be referenced using $script:223 /// </param>224 /// <returns>225 /// A new SessionStateScope which is a child of the current scope.226 /// </returns>227 internal SessionStateScope NewScope(bool isScriptScope)228 {229 Diagnostics.Assert(230 _currentScope != null,231 "The currentScope should always be set.");232 233 // Create the new child scope.234 235 SessionStateScope newScope = new SessionStateScope(_currentScope);236 237 if (isScriptScope)238 {239 newScope.ScriptScope = newScope;240 }241 242 return newScope;243 }244 245 /// <summary>246 /// Removes the current scope from the scope tree and247 /// changes the current scope to the parent scope.248 /// </summary>249 /// <param name="scope">250 /// The scope to cleanup and remove.251 /// </param>252 /// <exception cref="SessionStateUnauthorizedAccessException">253 /// The global scope cannot be removed.254 /// </exception>255 internal void RemoveScope(SessionStateScope scope)256 {257 Diagnostics.Assert(258 _currentScope != null,259 "The currentScope should always be set.");260 261 if (scope == GlobalScope)262 {263 SessionStateUnauthorizedAccessException e =264 new SessionStateUnauthorizedAccessException(265 StringLiterals.Global,266 SessionStateCategory.Scope,267 "GlobalScopeCannotRemove",268 SessionStateStrings.GlobalScopeCannotRemove);269 270 throw e;271 }272 273 // Give the provider a chance to cleanup the drive data associated274 // with drives in this scope275 276 foreach (PSDriveInfo drive in scope.Drives)277 {278 if (drive == null)279 {280 continue;281 }282 283 CmdletProviderContext context = new CmdletProviderContext(this.ExecutionContext);284 285 // Call CanRemoveDrive to give the provider a chance to cleanup286 // but ignore the return value and exceptions287 288 try289 {290 CanRemoveDrive(drive, context);291 }292 catch (LoopFlowException)293 {294 throw;295 }296 catch (PipelineStoppedException)297 {298 throw;299 }300 catch (ActionPreferenceStopException)301 {302 throw;303 }304 catch (Exception) // Catch-all OK, 3rd party callout.305 {306 // Ignore all exceptions from the provider as we are307 // going to force the removal anyway308 }309 }310 311 scope.RemoveAllDrives();312 313 // If the scope being removed is the current scope,314 // then it must be removed from the tree.315 316 if (scope == _currentScope && _currentScope.Parent != null)317 {318 _currentScope = _currentScope.Parent;319 }320 321 scope.Parent = null;322 }323 }324}325 326#pragma warning restore 56500327 