MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Diagnostics.CodeAnalysis;7using System.Globalization;8using System.IO;9using System.Management.Automation.Host;10using System.Management.Automation.Internal;11using System.Management.Automation.Internal.Host;12using System.Management.Automation.Language;13using System.Management.Automation.Runspaces;14using System.Reflection;15using System.Runtime.CompilerServices;16using System.Security;17 18using Microsoft.PowerShell;19using Microsoft.PowerShell.Commands.Internal.Format;20 21namespace System.Management.Automation22{23 /// <summary>24 /// This class contains the execution context that gets passed25 /// around to commands. This is all of the information that lets you get26 /// at session state and the host interfaces.27 /// </summary>28 internal class ExecutionContext29 {30 #region Properties31 32 /// <summary>33 /// The events received by this runspace.34 /// </summary>35 internal PSLocalEventManager Events { get; private set; }36 37 internal HashSet<string> AutoLoadingModuleInProgress { get; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);38 39 /// <summary>40 /// The debugger for the interpreter.41 /// </summary>42 internal ScriptDebugger Debugger43 {44 get { return _debugger; }45 }46 47 internal ScriptDebugger _debugger;48 49 internal int _debuggingMode;50 51 /// <summary>52 /// Reset or clear the various context managers so the runspace can be reused without contamination.53 /// </summary>54 internal void ResetManagers()55 {56 _debugger?.ResetDebugger();57 58 Events?.Dispose();59 Events = new PSLocalEventManager(this);60 61 this.transactionManager?.Dispose();62 this.transactionManager = new PSTransactionManager();63 }64 /// <summary>65 /// The tracing mode for the interpreter.66 /// </summary>67 /// <value>True if tracing is turned on, false if it's turned off.</value>68 internal int PSDebugTraceLevel69 {70 get71 {72 // Pretend that tracing is off if ignoreScriptDebug is true73 return IgnoreScriptDebug ? 0 : _debugTraceLevel;74 }75 76 set77 {78 _debugTraceLevel = value;79 }80 }81 82 private int _debugTraceLevel;83 84 /// <summary>85 /// The step mode for the interpreter.86 /// </summary>87 /// <value>True of stepping is turned on, false if it's turned off.</value>88 internal bool PSDebugTraceStep89 {90 get91 {92 // Pretend that tracing is off if ignoreScriptDebug is true93 return !IgnoreScriptDebug && _debugTraceStep;94 }95 96 set97 {98 _debugTraceStep = value;99 }100 }101 102 private bool _debugTraceStep;103 104 // Helper for generated code to handle running w/ no execution context105 internal static bool IsStrictVersion(ExecutionContext context, int majorVersion)106 {107 context ??= LocalPipeline.GetExecutionContextFromTLS();108 109 return (context != null) && context.IsStrictVersion(majorVersion);110 }111 /// <summary>112 /// Check to see a specific version of strict mode is enabled. The check is always scoped,113 /// even though in version 1 the check was engine wide.114 /// </summary>115 /// <param name="majorVersion">The version for a strict check about to be performed.</param>116 /// <returns></returns>117 internal bool IsStrictVersion(int majorVersion)118 {119 SessionStateScope scope = EngineSessionState.CurrentScope;120 while (scope != null)121 {122 // If StrictModeVersion is null, we haven't seen set-strictmode, so check the parent scope.123 if (scope.StrictModeVersion != null)124 {125 // If StrictModeVersion is not null, just check the major version. A version of 0126 // is the same as off to make this a simple check.127 return (scope.StrictModeVersion.Major >= majorVersion);128 }129 // We shouldn't check global scope if we were in a module.130 if (scope == EngineSessionState.ModuleScope)131 {132 break;133 }134 135 scope = scope.Parent;136 }137 138 // set-strictmode hasn't been used.139 return false;140 }141 142 /// <summary>143 /// Is true if the current statement in the interpreter should be traced...144 /// </summary>145 internal bool ShouldTraceStatement146 {147 get148 {149 // Pretend that tracing is off if ignoreScriptDebug is true150 return !IgnoreScriptDebug && (_debugTraceLevel > 0 || _debugTraceStep);151 }152 }153 154 /// <summary>155 /// If true, then a script command processor should rethrow the exit exception instead of156 /// simply capturing it. This is used by the -file option on the console host.157 /// </summary>158 internal bool ScriptCommandProcessorShouldRethrowExit { get; set; } = false;159 160 /// <summary>161 /// If this flag is set to true, script trace output162 /// will not be generated regardless of the state of the163 /// trace flag.164 /// </summary>165 /// <value>The current state of the IgnoreScriptDebug flag.</value>166 internal bool IgnoreScriptDebug { get; set; } = true;167 168 /// <summary>169 /// Gets the automation engine instance.170 /// </summary>171 internal AutomationEngine Engine { get; private set; }172 173 internal InitialSessionState InitialSessionState { get; }174 175 /// <summary>176 /// Added for Win8: 336382177 /// Contains the name of the previous module that was processed. This178 /// allows you to skip this module when doing a lookup.179 /// </summary>180 internal string PreviousModuleProcessed { get; set; }181 182 /// <summary>183 /// Added for 4980967184 /// Contains the name of the latest module that was imported,185 /// Allows "module\function" to call the function from latest imported module instead of randomly choosing the first module in the moduletable.186 /// </summary>187 internal Hashtable previousModuleImported { get; set; } = new Hashtable();188 189 /// <summary>190 /// Contains the name of the module currently being processed. This191 /// allows you to skip this module when doing a lookup.192 /// </summary>193 internal string ModuleBeingProcessed { get; set; }194 195 /// <summary>196 /// Authorization manager for this runspace.197 /// </summary>198 internal AuthorizationManager AuthorizationManager { get; private set; }199 200 /// <summary>201 /// Gets the appropriate provider names for the default202 /// providers based on the type of the shell203 /// (single shell or custom shell).204 /// </summary>205 internal ProviderNames ProviderNames206 {207 get208 {209 _providerNames ??= new SingleShellProviderNames();210 211 return _providerNames;212 }213 }214 215 private ProviderNames _providerNames;216 217 /// <summary>218 /// The module information for this engine...219 /// </summary>220 internal ModuleIntrinsics Modules { get; private set; }221 222 /// <summary>223 /// Get the shellID for this runspace...224 /// </summary>225 internal string ShellID226 {227 get228 {229 if (_shellId == null)230 {231 // Use the ShellID from PSAuthorizationManager before everything else because that's what's used232 // to check execution policy...233 if (AuthorizationManager is PSAuthorizationManager && !string.IsNullOrEmpty(AuthorizationManager.ShellId))234 {235 _shellId = AuthorizationManager.ShellId;236 }237 else238 {239 // Finally fall back to the default shell id...240 _shellId = Utils.DefaultPowerShellShellID;241 }242 }243 244 return _shellId;245 }246 }247 248 private string _shellId;249 250 /// <summary>251 /// Session State with which this instance of engine works.252 /// </summary>253 internal SessionStateInternal EngineSessionState { get; set; }254 255 /// <summary>256 /// The default or top-level session state instance for the257 /// engine.258 /// </summary>259 internal SessionStateInternal TopLevelSessionState { get; private set; }260 261 /// <summary>262 /// Get the SessionState facade for the internal session state APIs.263 /// </summary>264 internal SessionState SessionState265 {266 get267 {268 return EngineSessionState.PublicSessionState;269 }270 }271 272 /// <summary>273 /// Get/set constraints for this execution environment.274 /// </summary>275 internal PSLanguageMode LanguageMode276 {277 get278 {279 return _languageMode;280 }281 282 set283 {284 // If we're moving to ConstrainedLanguage, invalidate the binding285 // caches. After that, the binding rules encode the language mode.286 if (value == PSLanguageMode.ConstrainedLanguage)287 {288 HasRunspaceEverUsedConstrainedLanguageMode = true;289 290 // If 'ExecutionContext.HasEverUsedConstrainedLanguage' is already set to True, then we have291 // already invalidated all cached binders, and binders already started to generate code with292 // consideration of 'LanguageMode'. In such case, we don't need to invalidate cached binders293 // again.294 // Note that when executing script blocks marked as 'FullLanguage' in a 'ConstrainedLanguage'295 // environment, we will set and Restore 'context.LanguageMode' very often. But we should not296 // invalidate the cached binders every time we restore to 'ConstrainedLanguage'.297 if (!ExecutionContext.HasEverUsedConstrainedLanguage)298 {299 lock (lockObject)300 {301 // If another thread has already set 'ExecutionContext.HasEverUsedConstrainedLanguage'302 // while we are waiting on the lock, then nothing needs to be done.303 if (!ExecutionContext.HasEverUsedConstrainedLanguage)304 {305 PSSetMemberBinder.InvalidateCache();306 PSInvokeMemberBinder.InvalidateCache();307 PSConvertBinder.InvalidateCache();308 PSBinaryOperationBinder.InvalidateCache();309 PSGetIndexBinder.InvalidateCache();310 PSSetIndexBinder.InvalidateCache();311 PSCreateInstanceBinder.InvalidateCache();312 313 // Set 'HasEverUsedConstrainedLanguage' at the very end to guarantee other threads to wait until314 // all invalidation operations are done.315 UntrustedObjects = new ConditionalWeakTable<object, object>();316 ExecutionContext.HasEverUsedConstrainedLanguage = true;317 }318 }319 }320 }321 322 // Conversion caches don't have version info / binding rules, so must be323 // cleared every time.324 LanguagePrimitives.RebuildConversionCache();325 326 _languageMode = value;327 }328 }329 330 private PSLanguageMode _languageMode = PSLanguageMode.FullLanguage;331 332 /// <summary>333 /// True if this runspace has ever used constrained language mode.334 /// </summary>335 internal bool HasRunspaceEverUsedConstrainedLanguageMode { get; private set; }336 337 /// <summary>338 /// Indicate if a parameter binding is happening that transitions the execution from ConstrainedLanguage339 /// mode to a trusted FullLanguage command.340 /// </summary>341 internal bool LanguageModeTransitionInParameterBinding { get; set; }342 343 /// <summary>344 /// True if we've ever used ConstrainedLanguage. If this is the case, then the binding restrictions345 /// need to also validate against the language mode.346 /// </summary>347 internal static bool HasEverUsedConstrainedLanguage { get; private set; }348 349 #region Variable Tracking350 351 /// <summary>352 /// Initialized when 'ConstrainedLanguage' is applied.353 /// The objects contained in this table are considered to be untrusted.354 /// </summary>355 private static ConditionalWeakTable<object, object> UntrustedObjects { get; set; }356 357 /// <summary>358 /// Helper for checking if the given value is marked as untrusted.359 /// </summary>360 internal static bool IsMarkedAsUntrusted(object value)361 {362 bool result = false;363 var baseValue = PSObject.Base(value);364 if (baseValue != null && baseValue != NullString.Value)365 {366 result = UntrustedObjects.TryGetValue(baseValue, out _);367 }368 369 return result;370 }371 372 /// <summary>373 /// Helper for marking a value as untrusted.374 /// </summary>375 internal static void MarkObjectAsUntrusted(object value)376 {377 // If the value is a PSObject, then we mark its base object untrusted378 var baseValue = PSObject.Base(value);379 if (baseValue != null && baseValue != NullString.Value)380 {381 // It's actually setting a key value pair when the key doesn't exist382 UntrustedObjects.GetValue(baseValue, static key => null);383 384 try385 {386 // If it's a PSReference object, we need to also mark the value it's holding on.387 // This could result in a recursion if psRef.Value points to itself directly or indirectly, so we check if psRef.Value is already388 // marked before making a recursive call. The additional check adds extra overhead for handling PSReference object, but it should389 // be rare in practice.390 var psRef = baseValue as PSReference;391 if (psRef != null && !IsMarkedAsUntrusted(psRef.Value))392 {393 MarkObjectAsUntrusted(psRef.Value);394 }395 }396 catch { /* psRef.Value may call PSVariable.Value under the hood, which may throw arbitrary exception */ }397 }398 }399 400 /// <summary>401 /// Helper for setting the untrusted value of an assignment to either a 'Global:' variable, or a 'Script:' variable in a module scope.402 /// </summary>403 /// <remarks>404 /// This method is for tracking assignment to global variables and module script scope varaibles in ConstrainedLanguage mode. Those variables405 /// can go across boundaries between ConstrainedLanguage and FullLanguage, and make it easy for a trusted script to use data from an untrusted406 /// environment. Therefore, in ConstrainedLanguage mode, we need to mark the value objects assigned to those variables as untrusted.407 /// </remarks>408 internal static void MarkObjectAsUntrustedForVariableAssignment(PSVariable variable, SessionStateScope scope, SessionStateInternal sessionState)409 {410 if (scope.Parent == null || // If it's the global scope, OR411 (sessionState.Module != null && // it's running in a module AND412 scope.ScriptScope == scope && scope.Parent.Parent == null)) // it's the module's script scope (scope.Parent is global scope and scope.ScriptScope points to itself)413 {414 // We are setting value for either a 'Global:' variable, or a 'Script:' variable within a module in 'ConstrainedLanguage' mode.415 // Global variable may be referenced within trusted script block (scriptBlock.LanguageMode == 'FullLanguage'), and users could416 // also set a 'Script:' variable in a trusted module scope from 'ConstrainedLanguage' environment via '& $mo { $script:<var> }'.417 // So we need to mark the value as untrusted.418 MarkObjectAsUntrusted(variable.Value);419 }420 }421 422 /// <summary>423 /// The result object is assumed generated by operating on the original object.424 /// So if the original object is from an untrusted input source, we mark the result object as untrusted.425 /// </summary>426 internal static void PropagateInputSource(object originalObject, object resultObject, PSLanguageMode currentLanguageMode)427 {428 // The untrusted flag is populated only in FullLanguage mode and ConstrainedLanguage has been used in the process before.429 if (ExecutionContext.HasEverUsedConstrainedLanguage && currentLanguageMode == PSLanguageMode.FullLanguage && IsMarkedAsUntrusted(originalObject))430 {431 MarkObjectAsUntrusted(resultObject);432 }433 }434 435 #endregion436 437 /// <summary>438 /// If true the PowerShell debugger will use FullLanguage mode, otherwise it will use the current language mode.439 /// </summary>440 internal bool UseFullLanguageModeInDebugger441 {442 get443 {444 return InitialSessionState != null && InitialSessionState.UseFullLanguageModeInDebugger;445 }446 }447 448 internal static readonly List<string> ModulesWithJobSourceAdapters = new List<string>449 {450 Utils.ScheduledJobModuleName,451 };452 453 /// <summary>454 /// Is true if the PSScheduledJob module is loaded for this runspace.455 /// </summary>456 internal bool IsModuleWithJobSourceAdapterLoaded457 {458 get; set;459 }460 461 /// <summary>462 /// Gets the location globber for the session state for463 /// this instance of the runspace.464 /// </summary>465 internal LocationGlobber LocationGlobber466 {467 get468 {469 _locationGlobber = new LocationGlobber(this.SessionState);470 return _locationGlobber;471 }472 }473 474 private LocationGlobber _locationGlobber;475 476 /// <summary>477 /// The assemblies that have been loaded for this runspace.478 /// </summary>479 internal Dictionary<string, Assembly> AssemblyCache { get; private set; }480 #endregion Properties481 482 #region Engine State483 484 /// <summary>485 /// The state for current engine that is running.486 /// </summary>487 /// <value></value>488 internal EngineState EngineState { get; set; } = EngineState.None;489 490 #endregion491 492 #region GetSetVariable methods493 494 /// <summary>495 /// Get a variable out of session state.496 /// </summary>497 internal object GetVariableValue(VariablePath path)498 {499 CmdletProviderContext context;500 SessionStateScope scope;501 return EngineSessionState.GetVariableValue(path, out context, out scope);502 }503 504 /// <summary>505 /// Get a variable out of session state. This calls GetVariable(name) and returns the506 /// value unless it is null in which case it returns the defaultValue provided by the caller.507 /// </summary>508 internal object GetVariableValue(VariablePath path, object defaultValue)509 {510 return EngineSessionState.GetVariableValue(path, out _, out _) ?? defaultValue;511 }512 513 /// <summary>514 /// Set a variable in session state.515 /// </summary>516 internal void SetVariable(VariablePath path, object newValue)517 {518 EngineSessionState.SetVariable(path, newValue, true, CommandOrigin.Internal);519 }520 521 internal T GetEnumPreference<T>(VariablePath preferenceVariablePath, T defaultPref, out bool defaultUsed)522 {523 object val = EngineSessionState.GetVariableValue(preferenceVariablePath, out _, out _);524 if (val is T)525 {526 if (val is ActionPreference actionPreferenceValue)527 {528 CheckActionPreference(preferenceVariablePath, actionPreferenceValue, defaultPref);529 }530 531 T convertedResult = (T)val;532 533 defaultUsed = false;534 return convertedResult;535 }536 537 defaultUsed = true;538 T result = defaultPref;539 540 if (val != null)541 {542 try543 {544 string valString = val as string;545 if (valString != null)546 {547 result = (T)Enum.Parse(typeof(T), valString, true);548 defaultUsed = false;549 }550 else551 {552 result = (T)PSObject.Base(val);553 defaultUsed = false;554 }555 556 if (result is ActionPreference actionPreferenceValue)557 {558 CheckActionPreference(preferenceVariablePath, actionPreferenceValue, defaultPref);559 }560 }561 catch (InvalidCastException)562 {563 // default value is used564 }565 catch (ArgumentException)566 {567 // default value is used568 }569 }570 571 return result;572 }573 574 private void CheckActionPreference(VariablePath preferenceVariablePath, ActionPreference preference, object defaultValue)575 {576 if (preference == ActionPreference.Suspend)577 {578 // ActionPreference.Suspend is reserved for future use. When it is used, reset579 // the variable to its default.580 string message = StringUtil.Format(ErrorPackage.ReservedActionPreferenceReplacedError, preference, preferenceVariablePath.UserPath, defaultValue);581 EngineSessionState.SetVariable(preferenceVariablePath, defaultValue, true, CommandOrigin.Internal);582 throw new NotSupportedException(message);583 }584 }585 586 /// <summary>587 /// Same as GetEnumPreference, but for boolean values.588 /// </summary>589 /// <param name="preferenceVariablePath"></param>590 /// <param name="defaultPref"></param>591 /// <param name="defaultUsed"></param>592 /// <returns></returns>593 internal bool GetBooleanPreference(VariablePath preferenceVariablePath, bool defaultPref, out bool defaultUsed)594 {595 object val = EngineSessionState.GetVariableValue(preferenceVariablePath, out _, out _);596 if (val is null)597 {598 defaultUsed = true;599 return defaultPref;600 }601 602 defaultUsed = !LanguagePrimitives.TryConvertTo(val, out bool converted);603 return defaultUsed ? defaultPref : converted;604 }605 #endregion GetSetVariable methods606 607 #region HelpSystem608 609 /// <summary>610 /// Help system for this engine context.611 /// </summary>612 /// <value></value>613 internal HelpSystem HelpSystem614 {615 get { return _helpSystem ??= new HelpSystem(this); }616 }617 618 private HelpSystem _helpSystem;619 620 #endregion621 622 #region FormatAndOutput623 internal object FormatInfo { get; set; }624 625 #endregion626 627 internal Dictionary<string, ScriptBlock> CustomArgumentCompleters { get; set; }628 629 internal Dictionary<string, ScriptBlock> NativeArgumentCompleters { get; set; }630 631 /// <summary>632 /// Routine to create a command(processor) instance using the factory.633 /// </summary>634 /// <param name="command">The name of the command to lookup.</param>635 /// <param name="dotSource"></param>636 /// <param name="forCompletion"></param>637 /// <returns>The command processor object.</returns>638 internal CommandProcessorBase CreateCommand(string command, bool dotSource, bool forCompletion = false)639 {640 CommandOrigin commandOrigin = this.EngineSessionState.CurrentScope.ScopeOrigin;641 CommandProcessorBase commandProcessor =642 CommandDiscovery.LookupCommandProcessor(command, commandOrigin, !dotSource, forCompletion);643 // Reset the command origin for script commands... // BUGBUG - dotting can get around command origin checks???644 if (commandProcessor != null && commandProcessor is ScriptCommandProcessorBase)645 {646 commandProcessor.Command.CommandOriginInternal = CommandOrigin.Internal;647 }648 649 return commandProcessor;650 }651 652 /// <summary>653 /// Hold the current command.654 /// </summary>655 /// <value>Reference to command discovery</value>656 internal CommandProcessorBase CurrentCommandProcessor { get; set; }657 658 /// <summary>659 /// Redirect to the CommandDiscovery in the engine.660 /// </summary>661 /// <value>Reference to command discovery</value>662 internal CommandDiscovery CommandDiscovery663 {664 get665 {666 return Engine.CommandDiscovery;667 }668 }669 670 /// <summary>671 /// Interface that should be used for interaction with host.672 /// </summary>673 internal InternalHost EngineHostInterface674 {675 // set not provided: it's not meaningful to change the host post-construction.676 get; private set;677 }678 679 /// <summary>680 /// Interface to be used for interaction with internal681 /// host. InternalHost wraps the host supplied682 /// during construction. Use this wrapper to access683 /// functionality specific to InternalHost.684 /// </summary>685 internal InternalHost InternalHost686 {687 get { return EngineHostInterface; }688 }689 690 /// <summary>691 /// Interface to the public API for the engine.692 /// </summary>693 internal EngineIntrinsics EngineIntrinsics694 {695 get { return _engineIntrinsics ??= new EngineIntrinsics(this); }696 }697 698 private EngineIntrinsics _engineIntrinsics;699 700 /// <summary>701 /// Log context cache.702 /// </summary>703 internal LogContextCache LogContextCache { get; } = new LogContextCache();704 705 #region Output pipes706 /// <summary>707 /// The PipelineWriter provided by the connection object for success output.708 /// </summary>709 internal PipelineWriter ExternalSuccessOutput { get; set; }710 711 /// <summary>712 /// The PipelineWriter provided by the connection object for error output.713 /// </summary>714 internal PipelineWriter ExternalErrorOutput { get; set; }715 716 /// <summary>717 /// The PipelineWriter provided by the connection object for progress output.718 /// </summary>719 internal PipelineWriter ExternalProgressOutput { get; set; }720 721 internal class SavedContextData722 {723 private readonly bool _stepScript;724 private readonly bool _ignoreScriptDebug;725 private readonly int _PSDebug;726 727 private readonly Pipe _shellFunctionErrorOutputPipe;728 729 public SavedContextData(ExecutionContext context)730 {731 _stepScript = context.PSDebugTraceStep;732 _ignoreScriptDebug = context.IgnoreScriptDebug;733 _PSDebug = context.PSDebugTraceLevel;734 735 _shellFunctionErrorOutputPipe = context.ShellFunctionErrorOutputPipe;736 }737 738 public void RestoreContextData(ExecutionContext context)739 {740 context.PSDebugTraceStep = _stepScript;741 context.IgnoreScriptDebug = _ignoreScriptDebug;742 context.PSDebugTraceLevel = _PSDebug;743 744 context.ShellFunctionErrorOutputPipe = _shellFunctionErrorOutputPipe;745 }746 }747 748 /// <summary>749 /// Host uses this to saves context data when entering a nested prompt.750 /// </summary>751 /// <returns></returns>752 internal SavedContextData SaveContextData()753 {754 return new SavedContextData(this);755 }756 757 internal void ResetShellFunctionErrorOutputPipe()758 {759 ShellFunctionErrorOutputPipe = null;760 }761 762 internal Pipe RedirectErrorPipe(Pipe newPipe)763 {764 Pipe oldPipe = ShellFunctionErrorOutputPipe;765 ShellFunctionErrorOutputPipe = newPipe;766 return oldPipe;767 }768 769 /// <summary>770 /// Reset all of the redirection book keeping variables. This routine should be called when starting to771 /// execute a script.772 /// </summary>773 internal void ResetRedirection()774 {775 ShellFunctionErrorOutputPipe = null;776 }777 778 /// <summary>779 /// Function and Script command processors will route their error output to780 /// this pipe if set, unless explicitly routed elsewhere. We also keep track781 /// of the first time this value is set so we can know if it's the default782 /// error output or not.783 /// </summary>784 internal Pipe ShellFunctionErrorOutputPipe { get; set; }785 786 /// <summary>787 /// Supports expression Warning output redirection.788 /// </summary>789 internal Pipe ExpressionWarningOutputPipe { get; set; }790 791 /// <summary>792 /// Supports expression Verbose output redirection.793 /// </summary>794 internal Pipe ExpressionVerboseOutputPipe { get; set; }795 796 /// <summary>797 /// Supports expression Verbose output redirection.798 /// </summary>799 internal Pipe ExpressionDebugOutputPipe { get; set; }800 801 /// <summary>802 /// Supports expression Information output redirection.803 /// </summary>804 internal Pipe ExpressionInformationOutputPipe { get; set; }805 806 #endregion Output pipes807 808 #region Append to $error809 /// <summary>810 /// Appends the object to $global:error if it's an error record or exception.811 /// </summary>812 /// <param name="obj">813 /// ErrorRecord or Exception to be written to $global:error814 /// </param>815 /// <exception cref="ExtendedTypeSystemException">816 /// (get-only) An error occurred accessing $ERROR.817 /// </exception>818 internal void AppendDollarError(object obj)819 {820 ErrorRecord objAsErrorRecord = obj as ErrorRecord;821 if (objAsErrorRecord is null && obj is not Exception)822 {823 Diagnostics.Assert(false, "Object to append was neither an ErrorRecord nor an Exception in ExecutionContext.AppendDollarError");824 return;825 }826 827 if (DollarErrorVariable is not ArrayList arraylist)828 {829 Diagnostics.Assert(false, "$error should be a global constant ArrayList");830 return;831 }832 833 // Don't add the same exception twice...834 if (arraylist.Count > 0)835 {836 // There may be exceptions stored directly in which case837 // the direct comparison will catch them...838 if (arraylist[0] == obj)839 return;840 // otherwise check the exception members of the error records...841 ErrorRecord er1 = arraylist[0] as ErrorRecord;842 843 if (er1 != null && objAsErrorRecord != null && er1.Exception == objAsErrorRecord.Exception)844 return;845 }846 847 const int maxErrorCount = 256;848 849 int numToErase = arraylist.Count - (maxErrorCount - 1);850 if (numToErase > 0)851 {852 arraylist.RemoveRange(853 maxErrorCount - 1,854 numToErase);855 }856 857 arraylist.Insert(0, obj);858 }859 #endregion860 861 #region Scope or Commands (in pipeline) Depth Count862 863 /// <summary>864 /// Check if the stack would overflow soon, if so, throw ScriptCallDepthException.865 /// </summary>866 /// <exception cref="ScriptCallDepthException">867 /// If the stack would overflow soon.868 /// </exception>869 internal static void CheckStackDepth()870 {871 try872 {873 RuntimeHelpers.EnsureSufficientExecutionStack();874 }875 catch (InsufficientExecutionStackException)876 {877 throw new ScriptCallDepthException();878 }879 }880 881 #endregion882 883 /// <summary>884 /// The current connection object.885 /// </summary>886 private Runspace _currentRunspace;887 // This should be internal, but it need to be friend of remoting dll.888 /// <summary>889 /// The current connection object.890 /// </summary>891 internal Runspace CurrentRunspace892 {893 get { return _currentRunspace; }894 895 set { _currentRunspace = value; }896 }897 898 /// <summary>899 /// Each pipeline has a stack of pipeline processor. This method900 /// pushes pp in to stack for currently executing pipeline.901 /// </summary>902 /// <param name="pp"></param>903 internal void PushPipelineProcessor(PipelineProcessor pp)904 {905 if (_currentRunspace == null)906 return;907 LocalPipeline lpl = (LocalPipeline)((RunspaceBase)_currentRunspace).GetCurrentlyRunningPipeline();908 if (lpl == null)909 return;910 lpl.Stopper.Push(pp);911 }912 913 /// <summary>914 /// Each pipeline has a stack of pipeline processor. This method pops the915 /// top item from the stack.916 /// </summary>917 internal void PopPipelineProcessor(bool fromSteppablePipeline)918 {919 if (_currentRunspace == null)920 return;921 LocalPipeline lpl = (LocalPipeline)((RunspaceBase)_currentRunspace).GetCurrentlyRunningPipeline();922 if (lpl == null)923 return;924 lpl.Stopper.Pop(fromSteppablePipeline);925 }926 927 /// <summary>928 /// This flag is checked by parser to stop loops etc.929 /// </summary>930 /// <returns></returns>931 internal bool CurrentPipelineStopping932 {933 get934 {935 if (_currentRunspace == null)936 return false;937 LocalPipeline lpl = (LocalPipeline)((RunspaceBase)_currentRunspace).GetCurrentlyRunningPipeline();938 if (lpl == null)939 return false;940 return lpl.IsStopping;941 }942 }943 944 /// <summary>945 /// True means one of these:946 /// 1) there is a trap statement in a dynamically enclosing statement block that might catch an exception.947 /// 2) execution happens inside a PS class and exceptions should be propagated all the way up, even if there is no enclosing try-catch-finally.948 /// </summary>949 /// <value></value>950 internal bool PropagateExceptionsToEnclosingStatementBlock { get; set; }951 952 internal RuntimeException CurrentExceptionBeingHandled { get; set; }953 954 /// <summary>955 /// Shortcut to get at $?956 /// </summary>957 /// <value>The current value of $? </value>958 internal bool QuestionMarkVariableValue { get; set; } = true;959 960 /// <summary>961 /// Shortcut to get at $error.962 /// </summary>963 /// <value>The current value of $global:error </value>964 internal object DollarErrorVariable965 {966 get967 {968 CmdletProviderContext context = null;969 SessionStateScope scope = null;970 object resultItem = null;971 972 if (!Events.IsExecutingEventAction)973 {974 resultItem = EngineSessionState.GetVariableValue(975 SpecialVariables.ErrorVarPath, out context, out scope);976 }977 else978 {979 resultItem = EngineSessionState.GetVariableValue(980 SpecialVariables.EventErrorVarPath, out context, out scope);981 }982 983 return resultItem;984 }985 986 set987 {988 EngineSessionState.SetVariable(989 SpecialVariables.ErrorVarPath, value, true, CommandOrigin.Internal);990 }991 }992 993 internal ActionPreference DebugPreferenceVariable994 {995 get996 {997 bool defaultUsed = false;998 return this.GetEnumPreference(999 SpecialVariables.DebugPreferenceVarPath,1000 InitialSessionState.DefaultDebugPreference,1001 out defaultUsed);1002 }1003 1004 set1005 {1006 this.EngineSessionState.SetVariable(1007 SpecialVariables.DebugPreferenceVarPath,1008 LanguagePrimitives.ConvertTo(value, typeof(ActionPreference), CultureInfo.InvariantCulture),1009 true,1010 CommandOrigin.Internal);1011 }1012 }1013 1014 internal ActionPreference VerbosePreferenceVariable1015 {1016 get1017 {1018 bool defaultUsed = false;1019 return this.GetEnumPreference(1020 SpecialVariables.VerbosePreferenceVarPath,1021 InitialSessionState.DefaultVerbosePreference,1022 out defaultUsed);1023 }1024 1025 set1026 {1027 this.EngineSessionState.SetVariable(1028 SpecialVariables.VerbosePreferenceVarPath,1029 LanguagePrimitives.ConvertTo(value, typeof(ActionPreference), CultureInfo.InvariantCulture),1030 true,1031 CommandOrigin.Internal);1032 }1033 }1034 1035 internal ActionPreference ErrorActionPreferenceVariable1036 {1037 get1038 {1039 bool defaultUsed = false;1040 return this.GetEnumPreference(1041 SpecialVariables.ErrorActionPreferenceVarPath,1042 InitialSessionState.DefaultErrorActionPreference,1043 out defaultUsed);1044 }1045 1046 set1047 {1048 this.EngineSessionState.SetVariable(1049 SpecialVariables.ErrorActionPreferenceVarPath,1050 LanguagePrimitives.ConvertTo(value, typeof(ActionPreference), CultureInfo.InvariantCulture),1051 true,1052 CommandOrigin.Internal);1053 }1054 }1055 1056 internal ActionPreference WarningActionPreferenceVariable1057 {1058 get1059 {1060 bool defaultUsed = false;1061 return this.GetEnumPreference(1062 SpecialVariables.WarningPreferenceVarPath,1063 InitialSessionState.DefaultWarningPreference,1064 out defaultUsed);1065 }1066 1067 set1068 {1069 this.EngineSessionState.SetVariable(1070 SpecialVariables.WarningPreferenceVarPath,1071 LanguagePrimitives.ConvertTo(value, typeof(ActionPreference), CultureInfo.InvariantCulture),1072 true,1073 CommandOrigin.Internal);1074 }1075 }1076 1077 internal ActionPreference InformationActionPreferenceVariable1078 {1079 get1080 {1081 bool defaultUsed = false;1082 return this.GetEnumPreference(1083 SpecialVariables.InformationPreferenceVarPath,1084 InitialSessionState.DefaultInformationPreference,1085 out defaultUsed);1086 }1087 1088 set1089 {1090 this.EngineSessionState.SetVariable(1091 SpecialVariables.InformationPreferenceVarPath,1092 LanguagePrimitives.ConvertTo(value, typeof(ActionPreference), CultureInfo.InvariantCulture),1093 true,1094 CommandOrigin.Internal);1095 }1096 }1097 1098 internal object WhatIfPreferenceVariable1099 {1100 get1101 {1102 CmdletProviderContext context = null;1103 SessionStateScope scope = null;1104 1105 object resultItem = this.EngineSessionState.GetVariableValue(1106 SpecialVariables.WhatIfPreferenceVarPath,1107 out context,1108 out scope);1109 1110 return resultItem;1111 }1112 1113 set1114 {1115 this.EngineSessionState.SetVariable(1116 SpecialVariables.WhatIfPreferenceVarPath,1117 value,1118 true,1119 CommandOrigin.Internal);1120 }1121 }1122 1123 internal ConfirmImpact ConfirmPreferenceVariable1124 {1125 get1126 {1127 bool defaultUsed = false;1128 return this.GetEnumPreference(1129 SpecialVariables.ConfirmPreferenceVarPath,1130 InitialSessionState.DefaultConfirmPreference,1131 out defaultUsed);1132 }1133 1134 set1135 {1136 this.EngineSessionState.SetVariable(1137 SpecialVariables.ConfirmPreferenceVarPath,1138 LanguagePrimitives.ConvertTo(value, typeof(ConfirmImpact), CultureInfo.InvariantCulture),1139 true,1140 CommandOrigin.Internal);1141 }1142 }1143 1144 internal void RunspaceClosingNotification()1145 {1146 EngineSessionState.RunspaceClosingNotification();1147 1148 _debugger?.Dispose();1149 1150 Events?.Dispose();1151 Events = null;1152 1153 this.transactionManager?.Dispose();1154 this.transactionManager = null;1155 }1156 1157 /// <summary>1158 /// Gets the type table instance for this engine.1159 /// </summary>1160 internal TypeTable TypeTable1161 {1162 get1163 {1164 if (_typeTable == null)1165 {1166 _typeTable = new TypeTable();1167 _typeTableWeakReference = new WeakReference<TypeTable>(_typeTable);1168 }1169 1170 return _typeTable;1171 }1172 1173 set1174 {1175 _typeTable = value;1176 _typeTableWeakReference = (value != null) ? new WeakReference<TypeTable>(value) : null;1177 }1178 }1179 1180 /// <summary>1181 /// Here for PSObject, should probably not be used elsewhere, maybe not even in PSObject.1182 /// </summary>1183 internal WeakReference<TypeTable> TypeTableWeakReference1184 {1185 get1186 {1187 if (_typeTable == null)1188 {1189 var unused = TypeTable;1190 }1191 1192 return _typeTableWeakReference;1193 }1194 }1195 1196 private TypeTable _typeTable;1197 private WeakReference<TypeTable> _typeTableWeakReference;1198 1199 /// <summary>1200 /// Gets the format info database for this engine.