MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#pragma warning disable 1634, 16915 6using System.Collections;7using System.Diagnostics.CodeAnalysis;8using System.Collections.Generic;9using System.Globalization;10using System.Reflection;11using System.Resources;12using System.Management.Automation.Internal;13using System.Threading;14 15namespace System.Management.Automation16{17 /// <summary>18 /// Defines members and overrides used by Cmdlets.19 /// All Cmdlets must derive from <see cref="System.Management.Automation.Cmdlet"/>.20 /// </summary>21 /// <remarks>22 /// There are two ways to create a Cmdlet: by deriving from the Cmdlet base class, and by23 /// deriving from the PSCmdlet base class. The Cmdlet base class is the primary means by24 /// which users create their own Cmdlets. Extending this class provides support for the most25 /// common functionality, including object output and record processing.26 /// If your Cmdlet requires access to the PowerShell Runtime (for example, variables in the session state,27 /// access to the host, or information about the current Cmdlet Providers,) then you should instead28 /// derive from the PSCmdlet base class.29 /// In both cases, users should first develop and implement an object model to accomplish their30 /// task, extending the Cmdlet or PSCmdlet classes only as a thin management layer.31 /// </remarks>32 /// <seealso cref="System.Management.Automation.Internal.InternalCommand"/>33 public abstract class Cmdlet : InternalCommand34 {35 #region public_properties36 37 /// <summary>38 /// Lists the common parameters that are added by the PowerShell engine to any cmdlet that derives39 /// from PSCmdlet.40 /// </summary>41 public static HashSet<string> CommonParameters42 {43 get44 {45 return s_commonParameters.Value;46 }47 }48 49 private static readonly Lazy<HashSet<string>> s_commonParameters = new Lazy<HashSet<string>>(50 () =>51 {52 return new HashSet<string>(StringComparer.OrdinalIgnoreCase) {53 "Verbose", "Debug", "ErrorAction", "WarningAction", "InformationAction", "ProgressAction",54 "ErrorVariable", "WarningVariable", "OutVariable",55 "OutBuffer", "PipelineVariable", "InformationVariable" };56 }57 );58 59 /// <summary>60 /// Lists the common parameters that are added by the PowerShell engine when a cmdlet defines61 /// additional capabilities (SupportsShouldProcess, SupportsTransactions)62 /// </summary>63 public static HashSet<string> OptionalCommonParameters64 {65 get66 {67 return s_optionalCommonParameters.Value;68 }69 }70 71 private static readonly Lazy<HashSet<string>> s_optionalCommonParameters = new Lazy<HashSet<string>>(72 () =>73 {74 return new HashSet<string>(StringComparer.OrdinalIgnoreCase) {75 "WhatIf", "Confirm", "UseTransaction" };76 }77 );78 79 /// <summary>80 /// Is this command stopping?81 /// </summary>82 /// <remarks>83 /// If Stopping is true, many Cmdlet methods will throw84 /// <see cref="System.Management.Automation.PipelineStoppedException"/>.85 ///86 /// In general, if a Cmdlet's override implementation of ProcessRecord etc.87 /// throws <see cref="System.Management.Automation.PipelineStoppedException"/>, the best thing to do is to88 /// shut down the operation and return to the caller.89 /// It is acceptable to not catch <see cref="System.Management.Automation.PipelineStoppedException"/>90 /// and allow the exception to reach ProcessRecord.91 /// </remarks>92 public bool Stopping93 {94 get95 {96 using (PSTransactionManager.GetEngineProtectionScope())97 {98 return this.IsStopping;99 }100 }101 }102 103 /// <summary>104 /// Gets the CancellationToken that is signaled when the pipeline is stopping.105 /// </summary>106 public CancellationToken PipelineStopToken => StopToken;107 108 /// <summary>109 /// The name of the parameter set in effect.110 /// </summary>111 /// <value>the parameter set name</value>112 internal string _ParameterSetName113 {114 get { return _parameterSetName; }115 }116 117 /// <summary>118 /// Sets the parameter set.119 /// </summary>120 /// <param name="parameterSetName">121 /// The name of the valid parameter set.122 /// </param>123 internal void SetParameterSetName(string parameterSetName)124 {125 _parameterSetName = parameterSetName;126 }127 128 private string _parameterSetName = string.Empty;129 130 #region Override Internal131 132 /// <summary>133 /// When overridden in the derived class, performs initialization134 /// of command execution.135 /// Default implementation in the base class just returns.136 /// </summary>137 /// <exception cref="Exception">138 /// This method is overridden in the implementation of139 /// individual cmdlets, and can throw literally any exception.140 /// </exception>141 internal override void DoBeginProcessing()142 {143 MshCommandRuntime mshRuntime = this.CommandRuntime as MshCommandRuntime;144 145 if (mshRuntime != null)146 {147 if (mshRuntime.UseTransaction &&148 (!this.Context.TransactionManager.HasTransaction))149 {150 string error = TransactionStrings.NoTransactionStarted;151 152 if (this.Context.TransactionManager.IsLastTransactionCommitted)153 {154 error = TransactionStrings.NoTransactionStartedFromCommit;155 }156 else if (this.Context.TransactionManager.IsLastTransactionRolledBack)157 {158 error = TransactionStrings.NoTransactionStartedFromRollback;159 }160 161 throw new InvalidOperationException(error);162 }163 }164 165 this.BeginProcessing();166 }167 168 /// <summary>169 /// When overridden in the derived class, performs execution170 /// of the command.171 /// </summary>172 /// <exception cref="Exception">173 /// This method is overridden in the implementation of174 /// individual cmdlets, and can throw literally any exception.175 /// </exception>176 internal override void DoProcessRecord()177 {178 this.ProcessRecord();179 }180 181 /// <summary>182 /// When overridden in the derived class, performs clean-up183 /// after the command execution.184 /// Default implementation in the base class just returns.185 /// </summary>186 /// <exception cref="Exception">187 /// This method is overridden in the implementation of188 /// individual cmdlets, and can throw literally any exception.189 /// </exception>190 internal override void DoEndProcessing()191 {192 this.EndProcessing();193 }194 195 /// <summary>196 /// When overridden in the derived class, interrupts currently197 /// running code within the command. It should interrupt BeginProcessing,198 /// ProcessRecord, and EndProcessing.199 /// Default implementation in the base class just returns.200 /// </summary>201 /// <exception cref="Exception">202 /// This method is overridden in the implementation of203 /// individual cmdlets, and can throw literally any exception.204 /// </exception>205 internal override void DoStopProcessing()206 {207 this.StopProcessing();208 }209 210 #endregion Override Internal211 212 #endregion internal_members213 214 #region ctor215 216 /// <summary>217 /// Initializes the new instance of Cmdlet class.218 /// </summary>219 /// <remarks>220 /// Only subclasses of <see cref="System.Management.Automation.Cmdlet"/>221 /// can be created.222 /// </remarks>223 protected Cmdlet()224 {225 }226 227 #endregion ctor228 229 #region public_methods230 231 #region Cmdlet virtuals232 233 /// <summary>234 /// Gets the resource string corresponding to235 /// baseName and resourceId from the current assembly.236 /// You should override this if you require a different behavior.237 /// </summary>238 /// <param name="baseName">The base resource name.</param>239 /// <param name="resourceId">The resource id.</param>240 /// <returns>The resource string corresponding to baseName and resourceId.</returns>241 /// <exception cref="System.ArgumentException">242 /// Invalid <paramref name="baseName"/> or <paramref name="resourceId"/>, or243 /// string not found in resources244 /// </exception>245 /// <remarks>246 /// This behavior may be used when the Cmdlet specifies247 /// HelpMessageBaseName and HelpMessageResourceId when defining248 /// <see cref="System.Management.Automation.ParameterAttribute"/>,249 /// or when it uses the250 /// <see cref="System.Management.Automation.ErrorDetails"/>251 /// constructor variants which take baseName and resourceId.252 /// </remarks>253 /// <seealso cref="System.Management.Automation.ParameterAttribute"/>254 /// <seealso cref="System.Management.Automation.ErrorDetails"/>255 public virtual string GetResourceString(string baseName, string resourceId)256 {257 using (PSTransactionManager.GetEngineProtectionScope())258 {259 if (string.IsNullOrEmpty(baseName))260 throw PSTraceSource.NewArgumentNullException(nameof(baseName));261 262 if (string.IsNullOrEmpty(resourceId))263 throw PSTraceSource.NewArgumentNullException(nameof(resourceId));264 265 ResourceManager manager = ResourceManagerCache.GetResourceManager(this.GetType().Assembly, baseName);266 string retValue = null;267 268 try269 {270 retValue = manager.GetString(resourceId, CultureInfo.CurrentUICulture);271 }272 catch (MissingManifestResourceException)273 {274 throw PSTraceSource.NewArgumentException(nameof(baseName), GetErrorText.ResourceBaseNameFailure, baseName);275 }276 277 if (retValue == null)278 {279 throw PSTraceSource.NewArgumentException(nameof(resourceId), GetErrorText.ResourceIdFailure, resourceId);280 }281 282 return retValue;283 }284 }285 286 #endregion Cmdlet virtuals287 288 #region Write289 290 /// <summary>291 /// Holds the command runtime object for this command. This object controls292 /// what actually happens when a write is called.293 /// </summary>294 public ICommandRuntime CommandRuntime295 {296 get297 {298 using (PSTransactionManager.GetEngineProtectionScope())299 {300 return commandRuntime;301 }302 }303 304 set305 {306 using (PSTransactionManager.GetEngineProtectionScope())307 {308 commandRuntime = value;309 }310 }311 }312 313 /// <summary>314 /// Internal variant: Writes the specified error to the error pipe.315 /// </summary>316 /// <remarks>317 /// Do not call WriteError(e.ErrorRecord).318 /// The ErrorRecord contained in the ErrorRecord property of319 /// an exception which implements IContainsErrorRecord320 /// should not be passed directly to WriteError, since it contains321 /// a <see cref="System.Management.Automation.ParentContainsErrorRecordException"/>322 /// rather than the real exception.323 /// </remarks>324 /// <param name="errorRecord">Error.</param>325 /// <exception cref="System.InvalidOperationException">326 /// Not permitted at this time or from this thread327 /// </exception>328 /// <exception cref="System.Management.Automation.PipelineStoppedException">329 /// The pipeline has already been terminated, or was terminated330 /// during the execution of this method.331 /// The Cmdlet should generally just allow PipelineStoppedException332 /// to percolate up to the caller of ProcessRecord etc.333 /// </exception>334 /// <remarks>335 /// <see cref="System.Management.Automation.Cmdlet.ThrowTerminatingError"/>336 /// terminates the command, where337 /// <see cref="System.Management.Automation.ICommandRuntime.WriteError"/>338 /// allows the command to continue.339 ///340 /// If the pipeline is terminated due to ActionPreference.Stop341 /// or ActionPreference.Inquire, this method will throw342 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,343 /// but the command failure will ultimately be344 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,345 /// </remarks>346 public void WriteError(ErrorRecord errorRecord)347 {348 using (PSTransactionManager.GetEngineProtectionScope())349 {350 if (commandRuntime != null)351 commandRuntime.WriteError(errorRecord);352 else353 throw new System.NotImplementedException("WriteError");354 }355 }356 /// <summary>357 /// Writes the object to the output pipe.358 /// </summary>359 /// <param name="sendToPipeline">360 /// The object that needs to be written. This will be written as361 /// a single object, even if it is an enumeration.362 /// </param>363 /// <exception cref="System.Management.Automation.PipelineStoppedException">364 /// The pipeline has already been terminated, or was terminated365 /// during the execution of this method.366 /// The Cmdlet should generally just allow PipelineStoppedException367 /// to percolate up to the caller of ProcessRecord etc.368 /// </exception>369 /// <exception cref="System.InvalidOperationException">370 /// Not permitted at this time or from this thread.371 /// WriteObject may only be called during a call to this Cmdlet's372 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,373 /// and only from that thread.374 /// </exception>375 /// <seealso cref="System.Management.Automation.ICommandRuntime.WriteObject(object,bool)"/>376 /// <seealso cref="System.Management.Automation.ICommandRuntime.WriteError(ErrorRecord)"/>377 public void WriteObject(object sendToPipeline)378 {379 using (PSTransactionManager.GetEngineProtectionScope())380 {381 if (commandRuntime != null)382 commandRuntime.WriteObject(sendToPipeline);383 else384 throw new System.NotImplementedException("WriteObject");385 }386 }387 /// <summary>388 /// Writes one or more objects to the output pipe.389 /// If the object is a collection and the enumerateCollection flag390 /// is true, the objects in the collection391 /// will be written individually.392 /// </summary>393 /// <param name="sendToPipeline">394 /// The object that needs to be written to the pipeline.395 /// </param>396 /// <param name="enumerateCollection">397 /// true if the collection should be enumerated398 /// </param>399 /// <exception cref="System.Management.Automation.PipelineStoppedException">400 /// The pipeline has already been terminated, or was terminated401 /// during the execution of this method.402 /// The Cmdlet should generally just allow PipelineStoppedException403 /// to percolate up to the caller of ProcessRecord etc.404 /// </exception>405 /// <exception cref="System.InvalidOperationException">406 /// Not permitted at this time or from this thread.407 /// WriteObject may only be called during a call to this Cmdlet's408 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,409 /// and only from that thread.410 /// </exception>411 /// <seealso cref="System.Management.Automation.ICommandRuntime.WriteObject(object)"/>412 /// <seealso cref="System.Management.Automation.ICommandRuntime.WriteError(ErrorRecord)"/>413 public void WriteObject(object sendToPipeline, bool enumerateCollection)414 {415 using (PSTransactionManager.GetEngineProtectionScope())416 {417 if (commandRuntime != null)418 commandRuntime.WriteObject(sendToPipeline, enumerateCollection);419 else420 throw new System.NotImplementedException("WriteObject");421 }422 }423 424 /// <summary>425 /// Display verbose information.426 /// </summary>427 /// <param name="text">Verbose output.</param>428 /// <exception cref="System.Management.Automation.PipelineStoppedException">429 /// The pipeline has already been terminated, or was terminated430 /// during the execution of this method.431 /// The Cmdlet should generally just allow PipelineStoppedException432 /// to percolate up to the caller of ProcessRecord etc.433 /// </exception>434 /// <exception cref="System.InvalidOperationException">435 /// Not permitted at this time or from this thread.436 /// WriteVerbose may only be called during a call to this Cmdlets's437 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,438 /// and only from that thread.439 /// </exception>440 /// <remarks>441 /// Use WriteVerbose to display more detailed information about442 /// the activity of your Cmdlet. By default, verbose output will443 /// not be displayed, although this can be configured with the444 /// VerbosePreference shell variable445 /// or the -Verbose and -Debug command-line options.446 /// </remarks>447 /// <seealso cref="System.Management.Automation.Cmdlet.WriteDebug(string)"/>448 /// <seealso cref="System.Management.Automation.Cmdlet.WriteWarning(string)"/>449 /// <seealso cref="System.Management.Automation.Cmdlet.WriteProgress(ProgressRecord)"/>450 public void WriteVerbose(string text)451 {452 using (PSTransactionManager.GetEngineProtectionScope())453 {454 if (commandRuntime != null)455 commandRuntime.WriteVerbose(text);456 else457 throw new System.NotImplementedException("WriteVerbose");458 }459 }460 461 internal bool IsWriteVerboseEnabled()462 => commandRuntime is not MshCommandRuntime mshRuntime || mshRuntime.IsWriteVerboseEnabled();463 464 /// <summary>465 /// Display warning information.466 /// </summary>467 /// <param name="text">Warning output.</param>468 /// <exception cref="System.Management.Automation.PipelineStoppedException">469 /// The pipeline has already been terminated, or was terminated470 /// during the execution of this method.471 /// The Cmdlet should generally just allow PipelineStoppedException472 /// to percolate up to the caller of ProcessRecord etc.473 /// </exception>474 /// <exception cref="System.InvalidOperationException">475 /// Not permitted at this time or from this thread.476 /// WriteWarning may only be called during a call to this Cmdlet's477 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,478 /// and only from that thread.479 /// </exception>480 /// <remarks>481 /// Use WriteWarning to display warnings about482 /// the activity of your Cmdlet. By default, warning output will483 /// be displayed, although this can be configured with the484 /// WarningPreference shell variable485 /// or the -Verbose and -Debug command-line options.486 /// </remarks>487 /// <seealso cref="System.Management.Automation.Cmdlet.WriteDebug(string)"/>488 /// <seealso cref="System.Management.Automation.Cmdlet.WriteVerbose(string)"/>489 /// <seealso cref="System.Management.Automation.Cmdlet.WriteProgress(ProgressRecord)"/>490 public void WriteWarning(string text)491 {492 using (PSTransactionManager.GetEngineProtectionScope())493 {494 if (commandRuntime != null)495 commandRuntime.WriteWarning(text);496 else497 throw new System.NotImplementedException("WriteWarning");498 }499 }500 501 internal bool IsWriteWarningEnabled()502 => commandRuntime is not MshCommandRuntime mshRuntime || mshRuntime.IsWriteWarningEnabled();503 504 /// <summary>505 /// Write text into pipeline execution log.506 /// </summary>507 /// <param name="text">Text to be written to log.</param>508 /// <exception cref="System.Management.Automation.PipelineStoppedException">509 /// The pipeline has already been terminated, or was terminated510 /// during the execution of this method.511 /// The Cmdlet should generally just allow PipelineStoppedException512 /// to percolate up to the caller of ProcessRecord etc.513 /// </exception>514 /// <exception cref="System.InvalidOperationException">515 /// Not permitted at this time or from this thread.516 /// WriteWarning may only be called during a call to this Cmdlet's517 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,518 /// and only from that thread.519 /// </exception>520 /// <remarks>521 /// Use WriteCommandDetail to write important information about cmdlet execution to522 /// pipeline execution log.523 ///524 /// If LogPipelineExecutionDetail is turned on, this information will be written525 /// to PowerShell log under log category "Pipeline execution detail"526 /// </remarks>527 /// <seealso cref="System.Management.Automation.Cmdlet.WriteDebug(string)"/>528 /// <seealso cref="System.Management.Automation.Cmdlet.WriteVerbose(string)"/>529 /// <seealso cref="System.Management.Automation.Cmdlet.WriteProgress(ProgressRecord)"/>530 public void WriteCommandDetail(string text)531 {532 using (PSTransactionManager.GetEngineProtectionScope())533 {534 if (commandRuntime != null)535 commandRuntime.WriteCommandDetail(text);536 else537 throw new System.NotImplementedException("WriteCommandDetail");538 }539 }540 541 /// <summary>542 /// Display progress information.543 /// </summary>544 /// <param name="progressRecord">Progress information.</param>545 /// <exception cref="System.Management.Automation.PipelineStoppedException">546 /// The pipeline has already been terminated, or was terminated547 /// during the execution of this method.548 /// The Cmdlet should generally just allow PipelineStoppedException549 /// to percolate up to the caller of ProcessRecord etc.550 /// </exception>551 /// <exception cref="System.InvalidOperationException">552 /// Not permitted at this time or from this thread.553 /// WriteProgress may only be called during a call to this Cmdlet's554 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,555 /// and only from that thread.556 /// </exception>557 /// <remarks>558 /// Use WriteProgress to display progress information about559 /// the activity of your Cmdlet, when the operation of your Cmdlet560 /// could potentially take a long time.561 ///562 /// By default, progress output will563 /// be displayed, although this can be configured with the564 /// ProgressPreference shell variable.565 /// </remarks>566 /// <seealso cref="System.Management.Automation.Cmdlet.WriteDebug(string)"/>567 /// <seealso cref="System.Management.Automation.Cmdlet.WriteWarning(string)"/>568 /// <seealso cref="System.Management.Automation.Cmdlet.WriteVerbose(string)"/>569 public void WriteProgress(ProgressRecord progressRecord)570 {571 using (PSTransactionManager.GetEngineProtectionScope())572 {573 if (commandRuntime != null)574 commandRuntime.WriteProgress(progressRecord);575 else576 throw new System.NotImplementedException("WriteProgress");577 }578 }579 580 /// <summary>581 /// Displays progress output if enabled.582 /// </summary>583 /// <param name="sourceId">584 /// Identifies which command is reporting progress585 /// </param>586 /// <param name="progressRecord">587 /// Progress status to be displayed588 /// </param>589 /// <exception cref="System.Management.Automation.PipelineStoppedException">590 /// The pipeline has already been terminated, or was terminated591 /// during the execution of this method.592 /// The Cmdlet should generally just allow PipelineStoppedException593 /// to percolate up to the caller of ProcessRecord etc.594 /// </exception>595 /// <remarks>596 /// If the pipeline is terminated due to ActionPreference.Stop597 /// or ActionPreference.Inquire, this method will throw598 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,599 /// but the command failure will ultimately be600 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,601 /// </remarks>602 internal void WriteProgress(603 Int64 sourceId,604 ProgressRecord progressRecord)605 {606 if (commandRuntime != null)607 commandRuntime.WriteProgress(sourceId, progressRecord);608 else609 throw new System.NotImplementedException("WriteProgress");610 }611 612 internal bool IsWriteProgressEnabled()613 => commandRuntime is not MshCommandRuntime mshRuntime || mshRuntime.IsWriteProgressEnabled();614 615 /// <summary>616 /// Display debug information.617 /// </summary>618 /// <param name="text">Debug output.</param>619 /// <exception cref="System.Management.Automation.PipelineStoppedException">620 /// The pipeline has already been terminated, or was terminated621 /// during the execution of this method.622 /// The Cmdlet should generally just allow PipelineStoppedException623 /// to percolate up to the caller of ProcessRecord etc.624 /// </exception>625 /// <exception cref="System.InvalidOperationException">626 /// Not permitted at this time or from this thread.627 /// WriteDebug may only be called during a call to this Cmdlet's628 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,629 /// and only from that thread.630 /// </exception>631 /// <remarks>632 /// Use WriteDebug to display debug information on the inner workings633 /// of your Cmdlet. By default, debug output will634 /// not be displayed, although this can be configured with the635 /// DebugPreference shell variable or the -Debug command-line option.636 /// </remarks>637 /// <remarks>638 /// If the pipeline is terminated due to ActionPreference.Stop639 /// or ActionPreference.Inquire, this method will throw640 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,641 /// but the command failure will ultimately be642 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,643 /// </remarks>644 /// <seealso cref="System.Management.Automation.Cmdlet.WriteVerbose(string)"/>645 /// <seealso cref="System.Management.Automation.Cmdlet.WriteWarning(string)"/>646 /// <seealso cref="System.Management.Automation.Cmdlet.WriteProgress(ProgressRecord)"/>647 public void WriteDebug(string text)648 {649 using (PSTransactionManager.GetEngineProtectionScope())650 {651 if (commandRuntime != null)652 commandRuntime.WriteDebug(text);653 else654 throw new System.NotImplementedException("WriteDebug");655 }656 }657 658 internal bool IsWriteDebugEnabled()659 => commandRuntime is not MshCommandRuntime mshRuntime || mshRuntime.IsWriteDebugEnabled();660 661 /// <summary>662 /// Route information to the user or host.663 /// </summary>664 /// <param name="messageData">The object / message data to transmit to the hosting application.</param>665 /// <param name="tags">666 /// Any tags to be associated with the message data. These can later be used to filter667 /// or separate objects being sent to the host.668 /// </param>669 /// <exception cref="System.Management.Automation.PipelineStoppedException">670 /// The pipeline has already been terminated, or was terminated671 /// during the execution of this method.672 /// The Cmdlet should generally just allow PipelineStoppedException673 /// to percolate up to the caller of ProcessRecord etc.674 /// </exception>675 /// <exception cref="System.InvalidOperationException">676 /// Not permitted at this time or from this thread.677 /// WriteInformation may only be called during a call to this Cmdlet's678 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,679 /// and only from that thread.680 /// </exception>681 /// <remarks>682 /// Use WriteInformation to transmit information to the user about the activity683 /// of your Cmdlet. By default, informational output will684 /// be displayed, although this can be configured with the685 /// InformationPreference shell variable or the -InformationPreference command-line option.686 /// </remarks>687 /// <remarks>688 /// If the pipeline is terminated due to ActionPreference.Stop689 /// or ActionPreference.Inquire, this method will throw690 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,691 /// but the command failure will ultimately be692 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,693 /// </remarks>694 public void WriteInformation(object messageData, string[] tags)695 {696 using (PSTransactionManager.GetEngineProtectionScope())697 {698 ICommandRuntime2 commandRuntime2 = commandRuntime as ICommandRuntime2;699 if (commandRuntime2 != null)700 {701 string source = this.MyInvocation.PSCommandPath;702 if (string.IsNullOrEmpty(source))703 {704 source = this.MyInvocation.MyCommand.Name;705 }706 707 InformationRecord informationRecord = new InformationRecord(messageData, source);708 709 if (tags != null)710 {711 informationRecord.Tags.AddRange(tags);712 }713 714 commandRuntime2.WriteInformation(informationRecord);715 }716 else717 {718 throw new System.NotImplementedException("WriteInformation");719 }720 }721 }722 723 /// <summary>724 /// Route information to the user or host.725 /// </summary>726 /// <param name="informationRecord">The information record to write.</param>727 /// <exception cref="System.Management.Automation.PipelineStoppedException">728 /// The pipeline has already been terminated, or was terminated729 /// during the execution of this method.730 /// The Cmdlet should generally just allow PipelineStoppedException731 /// to percolate up to the caller of ProcessRecord etc.732 /// </exception>733 /// <exception cref="System.InvalidOperationException">734 /// Not permitted at this time or from this thread.735 /// WriteInformation may only be called during a call to this Cmdlet's736 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,737 /// and only from that thread.738 /// </exception>739 /// <remarks>740 /// Use WriteInformation to transmit information to the user about the activity741 /// of your Cmdlet. By default, informational output will742 /// be displayed, although this can be configured with the743 /// InformationPreference shell variable or the -InformationPreference command-line option.744 /// </remarks>745 /// <remarks>746 /// If the pipeline is terminated due to ActionPreference.Stop747 /// or ActionPreference.Inquire, this method will throw748 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,749 /// but the command failure will ultimately be750 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,751 /// </remarks>752 public void WriteInformation(InformationRecord informationRecord)753 {754 using (PSTransactionManager.GetEngineProtectionScope())755 {756 ICommandRuntime2 commandRuntime2 = commandRuntime as ICommandRuntime2;757 if (commandRuntime2 != null)758 {759 commandRuntime2.WriteInformation(informationRecord);760 }761 else762 {763 throw new System.NotImplementedException("WriteInformation");764 }765 }766 }767 768 internal bool IsWriteInformationEnabled()769 => commandRuntime is not MshCommandRuntime mshRuntime || mshRuntime.IsWriteInformationEnabled();770 771 #endregion Write772 773 #region ShouldProcess774 /// <summary>775 /// Confirm the operation with the user. Cmdlets which make changes776 /// (e.g. delete files, stop services etc.) should call ShouldProcess777 /// to give the user the opportunity to confirm that the operation778 /// should actually be performed.779 /// </summary>780 /// <param name="target">781 /// Name of the target resource being acted upon. This will782 /// potentially be displayed to the user.783 /// </param>784 /// <exception cref="System.Management.Automation.PipelineStoppedException">785 /// The pipeline has already been terminated, or was terminated786 /// during the execution of this method.787 /// The Cmdlet should generally just allow PipelineStoppedException788 /// to percolate up to the caller of ProcessRecord etc.789 /// </exception>790 /// <exception cref="System.InvalidOperationException">791 /// Not permitted at this time or from this thread.792 /// ShouldProcess may only be called during a call to this Cmdlet's793 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,794 /// and only from that thread.795 /// </exception>796 /// <returns>797 /// If ShouldProcess returns true, the operation should be performed.798 /// If ShouldProcess returns false, the operation should not be799 /// performed, and the Cmdlet should move on to the next target resource.800 /// </returns>801 /// <remarks>802 /// A Cmdlet should declare803 /// [Cmdlet( SupportsShouldProcess = true )]804 /// if-and-only-if it calls ShouldProcess before making changes.805 ///806 /// ShouldProcess may only be called during a call to this Cmdlet's807 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,808 /// and only from that thread.809 ///810 /// ShouldProcess will take into account command-line settings811 /// and preference variables in determining what it should return812 /// and whether it should prompt the user.813 /// </remarks>814 /// <remarks>815 /// If the pipeline is terminated due to ActionPreference.Stop816 /// or ActionPreference.Inquire,817 /// <see cref="System.Management.Automation.Cmdlet.ShouldProcess(string)"/>818 /// will throw819 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,820 /// but the command failure will ultimately be821 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,822 /// </remarks>823 /// <example>824 /// <code>825 /// namespace Microsoft.Samples.Cmdlet826 /// {827 /// [Cmdlet(VerbsCommon.Remove,"myobjecttype1")]828 /// public class RemoveMyObjectType1 : Cmdlet829 /// {830 /// [Parameter( Mandatory = true )]831 /// public string Filename832 /// {833 /// get { return filename; }834 /// set { filename = value; }835 /// }836 /// private string filename;837 ///838 /// public override void ProcessRecord()839 /// {840 /// if (ShouldProcess(filename))841 /// {842 /// // delete the object843 /// }844 /// }845 /// }846 /// }847 /// </code>848 /// </example>849 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string)"/>850 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string,string)"/>851 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string,string,out ShouldProcessReason)"/>852 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string)"/>853 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string,ref bool,ref bool)"/>854 public bool ShouldProcess(string target)855 {856 using (PSTransactionManager.GetEngineProtectionScope())857 {858 if (commandRuntime != null)859 return commandRuntime.ShouldProcess(target);860 else861 return true;862 }863 }864 865 /// <summary>866 /// Confirm the operation with the user. Cmdlets which make changes867 /// (e.g. delete files, stop services etc.) should call ShouldProcess868 /// to give the user the opportunity to confirm that the operation869 /// should actually be performed.870 ///871 /// This variant allows the caller to specify text for both the872 /// target resource and the action.873 /// </summary>874 /// <param name="target">875 /// Name of the target resource being acted upon. This will876 /// potentially be displayed to the user.877 /// </param>878 /// <param name="action">879 /// Name of the action which is being performed. This will880 /// potentially be displayed to the user. (default is Cmdlet name)881 /// </param>882 /// <exception cref="System.Management.Automation.PipelineStoppedException">883 /// The pipeline has already been terminated, or was terminated884 /// during the execution of this method.885 /// The Cmdlet should generally just allow PipelineStoppedException886 /// to percolate up to the caller of ProcessRecord etc.887 /// </exception>888 /// <exception cref="System.InvalidOperationException">889 /// Not permitted at this time or from this thread.890 /// ShouldProcess may only be called during a call to this Cmdlet's891 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,892 /// and only from that thread.893 /// </exception>894 /// <returns>895 /// If ShouldProcess returns true, the operation should be performed.896 /// If ShouldProcess returns false, the operation should not be897 /// performed, and the Cmdlet should move on to the next target resource.898 /// </returns>899 /// <remarks>900 /// A Cmdlet should declare901 /// [Cmdlet( SupportsShouldProcess = true )]902 /// if-and-only-if it calls ShouldProcess before making changes.903 ///904 /// ShouldProcess may only be called during a call to this Cmdlet's905 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,906 /// and only from that thread.907 ///908 /// ShouldProcess will take into account command-line settings909 /// and preference variables in determining what it should return910 /// and whether it should prompt the user.911 /// </remarks>912 /// <remarks>913 /// If the pipeline is terminated due to ActionPreference.Stop914 /// or ActionPreference.Inquire, this method will throw915 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,916 /// but the command failure will ultimately be917 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,918 /// </remarks>919 /// <example>920 /// <code>921 /// namespace Microsoft.Samples.Cmdlet922 /// {923 /// [Cmdlet(VerbsCommon.Remove,"myobjecttype2")]924 /// public class RemoveMyObjectType2 : Cmdlet925 /// {926 /// [Parameter( Mandatory = true )]927 /// public string Filename928 /// {929 /// get { return filename; }930 /// set { filename = value; }931 /// }932 /// private string filename;933 ///934 /// public override void ProcessRecord()935 /// {936 /// if (ShouldProcess(filename, "delete"))937 /// {938 /// // delete the object939 /// }940 /// }941 /// }942 /// }943 /// </code>944 /// </example>945 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string)"/>946 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string,string)"/>947 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string,string,out ShouldProcessReason)"/>948 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string)"/>949 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string,ref bool,ref bool)"/>950 public bool ShouldProcess(string target, string action)951 {952 using (PSTransactionManager.GetEngineProtectionScope())953 {954 if (commandRuntime != null)955 return commandRuntime.ShouldProcess(target, action);956 else957 return true;958 }959 }960 961 /// <summary>962 /// Confirm the operation with the user. Cmdlets which make changes963 /// (e.g. delete files, stop services etc.) should call ShouldProcess964 /// to give the user the opportunity to confirm that the operation965 /// should actually be performed.966 ///967 /// This variant allows the caller to specify the complete text968 /// describing the operation, rather than just the name and action.969 /// </summary>970 /// <param name="verboseDescription">971 /// Textual description of the action to be performed.972 /// This is what will be displayed to the user for973 /// ActionPreference.Continue.974 /// </param>975 /// <param name="verboseWarning">976 /// Textual query of whether the action should be performed,977 /// usually in the form of a question.978 /// This is what will be displayed to the user for979 /// ActionPreference.Inquire.980 /// </param>981 /// <param name="caption">982 /// Caption of the window which may be displayed983 /// if the user is prompted whether or not to perform the action.984 /// <paramref name="caption"/> may be displayed by some hosts, but not all.985 /// </param>986 /// <exception cref="System.Management.Automation.PipelineStoppedException">987 /// The pipeline has already been terminated, or was terminated988 /// during the execution of this method.989 /// The Cmdlet should generally just allow PipelineStoppedException990 /// to percolate up to the caller of ProcessRecord etc.991 /// </exception>992 /// <exception cref="System.InvalidOperationException">993 /// Not permitted at this time or from this thread.994 /// ShouldProcess may only be called during a call to this Cmdlet's995 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,996 /// and only from that thread.997 /// </exception>998 /// <returns>999 /// If ShouldProcess returns true, the operation should be performed.1000 /// If ShouldProcess returns false, the operation should not be1001 /// performed, and the Cmdlet should move on to the next target resource.1002 /// </returns>1003 /// <remarks>1004 /// A Cmdlet should declare1005 /// [Cmdlet( SupportsShouldProcess = true )]1006 /// if-and-only-if it calls ShouldProcess before making changes.1007 ///1008 /// ShouldProcess may only be called during a call to this Cmdlet's1009 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,1010 /// and only from that thread.1011 ///1012 /// ShouldProcess will take into account command-line settings1013 /// and preference variables in determining what it should return1014 /// and whether it should prompt the user.1015 /// </remarks>1016 /// <remarks>1017 /// If the pipeline is terminated due to ActionPreference.Stop1018 /// or ActionPreference.Inquire, this method will throw1019 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,1020 /// but the command failure will ultimately be1021 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,1022 /// </remarks>1023 /// <example>1024 /// <code>1025 /// namespace Microsoft.Samples.Cmdlet1026 /// {1027 /// [Cmdlet(VerbsCommon.Remove,"myobjecttype3")]1028 /// public class RemoveMyObjectType3 : Cmdlet1029 /// {1030 /// [Parameter( Mandatory = true )]1031 /// public string Filename1032 /// {1033 /// get { return filename; }1034 /// set { filename = value; }1035 /// }1036 /// private string filename;1037 ///1038 /// public override void ProcessRecord()1039 /// {1040 /// if (ShouldProcess(1041 /// string.Format($"Deleting file {filename}"),1042 /// string.Format($"Are you sure you want to delete file {filename}?"),1043 /// "Delete file"))1044 /// {1045 /// // delete the object1046 /// }1047 /// }1048 /// }1049 /// }1050 /// </code>1051 /// </example>1052 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string)"/>1053 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string)"/>1054 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string,string,out ShouldProcessReason)"/>1055 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string)"/>1056 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string,ref bool,ref bool)"/>1057 public bool ShouldProcess(1058 string verboseDescription,1059 string verboseWarning,1060 string caption)1061 {1062 using (PSTransactionManager.GetEngineProtectionScope())1063 {1064 if (commandRuntime != null)1065 return commandRuntime.ShouldProcess(verboseDescription, verboseWarning, caption);1066 else1067 return true;1068 }1069 }1070 1071 /// <summary>1072 /// Confirm the operation with the user. Cmdlets which make changes1073 /// (e.g. delete files, stop services etc.) should call ShouldProcess1074 /// to give the user the opportunity to confirm that the operation1075 /// should actually be performed.1076 ///1077 /// This variant allows the caller to specify the complete text1078 /// describing the operation, rather than just the name and action.1079 /// </summary>1080 /// <param name="verboseDescription">1081 /// Textual description of the action to be performed.1082 /// This is what will be displayed to the user for1083 /// ActionPreference.Continue.1084 /// </param>1085 /// <param name="verboseWarning">1086 /// Textual query of whether the action should be performed,1087 /// usually in the form of a question.1088 /// This is what will be displayed to the user for1089 /// ActionPreference.Inquire.1090 /// </param>1091 /// <param name="caption">1092 /// Caption of the window which may be displayed1093 /// if the user is prompted whether or not to perform the action.1094 /// <paramref name="caption"/> may be displayed by some hosts, but not all.1095 /// </param>1096 /// <param name="shouldProcessReason">1097 /// Indicates the reason(s) why ShouldProcess returned what it returned.1098 /// Only the reasons enumerated in1099 /// <see cref="System.Management.Automation.ShouldProcessReason"/>1100 /// are returned.1101 /// </param>1102 /// <exception cref="System.Management.Automation.PipelineStoppedException">1103 /// The pipeline has already been terminated, or was terminated1104 /// during the execution of this method.1105 /// The Cmdlet should generally just allow PipelineStoppedException1106 /// to percolate up to the caller of ProcessRecord etc.1107 /// </exception>1108 /// <exception cref="System.InvalidOperationException">1109 /// Not permitted at this time or from this thread.1110 /// ShouldProcess may only be called during a call to this Cmdlet's1111 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,1112 /// and only from that thread.1113 /// </exception>1114 /// <returns>1115 /// If ShouldProcess returns true, the operation should be performed.1116 /// If ShouldProcess returns false, the operation should not be1117 /// performed, and the Cmdlet should move on to the next target resource.1118 /// </returns>1119 /// <remarks>1120 /// A Cmdlet should declare1121 /// [Cmdlet( SupportsShouldProcess = true )]1122 /// if-and-only-if it calls ShouldProcess before making changes.1123 ///1124 /// ShouldProcess may only be called during a call to this Cmdlet's1125 /// implementation of ProcessRecord, BeginProcessing or EndProcessing,1126 /// and only from that thread.1127 ///1128 /// ShouldProcess will take into account command-line settings1129 /// and preference variables in determining what it should return1130 /// and whether it should prompt the user.1131 /// </remarks>1132 /// <remarks>1133 /// If the pipeline is terminated due to ActionPreference.Stop1134 /// or ActionPreference.Inquire, this method will throw1135 /// <see cref="System.Management.Automation.PipelineStoppedException"/>,1136 /// but the command failure will ultimately be1137 /// <see cref="System.Management.Automation.ActionPreferenceStopException"/>,1138 /// </remarks>1139 /// <example>1140 /// <code>1141 /// namespace Microsoft.Samples.Cmdlet1142 /// {1143 /// [Cmdlet(VerbsCommon.Remove,"myobjecttype3")]1144 /// public class RemoveMyObjectType3 : Cmdlet1145 /// {1146 /// [Parameter( Mandatory = true )]1147 /// public string Filename1148 /// {1149 /// get { return filename; }1150 /// set { filename = value; }1151 /// }1152 /// private string filename;1153 ///1154 /// public override void ProcessRecord()1155 /// {1156 /// ShouldProcessReason shouldProcessReason;1157 /// if (ShouldProcess(1158 /// string.Format($"Deleting file {filename}"),1159 /// string.Format($"Are you sure you want to delete file {filename}?"),1160 /// "Delete file",1161 /// out shouldProcessReason))1162 /// {1163 /// // delete the object1164 /// }1165 /// }1166 /// }1167 /// }1168 /// </code>1169 /// </example>1170 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string)"/>1171 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string)"/>1172 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldProcess(string,string,string)"/>1173 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string)"/>1174 /// <seealso cref="System.Management.Automation.Cmdlet.ShouldContinue(string,string,ref bool,ref bool)"/>1175 public bool ShouldProcess(1176 string verboseDescription,1177 string verboseWarning,1178 string caption,1179 out ShouldProcessReason shouldProcessReason)1180 {1181 using (PSTransactionManager.GetEngineProtectionScope())1182 {1183 if (commandRuntime != null)1184 return commandRuntime.ShouldProcess(verboseDescription, verboseWarning, caption, out shouldProcessReason);1185 else1186 {1187 shouldProcessReason = ShouldProcessReason.None;1188 return true;1189 }1190 }1191 }1192 1193 #endregion ShouldProcess1194 1195 #region ShouldContinue1196 /// <summary>1197 /// Confirm an operation or grouping of operations with the user.1198 /// This differs from ShouldProcess in that it is not affected by1199 /// preference settings or command-line parameters,1200 /// it always does the query.