MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.ObjectModel;5 6using Dbg = System.Management.Automation;7 8namespace System.Management.Automation9{10 /// <summary>11 /// The context of the core command that is being run. This12 /// includes data like the user name and password, as well13 /// as callbacks for streaming output, prompting, and progress.14 ///15 /// This allows the providers to be called in a variety of situations.16 /// The most common will be from the core cmdlets themselves but they17 /// can also be called programmatically either by having the results18 /// accumulated or by providing delegates for the various streams.19 ///20 /// NOTE: USER Feedback mechanism are only enabled for the CoreCmdlet21 /// case. This is because we have not seen a use-case for them in the22 /// other scenarios.23 /// </summary>24 internal sealed class CmdletProviderContext25 {26 #region Trace object27 28 /// <summary>29 /// An instance of the PSTraceSource class used for trace output30 /// using "CmdletProviderContext" as the category.31 /// </summary>32 [Dbg.TraceSource(33 "CmdletProviderContext",34 "The context under which a core command is being run.")]35 private static readonly Dbg.PSTraceSource s_tracer =36 Dbg.PSTraceSource.GetTracer("CmdletProviderContext",37 "The context under which a core command is being run.");38 39 #endregion Trace object40 41 #region Constructor42 43 /// <summary>44 /// Constructs the context under which the core command providers45 /// operate.46 /// </summary>47 /// <param name="executionContext">48 /// The context of the engine.49 /// </param>50 /// <exception cref="ArgumentNullException">51 /// If <paramref name="executionContext"/> is null.52 /// </exception>53 internal CmdletProviderContext(ExecutionContext executionContext)54 {55 if (executionContext == null)56 {57 throw PSTraceSource.NewArgumentNullException(nameof(executionContext));58 }59 60 ExecutionContext = executionContext;61 Origin = CommandOrigin.Internal;62 Drive = executionContext.EngineSessionState.CurrentDrive;63 if ((executionContext.CurrentCommandProcessor != null) &&64 (executionContext.CurrentCommandProcessor.Command is Cmdlet))65 {66 _command = (Cmdlet)executionContext.CurrentCommandProcessor.Command;67 }68 }69 70 /// <summary>71 /// Constructs the context under which the core command providers72 /// operate.73 /// </summary>74 /// <param name="executionContext">75 /// The context of the engine.76 /// </param>77 /// <param name="origin">78 /// The origin of the caller of this API79 /// </param>80 /// <exception cref="ArgumentNullException">81 /// If <paramref name="executionContext"/> is null.82 /// </exception>83 internal CmdletProviderContext(ExecutionContext executionContext, CommandOrigin origin)84 {85 if (executionContext == null)86 {87 throw PSTraceSource.NewArgumentNullException(nameof(executionContext));88 }89 90 ExecutionContext = executionContext;91 Origin = origin;92 }93 94 /// <summary>95 /// Constructs the context under which the core command providers96 /// operate.97 /// </summary>98 /// <param name="command">99 /// The command object that is running.100 /// </param>101 /// <param name="credentials">102 /// The credentials the core command provider should use.103 /// </param>104 /// <param name="drive">105 /// The drive under which this context should operate.106 /// </param>107 /// <exception cref="ArgumentNullException">108 /// If <paramref name="command"/> is null.109 /// </exception>110 /// <exception cref="ArgumentException">111 /// If <paramref name="command"/> contains a null Host or Context reference.112 /// </exception>113 internal CmdletProviderContext(114 PSCmdlet command,115 PSCredential credentials,116 PSDriveInfo drive)117 {118 // verify the command parameter119 if (command == null)120 {121 throw PSTraceSource.NewArgumentNullException(nameof(command));122 }123 124 _command = command;125 Origin = command.CommandOrigin;126 127 if (credentials != null)128 {129 _credentials = credentials;130 }131 132 Drive = drive;133 134 if (command.Host == null)135 {136 throw PSTraceSource.NewArgumentException("command.Host");137 }138 139 if (command.Context == null)140 {141 throw PSTraceSource.NewArgumentException("command.Context");142 }143 144 ExecutionContext = command.Context;145 146 // Stream will default to true because command methods will be used.147 148 PassThru = true;149 _streamErrors = true;150 }151 152 /// <summary>153 /// Constructs the context under which the core command providers154 /// operate.155 /// </summary>156 /// <param name="command">157 /// The command object that is running.158 /// </param>159 /// <param name="credentials">160 /// The credentials the core command provider should use.161 /// </param>162 /// <exception cref="ArgumentNullException">163 /// If <paramref name="command"/> is null.164 /// </exception>165 /// <exception cref="ArgumentException">166 /// If <paramref name="command"/> contains a null Host or Context reference.167 /// </exception>168 internal CmdletProviderContext(169 PSCmdlet command,170 PSCredential credentials)171 {172 // verify the command parameter173 if (command == null)174 {175 throw PSTraceSource.NewArgumentNullException(nameof(command));176 }177 178 _command = command;179 Origin = command.CommandOrigin;180 181 if (credentials != null)182 {183 _credentials = credentials;184 }185 186 if (command.Host == null)187 {188 throw PSTraceSource.NewArgumentException("command.Host");189 }190 191 if (command.Context == null)192 {193 throw PSTraceSource.NewArgumentException("command.Context");194 }195 196 ExecutionContext = command.Context;197 198 // Stream will default to true because command methods will be used.199 200 PassThru = true;201 _streamErrors = true;202 }203 204 /// <summary>205 /// Constructs the context under which the core command providers206 /// operate.207 /// </summary>208 /// <param name="command">209 /// The command object that is running.210 /// </param>211 /// <exception cref="ArgumentNullException">212 /// If <paramref name="command"/> is null.213 /// </exception>214 /// <exception cref="ArgumentException">215 /// If <paramref name="command"/> contains a null Host or Context reference.216 /// </exception>217 internal CmdletProviderContext(218 Cmdlet command)219 {220 // verify the command parameter221 if (command == null)222 {223 throw PSTraceSource.NewArgumentNullException(nameof(command));224 }225 226 _command = command;227 Origin = command.CommandOrigin;228 229 if (command.Context == null)230 {231 throw PSTraceSource.NewArgumentException("command.Context");232 }233 234 ExecutionContext = command.Context;235 236 // Stream will default to true because command methods will be used.237 238 PassThru = true;239 _streamErrors = true;240 }241 242 /// <summary>243 /// Constructs the context under which the core command providers244 /// operate using an existing context.245 /// </summary>246 /// <param name="contextToCopyFrom">247 /// A CmdletProviderContext instance to copy the filters, ExecutionContext,248 /// Credentials, Drive, and Force options from.249 /// </param>250 /// <exception cref="ArgumentNullException">251 /// If <paramref name="contextToCopyFrom"/> is null.252 /// </exception>253 internal CmdletProviderContext(254 CmdletProviderContext contextToCopyFrom)255 {256 if (contextToCopyFrom == null)257 {258 throw PSTraceSource.NewArgumentNullException(nameof(contextToCopyFrom));259 }260 261 ExecutionContext = contextToCopyFrom.ExecutionContext;262 263 _command = contextToCopyFrom._command;264 265 if (contextToCopyFrom.Credential != null)266 {267 _credentials = contextToCopyFrom.Credential;268 }269 270 Drive = contextToCopyFrom.Drive;271 _force = contextToCopyFrom.Force;272 this.CopyFilters(contextToCopyFrom);273 SuppressWildcardExpansion = contextToCopyFrom.SuppressWildcardExpansion;274 DynamicParameters = contextToCopyFrom.DynamicParameters;275 Origin = contextToCopyFrom.Origin;276 277 // Copy the stopping state incase the source context278 // has already been signaled for stopping279 280 Stopping = contextToCopyFrom.Stopping;281 282 // add this context to the stop referral on the copied283 // context284 285 contextToCopyFrom.StopReferrals.Add(this);286 _copiedContext = contextToCopyFrom;287 }288 289 #endregion Constructor290 291 #region private properties292 293 /// <summary>294 /// If the constructor that takes a context to copy is295 /// called, this will be set to the context being copied.296 /// </summary>297 private readonly CmdletProviderContext _copiedContext;298 299 /// <summary>300 /// The credentials under which the operation should run.301 /// </summary>302 private readonly PSCredential _credentials = PSCredential.Empty;303 304 /// <summary>305 /// The force parameter gives guidance to providers on how vigorously they306 /// should try to perform an operation.307 /// </summary>308 private bool _force;309 310 /// <summary>311 /// The command which defines the context. This should not be312 /// made visible to anyone and should only be set through the313 /// constructor.314 /// </summary>315 private readonly Cmdlet _command;316 317 /// <summary>318 /// This makes the origin of the provider request visible to the internals.319 /// </summary>320 internal CommandOrigin Origin { get; } = CommandOrigin.Internal;321 322 /// <summary>323 /// This defines the default behavior for the WriteError method.324 /// If it is true, a call to this method will result in an immediate call325 /// to the command WriteError method, or to the writeErrorDelegate if326 /// one has been supplied.327 /// If it is false, the objects will be accumulated until the328 /// GetErrorObjects method is called.329 /// </summary>330 private readonly bool _streamErrors;331 332 /// <summary>333 /// A collection in which objects that are written using the WriteObject(s)334 /// methods are accumulated if <see cref="PassThru"/> is false.335 /// </summary>336 private Collection<PSObject> _accumulatedObjects = new Collection<PSObject>();337 338 /// <summary>339 /// A collection in which objects that are written using the WriteError340 /// method are accumulated if <see cref="PassThru"/> is false.341 /// </summary>342 private Collection<ErrorRecord> _accumulatedErrorObjects = new Collection<ErrorRecord>();343 344 /// <summary>345 /// The instance of the provider that is currently executing in this context.346 /// </summary>347 private System.Management.Automation.Provider.CmdletProvider _providerInstance;348 349 #endregion private properties350 351 #region Internal properties352 353 /// <summary>354 /// Gets the execution context of the engine.355 /// </summary>356 internal ExecutionContext ExecutionContext { get; }357 358 /// <summary>359 /// Gets or sets the provider instance for the current360 /// execution context.361 /// </summary>362 internal System.Management.Automation.Provider.CmdletProvider ProviderInstance363 {364 get365 {366 return _providerInstance;367 }368 369 set370 {371 _providerInstance = value;372 }373 }374 375 /// <summary>376 /// Copies the include, exclude, and provider filters from377 /// the specified context to this context.378 /// </summary>379 /// <param name="context">380 /// The context to copy the filters from.381 /// </param>382 private void CopyFilters(CmdletProviderContext context)383 {384 Dbg.Diagnostics.Assert(385 context != null,386 "The caller should have verified the context");387 388 Include = context.Include;389 Exclude = context.Exclude;390 Filter = context.Filter;391 }392 393 internal void RemoveStopReferral() => _copiedContext?.StopReferrals.Remove(this);394 395 #endregion Internal properties396 397 #region Public properties398 399 /// <summary>400 /// Gets or sets the dynamic parameters for the context.401 /// </summary>402 internal object DynamicParameters { get; set; }403 404 /// <summary>405 /// Returns MyInvocation from the underlying cmdlet.406 /// </summary>407 internal InvocationInfo MyInvocation408 {409 get410 {411 if (_command != null)412 {413 return _command.MyInvocation;414 }415 else416 {417 return null;418 }419 }420 }421 422 /// <summary>423 /// Determines if the Write* calls should be passed through to the command424 /// instance if there is one. The default value is true.425 /// </summary>426 internal bool PassThru { get; set; }427 428 /// <summary>429 /// The drive associated with this context.430 /// </summary>431 /// <exception cref="ArgumentNullException">432 /// If <paramref name="value"/> is null on set.433 /// </exception>434 internal PSDriveInfo Drive { get; set; }435 436 /// <summary>437 /// Gets the user name under which the operation should run.438 /// </summary>439 internal PSCredential Credential440 {441 get442 {443 PSCredential result = _credentials;444 445 // If the username wasn't specified, use the drive credentials446 447 if (_credentials == null && Drive != null)448 {449 result = Drive.Credential;450 }451 452 return result;453 }454 }455 456 #region Transaction Support457 458 /// <summary>459 /// Gets the flag that determines if the command requested a transaction.460 /// </summary>461 internal bool UseTransaction462 {463 get464 {465 if ((_command != null) && (_command.CommandRuntime != null))466 {467 MshCommandRuntime mshRuntime = _command.CommandRuntime as MshCommandRuntime;468 469 if (mshRuntime != null)470 {471 return mshRuntime.UseTransaction;472 }473 }474 475 return false;476 }477 }478 479 /// <summary>480 /// Returns true if a transaction is available and active.481 /// </summary>482 public bool TransactionAvailable()483 {484 if (_command != null)485 {486 return _command.TransactionAvailable();487 }488 489 return false;490 }491 492 /// <summary>493 /// Gets an object that surfaces the current PowerShell transaction.494 /// When this object is disposed, PowerShell resets the active transaction.495 /// </summary>496 public PSTransactionContext CurrentPSTransaction497 {498 get499 {500 if (_command != null)501 {502 return _command.CurrentPSTransaction;503 }504 505 return null;506 }507 }508 #endregion Transaction Support509 510 /// <summary>511 /// Gets or sets the Force property that is passed to providers.512 /// </summary>513 internal SwitchParameter Force514 {515 get { return _force; }516 517 set { _force = value; }518 }519 520 /// <summary>521 /// The provider specific filter that should be used when determining522 /// which items an action should take place on.523 /// </summary>524 internal string Filter { get; set; }525 526 /// <summary>527 /// A glob string that signifies which items should be included when determining528 /// which items the action should occur on.529 /// </summary>530 internal Collection<string> Include { get; private set; }531 532 /// <summary>533 /// A glob string that signifies which items should be excluded when determining534 /// which items the action should occur on.535 /// </summary>536 internal Collection<string> Exclude { get; private set; }537 538 /// <summary>539 /// Gets or sets the property that tells providers (that540 /// declare their own wildcard support) to suppress wildcard541 /// expansion. This is set when the user specifies the542 /// -LiteralPath parameter to one of the core commands.543 /// </summary>544 public bool SuppressWildcardExpansion { get; internal set; }545 546 #region User feedback mechanisms547 548 /// <summary>549 /// Confirm the operation with the user.550 /// </summary>551 /// <param name="target">552 /// Name of the target resource being acted upon553 /// </param>554 /// <remarks>true if-and-only-if the action should be performed</remarks>555 /// <exception cref="PipelineStoppedException">556 /// The ActionPreference.Stop or ActionPreference.Inquire policy557 /// triggered a terminating error. The pipeline failure will be558 /// ActionPreferenceStopException.559 /// Also, this occurs if the pipeline was already stopped.560 /// </exception>561 internal bool ShouldProcess(562 string target)563 {564 bool result = true;565 if (_command != null)566 {567 result = _command.ShouldProcess(target);568 }569 570 return result;571 }572 573 /// <summary>574 /// Confirm the operation with the user.575 /// </summary>576 /// <param name="target">577 /// Name of the target resource being acted upon578 /// </param>579 /// <param name="action">What action was being performed.</param>580 /// <remarks>true if-and-only-if the action should be performed</remarks>581 /// <exception cref="PipelineStoppedException">582 /// The ActionPreference.Stop or ActionPreference.Inquire policy583 /// triggered a terminating error. The pipeline failure will be584 /// ActionPreferenceStopException.585 /// Also, this occurs if the pipeline was already stopped.586 /// </exception>587 internal bool ShouldProcess(588 string target,589 string action)590 {591 bool result = true;592 if (_command != null)593 {594 result = _command.ShouldProcess(target, action);595 }596 597 return result;598 }599 600 /// <summary>601 /// Confirm the operation with the user.602 /// </summary>603 /// <param name="verboseDescription">604 /// This should contain a textual description of the action to be605 /// performed. This is what will be displayed to the user for606 /// ActionPreference.Continue.607 /// </param>608 /// <param name="verboseWarning">609 /// This should contain a textual query of whether the action610 /// should be performed, usually in the form of a question.611 /// This is what will be displayed to the user for612 /// ActionPreference.Inquire.613 /// </param>614 /// <param name="caption">615 /// This is the caption of the window which may be displayed616 /// if the user is prompted whether or not to perform the action.617 /// It may be displayed by some hosts, but not all.618 /// </param>619 /// <remarks>true if-and-only-if the action should be performed</remarks>620 /// <exception cref="PipelineStoppedException">621 /// The ActionPreference.Stop or ActionPreference.Inquire policy622 /// triggered a terminating error. The pipeline failure will be623 /// ActionPreferenceStopException.624 /// Also, this occurs if the pipeline was already stopped.625 /// </exception>626 internal bool ShouldProcess(627 string verboseDescription,628 string verboseWarning,629 string caption)630 {631 bool result = true;632 if (_command != null)633 {634 result = _command.ShouldProcess(635 verboseDescription,636 verboseWarning,637 caption);638 }639 640 return result;641 }642 643 /// <summary>644 /// Confirm the operation with the user.645 /// </summary>646 /// <param name="verboseDescription">647 /// This should contain a textual description of the action to be648 /// performed. This is what will be displayed to the user for649 /// ActionPreference.Continue.650 /// </param>651 /// <param name="verboseWarning">652 /// This should contain a textual query of whether the action653 /// should be performed, usually in the form of a question.654 /// This is what will be displayed to the user for655 /// ActionPreference.Inquire.656 /// </param>657 /// <param name="caption">658 /// This is the caption of the window which may be displayed659 /// if the user is prompted whether or not to perform the action.660 /// It may be displayed by some hosts, but not all.661 /// </param>662 /// <param name="shouldProcessReason">663 /// Indicates the reason(s) why ShouldProcess returned what it returned.664 /// Only the reasons enumerated in665 /// <see cref="System.Management.Automation.ShouldProcessReason"/>666 /// are returned.667 /// </param>668 /// <remarks>true if-and-only-if the action should be performed</remarks>669 /// <exception cref="PipelineStoppedException">670 /// The ActionPreference.Stop or ActionPreference.Inquire policy671 /// triggered a terminating error. The pipeline failure will be672 /// ActionPreferenceStopException.673 /// Also, this occurs if the pipeline was already stopped.674 /// </exception>675 internal bool ShouldProcess(676 string verboseDescription,677 string verboseWarning,678 string caption,679 out ShouldProcessReason shouldProcessReason)680 {681 bool result = true;682 if (_command != null)683 {684 result = _command.ShouldProcess(685 verboseDescription,686 verboseWarning,687 caption,688 out shouldProcessReason);689 }690 else691 {692 shouldProcessReason = ShouldProcessReason.None;693 }694 695 return result;696 }697 698 /// <summary>699 /// Ask the user whether to continue/stop or break to a subshell.700 /// </summary>701 /// <param name="query">702 /// Message to display to the user. This routine will append703 /// the text "Continue" to ensure that people know what question704 /// they are answering.705 /// </param>706 /// <param name="caption">707 /// Dialog caption if the host uses a dialog.708 /// </param>709 /// <returns>710 /// True if the user wants to continue, false if not.711 /// </returns>712 internal bool ShouldContinue(713 string query,714 string caption)715 {716 bool result = true;717 if (_command != null)718 {719 result = _command.ShouldContinue(query, caption);720 }721 722 return result;723 }724 725 /// <summary>726 /// Ask the user whether to continue/stop or break to a subshell.727 /// </summary>728 /// <param name="query">729 /// Message to display to the user. This routine will append730 /// the text "Continue" to ensure that people know what question731 /// they are answering.732 /// </param>733 /// <param name="caption">734 /// Dialog caption if the host uses a dialog.735 /// </param>736 /// <param name="yesToAll">737 /// Indicates whether the user selected YesToAll738 /// </param>739 /// <param name="noToAll">740 /// Indicates whether the user selected NoToAll741 /// </param>742 /// <returns>743 /// True if the user wants to continue, false if not.744 /// </returns>745 internal bool ShouldContinue(746 string query,747 string caption,748 ref bool yesToAll,749 ref bool noToAll)750 {751 bool result = true;752 if (_command != null)753 {754 result = _command.ShouldContinue(755 query, caption, ref yesToAll, ref noToAll);756 }757 else758 {759 yesToAll = false;760 noToAll = false;761 }762 763 return result;764 }765 766 /// <summary>767 /// Writes the object to the Verbose pipe.768 /// </summary>769 /// <param name="text">770 /// The string that needs to be written.771 /// </param>772 internal void WriteVerbose(string text) => _command?.WriteVerbose(text);773 774 /// <summary>775 /// Writes the object to the Warning pipe.776 /// </summary>777 /// <param name="text">778 /// The string that needs to be written.779 /// </param>780 internal void WriteWarning(string text) => _command?.WriteWarning(text);781 782 internal void WriteProgress(ProgressRecord record) => _command?.WriteProgress(record);783 784 /// <summary>785 /// Writes a debug string.786 /// </summary>787 /// <param name="text">788 /// The String that needs to be written.789 /// </param>790 internal void WriteDebug(string text) => _command?.WriteDebug(text);791 792 internal void WriteInformation(InformationRecord record) => _command?.WriteInformation(record);793 794 internal void WriteInformation(object messageData, string[] tags) => _command?.WriteInformation(messageData, tags);795 796 #endregion User feedback mechanisms797 798 #endregion Public properties799 800 #region Public methods801 802 /// <summary>803 /// Sets the filters that are used within this context.804 /// </summary>805 /// <param name="include">806 /// The include filters which determines which items are included in807 /// operations within this context.808 /// </param>809 /// <param name="exclude">810 /// The exclude filters which determines which items are excluded from811 /// operations within this context.812 /// </param>813 /// <param name="filter">814 /// The provider specific filter for the operation.815 /// </param>816 internal void SetFilters(Collection<string> include, Collection<string> exclude, string filter)817 {818 Include = include;819 Exclude = exclude;820 Filter = filter;821 }822 823 /// <summary>824 /// Gets an array of the objects that have been accumulated825 /// and the clears the collection.826 /// </summary>827 /// <returns>828 /// An object array of the objects that have been accumulated829 /// through the WriteObject method.830 /// </returns>831 internal Collection<PSObject> GetAccumulatedObjects()832 {833 // Get the contents as an array834 835 Collection<PSObject> results = _accumulatedObjects;836 _accumulatedObjects = new Collection<PSObject>();837 838 // Return the array839 840 return results;841 }842 843 /// <summary>844 /// Gets an array of the error objects that have been accumulated845 /// and the clears the collection.846 /// </summary>847 /// <returns>848 /// An object array of the objects that have been accumulated849 /// through the WriteError method.850 /// </returns>851 internal Collection<ErrorRecord> GetAccumulatedErrorObjects()852 {853 // Get the contents as an array854 855 Collection<ErrorRecord> results = _accumulatedErrorObjects;856 _accumulatedErrorObjects = new Collection<ErrorRecord>();857 858 // Return the array859 860 return results;861 }862 863 /// <summary>864 /// If there are any errors accumulated, the first error is thrown.865 /// </summary>866 /// <exception cref="ProviderInvocationException">867 /// If a CmdletProvider wrote any exceptions to the error pipeline, it is868 /// wrapped and then thrown.869 /// </exception>870 internal void ThrowFirstErrorOrDoNothing()871 {872 ThrowFirstErrorOrDoNothing(true);873 }874 875 /// <summary>876 /// If there are any errors accumulated, the first error is thrown.877 /// </summary>878 /// <param name="wrapExceptionInProviderException">879 /// If true, the error will be wrapped in a ProviderInvocationException before880 /// being thrown. If false, the error will be thrown as is.881 /// </param>882 /// <exception cref="ProviderInvocationException">883 /// If <paramref name="wrapExceptionInProviderException"/> is true, the884 /// first exception that was written to the error pipeline by a CmdletProvider885 /// is wrapped and thrown.886 /// </exception>887 /// <exception>888 /// If <paramref name="wrapExceptionInProviderException"/> is false,889 /// the first exception that was written to the error pipeline by a CmdletProvider890 /// is thrown.891 /// </exception>892 internal void ThrowFirstErrorOrDoNothing(bool wrapExceptionInProviderException)893 {894 if (HasErrors())895 {896 Collection<ErrorRecord> errors = GetAccumulatedErrorObjects();897 898 if (errors != null && errors.Count > 0)899 {900 // Throw the first exception901 902 if (wrapExceptionInProviderException)903 {904 ProviderInfo providerInfo = null;905 if (this.ProviderInstance != null)906 {907 providerInfo = this.ProviderInstance.ProviderInfo;908 }909 910 ProviderInvocationException e =911 new ProviderInvocationException(912 providerInfo,913 errors[0]);914 915 // Log a provider health event916 917 MshLog.LogProviderHealthEvent(918 this.ExecutionContext,919 providerInfo != null ? providerInfo.Name : "unknown provider",920 e,921 Severity.Warning);922 923 throw e;924 }925 else926 {927 throw errors[0].Exception;928 }929 }930 }931 }932 933 /// <summary>934 /// Writes all the accumulated errors to the specified context using WriteError.935 /// </summary>936 /// <param name="errorContext">937 /// The context to write the errors to.938 /// </param>939 /// <exception cref="ArgumentNullException">940 /// If <paramref name="errorContext"/> is null.941 /// </exception>942 internal void WriteErrorsToContext(CmdletProviderContext errorContext)943 {944 if (errorContext == null)945 {946 throw PSTraceSource.NewArgumentNullException(nameof(errorContext));947 }948 949 if (HasErrors())950 {951 foreach (ErrorRecord errorRecord in GetAccumulatedErrorObjects())952 {953 errorContext.WriteError(errorRecord);954 }955 }956 }957 958 /// <summary>959 /// Writes an object to the output.960 /// </summary>961 /// <param name="obj">962 /// The object to be written.963 /// </param>964 /// <remarks>965 /// If streaming is on and the writeObjectHandler was specified then the object966 /// gets written to the writeObjectHandler. If streaming is on and the writeObjectHandler967 /// was not specified and the command object was specified, the object gets written to968 /// the WriteObject method of the command object.969 /// If streaming is off the object gets written to an accumulator collection. The collection970 /// of written object can be retrieved using the AccumulatedObjects method.971 /// </remarks>972 /// <exception cref="InvalidOperationException">973 /// The CmdletProvider could not stream the results because no974 /// cmdlet was specified to stream the output through.975 /// </exception>976 /// <exception cref="PipelineStoppedException">977 /// If the pipeline has been signaled for stopping but978 /// the provider calls this method.979 /// </exception>980 internal void WriteObject(object obj)981 {982 // Making sure to obey the StopProcessing by983 // throwing an exception anytime a provider tries984 // to WriteObject985 986 if (Stopping)987 {988 PipelineStoppedException stopPipeline =989 new PipelineStoppedException();990 991 throw stopPipeline;992 }993 994 if (PassThru)995 {996 if (_command != null)997 {998 s_tracer.WriteLine("Writing to command pipeline");999 1000 // Since there was no writeObject handler use1001 // the command WriteObject method.1002 1003 _command.WriteObject(obj);1004 }1005 else1006 {1007 // The flag was set for streaming but we have no where1008 // to stream to.1009 1010 InvalidOperationException e =1011 PSTraceSource.NewInvalidOperationException(1012 SessionStateStrings.OutputStreamingNotEnabled);1013 throw e;1014 }1015 }1016 else1017 {1018 s_tracer.WriteLine("Writing to accumulated objects");1019 1020 // Convert the object to a PSObject if it's not already1021 // one.1022 1023 PSObject newObj = PSObject.AsPSObject(obj);1024 1025 // Since we are not streaming, just add the object to the accumulatedObjects1026 1027 _accumulatedObjects.Add(newObj);1028 }1029 }1030 1031 /// <summary>1032 /// Writes the error to the pipeline or accumulates the error in an internal1033 /// buffer.1034 /// </summary>1035 /// <param name="errorRecord">1036 /// The error record to write to the pipeline or the internal buffer.1037 /// </param>1038 /// <exception cref="InvalidOperationException">1039 /// The CmdletProvider could not stream the error because no1040 /// cmdlet was specified to stream the output through.1041 /// </exception>1042 /// <exception cref="PipelineStoppedException">1043 /// If the pipeline has been signaled for stopping but1044 /// the provider calls this method.1045 /// </exception>1046 internal void WriteError(ErrorRecord errorRecord)1047 {1048 // Making sure to obey the StopProcessing by1049 // throwing an exception anytime a provider tries1050 // to WriteError1051 1052 if (Stopping)1053 {1054 PipelineStoppedException stopPipeline =1055 new PipelineStoppedException();1056 1057 throw stopPipeline;1058 }1059 1060 if (_streamErrors)1061 {1062 if (_command != null)1063 {1064 s_tracer.WriteLine("Writing error package to command error pipe");1065 1066 _command.WriteError(errorRecord);1067 }1068 else1069 {1070 InvalidOperationException e =1071 PSTraceSource.NewInvalidOperationException(1072 SessionStateStrings.ErrorStreamingNotEnabled);1073 throw e;1074 }1075 }1076 else1077 {1078 // Since we are not streaming, just add the object to the accumulatedErrorObjects1079 _accumulatedErrorObjects.Add(errorRecord);1080 1081 if (errorRecord.ErrorDetails != null1082 && errorRecord.ErrorDetails.TextLookupError != null)1083 {1084 Exception textLookupError = errorRecord.ErrorDetails.TextLookupError;1085 errorRecord.ErrorDetails.TextLookupError = null;1086 MshLog.LogProviderHealthEvent(1087 this.ExecutionContext,1088 this.ProviderInstance.ProviderInfo.Name,1089 textLookupError,1090 Severity.Warning);1091 }1092 }1093 }1094 1095 /// <summary>1096 /// If the error pipeline hasn't been supplied a delegate or a command then this method1097 /// will determine if any errors have accumulated.1098 /// </summary>1099 /// <returns>1100 /// True if the errors are being accumulated and some errors have been accumulated. False otherwise.1101 /// </returns>1102 internal bool HasErrors()1103 {1104 return _accumulatedErrorObjects != null && _accumulatedErrorObjects.Count > 0;1105 }1106 1107 /// <summary>1108 /// Call this on a separate thread when a provider is using1109 /// this context to do work. This method will call the StopProcessing1110 /// method of the provider.1111 /// </summary>1112 internal void StopProcessing()1113 {1114 Stopping = true;1115 1116 // We don't need to catch any of the exceptions here because1117 // we are terminating the pipeline and any exception will1118 // be caught by the engine.1119 _providerInstance?.StopProcessing();1120 1121 // Call the stop referrals if any1122 1123 foreach (CmdletProviderContext referralContext in StopReferrals)1124 {1125 referralContext.StopProcessing();1126 }1127 }1128 1129 internal bool Stopping { get; private set; }1130 1131 /// <summary>1132 /// The list of contexts to which the StopProcessing calls1133 /// should be referred.1134 /// </summary>1135 internal Collection<CmdletProviderContext> StopReferrals { get; } = new Collection<CmdletProviderContext>();1136 1137 internal bool HasIncludeOrExclude1138 {1139 get1140 {1141 return ((Include != null && Include.Count > 0) ||1142 (Exclude != null && Exclude.Count > 0));1143 }1144 }1145 1146 #endregion Public methods1147 }1148}1149 