// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma warning disable 1634, 1691
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Management.Automation.Internal;
using Dbg = System.Management.Automation.Diagnostics;
namespace System.Management.Automation
{
///
/// Defines members and overrides used by Cmdlets.
/// All Cmdlets must derive from .
///
///
/// There are two ways to create a Cmdlet: by deriving from the Cmdlet base class, and by
/// deriving from the PSCmdlet base class. The Cmdlet base class is the primary means by
/// which users create their own Cmdlets. Extending this class provides support for the most
/// common functionality, including object output and record processing.
/// If your Cmdlet requires access to the PowerShell Runtime (for example, variables in the session state,
/// access to the host, or information about the current Cmdlet Providers,) then you should instead
/// derive from the PSCmdlet base class.
/// In both cases, users should first develop and implement an object model to accomplish their
/// task, extending the Cmdlet or PSCmdlet classes only as a thin management layer.
///
///
public abstract class Cmdlet : InternalCommand
{
#region public_properties
///
/// Lists the common parameters that are added by the PowerShell engine to any cmdlet that derives
/// from PSCmdlet.
///
public static HashSet CommonParameters
{
get
{
return s_commonParameters.Value;
}
}
private static readonly Lazy> s_commonParameters = new Lazy>(
() =>
{
return new HashSet(StringComparer.OrdinalIgnoreCase) {
"Verbose", "Debug", "ErrorAction", "WarningAction", "InformationAction", "ProgressAction",
"ErrorVariable", "WarningVariable", "OutVariable",
"OutBuffer", "PipelineVariable", "InformationVariable" };
}
);
///
/// Lists the common parameters that are added by the PowerShell engine when a cmdlet defines
/// additional capabilities (SupportsShouldProcess, SupportsTransactions)
///
public static HashSet OptionalCommonParameters
{
get
{
return s_optionalCommonParameters.Value;
}
}
private static readonly Lazy> s_optionalCommonParameters = new Lazy>(
() =>
{
return new HashSet(StringComparer.OrdinalIgnoreCase) {
"WhatIf", "Confirm", "UseTransaction" };
}
);
///
/// Is this command stopping?
///
///
/// If Stopping is true, many Cmdlet methods will throw
/// .
///
/// In general, if a Cmdlet's override implementation of ProcessRecord etc.
/// throws , the best thing to do is to
/// shut down the operation and return to the caller.
/// It is acceptable to not catch
/// and allow the exception to reach ProcessRecord.
///
public bool Stopping
{
get
{
using (PSTransactionManager.GetEngineProtectionScope())
{
return this.IsStopping;
}
}
}
///
/// The name of the parameter set in effect.
///
/// the parameter set name
internal string _ParameterSetName
{
get { return _parameterSetName; }
}
///
/// Sets the parameter set.
///
///
/// The name of the valid parameter set.
///
internal void SetParameterSetName(string parameterSetName)
{
_parameterSetName = parameterSetName;
}
private string _parameterSetName = string.Empty;
#region Override Internal
///
/// When overridden in the derived class, performs initialization
/// of command execution.
/// Default implementation in the base class just returns.
///
///
/// This method is overridden in the implementation of
/// individual cmdlets, and can throw literally any exception.
///
internal override void DoBeginProcessing()
{
MshCommandRuntime mshRuntime = this.CommandRuntime as MshCommandRuntime;
if (mshRuntime != null)
{
if (mshRuntime.UseTransaction &&
(!this.Context.TransactionManager.HasTransaction))
{
string error = TransactionStrings.NoTransactionStarted;
if (this.Context.TransactionManager.IsLastTransactionCommitted)
{
error = TransactionStrings.NoTransactionStartedFromCommit;
}
else if (this.Context.TransactionManager.IsLastTransactionRolledBack)
{
error = TransactionStrings.NoTransactionStartedFromRollback;
}
throw new InvalidOperationException(error);
}
}
this.BeginProcessing();
}
///
/// When overridden in the derived class, performs execution
/// of the command.
///
///
/// This method is overridden in the implementation of
/// individual cmdlets, and can throw literally any exception.
///
internal override void DoProcessRecord()
{
this.ProcessRecord();
}
///
/// When overridden in the derived class, performs clean-up
/// after the command execution.
/// Default implementation in the base class just returns.
///
///
/// This method is overridden in the implementation of
/// individual cmdlets, and can throw literally any exception.
///
internal override void DoEndProcessing()
{
this.EndProcessing();
}
///
/// When overridden in the derived class, interrupts currently
/// running code within the command. It should interrupt BeginProcessing,
/// ProcessRecord, and EndProcessing.
/// Default implementation in the base class just returns.
///
///
/// This method is overridden in the implementation of
/// individual cmdlets, and can throw literally any exception.
///
internal override void DoStopProcessing()
{
this.StopProcessing();
}
#endregion Override Internal
#endregion internal_members
#region ctor
///
/// Initializes the new instance of Cmdlet class.
///
///
/// Only subclasses of
/// can be created.
///
protected Cmdlet()
{
}
#endregion ctor
#region public_methods
#region Cmdlet virtuals
///
/// Gets the resource string corresponding to
/// baseName and resourceId from the current assembly.
/// You should override this if you require a different behavior.
///
/// The base resource name.
/// The resource id.
/// The resource string corresponding to baseName and resourceId.
///
/// Invalid or , or
/// string not found in resources
///
///
/// This behavior may be used when the Cmdlet specifies
/// HelpMessageBaseName and HelpMessageResourceId when defining
/// ,
/// or when it uses the
///
/// constructor variants which take baseName and resourceId.
///
///
///
public virtual string GetResourceString(string baseName, string resourceId)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (string.IsNullOrEmpty(baseName))
throw PSTraceSource.NewArgumentNullException(nameof(baseName));
if (string.IsNullOrEmpty(resourceId))
throw PSTraceSource.NewArgumentNullException(nameof(resourceId));
ResourceManager manager = ResourceManagerCache.GetResourceManager(this.GetType().Assembly, baseName);
string retValue = null;
try
{
retValue = manager.GetString(resourceId, CultureInfo.CurrentUICulture);
}
catch (MissingManifestResourceException)
{
throw PSTraceSource.NewArgumentException(nameof(baseName), GetErrorText.ResourceBaseNameFailure, baseName);
}
if (retValue == null)
{
throw PSTraceSource.NewArgumentException(nameof(resourceId), GetErrorText.ResourceIdFailure, resourceId);
}
return retValue;
}
}
#endregion Cmdlet virtuals
#region Write
///
/// Holds the command runtime object for this command. This object controls
/// what actually happens when a write is called.
///
public ICommandRuntime CommandRuntime
{
get
{
using (PSTransactionManager.GetEngineProtectionScope())
{
return commandRuntime;
}
}
set
{
using (PSTransactionManager.GetEngineProtectionScope())
{
commandRuntime = value;
}
}
}
///
/// Internal variant: Writes the specified error to the error pipe.
///
///
/// Do not call WriteError(e.ErrorRecord).
/// The ErrorRecord contained in the ErrorRecord property of
/// an exception which implements IContainsErrorRecord
/// should not be passed directly to WriteError, since it contains
/// a
/// rather than the real exception.
///
/// Error.
///
/// Not permitted at this time or from this thread
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
///
/// terminates the command, where
///
/// allows the command to continue.
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
public void WriteError(ErrorRecord errorRecord)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteError(errorRecord);
else
throw new System.NotImplementedException("WriteError");
}
}
///
/// Writes the object to the output pipe.
///
///
/// The object that needs to be written. This will be written as
/// a single object, even if it is an enumeration.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteObject may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
///
public void WriteObject(object sendToPipeline)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteObject(sendToPipeline);
else
throw new System.NotImplementedException("WriteObject");
}
}
///
/// Writes one or more objects to the output pipe.
/// If the object is a collection and the enumerateCollection flag
/// is true, the objects in the collection
/// will be written individually.
///
///
/// The object that needs to be written to the pipeline.
///
///
/// true if the collection should be enumerated
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteObject may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
///
public void WriteObject(object sendToPipeline, bool enumerateCollection)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteObject(sendToPipeline, enumerateCollection);
else
throw new System.NotImplementedException("WriteObject");
}
}
///
/// Display verbose information.
///
/// Verbose output.
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteVerbose may only be called during a call to this Cmdlets's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// Use WriteVerbose to display more detailed information about
/// the activity of your Cmdlet. By default, verbose output will
/// not be displayed, although this can be configured with the
/// VerbosePreference shell variable
/// or the -Verbose and -Debug command-line options.
///
///
///
///
public void WriteVerbose(string text)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteVerbose(text);
else
throw new System.NotImplementedException("WriteVerbose");
}
}
///
/// Display warning information.
///
/// Warning output.
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteWarning may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// Use WriteWarning to display warnings about
/// the activity of your Cmdlet. By default, warning output will
/// be displayed, although this can be configured with the
/// WarningPreference shell variable
/// or the -Verbose and -Debug command-line options.
///
///
///
///
public void WriteWarning(string text)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteWarning(text);
else
throw new System.NotImplementedException("WriteWarning");
}
}
///
/// Write text into pipeline execution log.
///
/// Text to be written to log.
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteWarning may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// Use WriteCommandDetail to write important information about cmdlet execution to
/// pipeline execution log.
///
/// If LogPipelineExecutionDetail is turned on, this information will be written
/// to PowerShell log under log category "Pipeline execution detail"
///
///
///
///
public void WriteCommandDetail(string text)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteCommandDetail(text);
else
throw new System.NotImplementedException("WriteCommandDetail");
}
}
///
/// Display progress information.
///
/// Progress information.
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteProgress may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// Use WriteProgress to display progress information about
/// the activity of your Cmdlet, when the operation of your Cmdlet
/// could potentially take a long time.
///
/// By default, progress output will
/// be displayed, although this can be configured with the
/// ProgressPreference shell variable.
///
///
///
///
public void WriteProgress(ProgressRecord progressRecord)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteProgress(progressRecord);
else
throw new System.NotImplementedException("WriteProgress");
}
}
///
/// Displays progress output if enabled.
///
///
/// Identifies which command is reporting progress
///
///
/// Progress status to be displayed
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
internal void WriteProgress(
Int64 sourceId,
ProgressRecord progressRecord)
{
if (commandRuntime != null)
commandRuntime.WriteProgress(sourceId, progressRecord);
else
throw new System.NotImplementedException("WriteProgress");
}
///
/// Display debug information.
///
/// Debug output.
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteDebug may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// Use WriteDebug to display debug information on the inner workings
/// of your Cmdlet. By default, debug output will
/// not be displayed, although this can be configured with the
/// DebugPreference shell variable or the -Debug command-line option.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
///
///
///
public void WriteDebug(string text)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
commandRuntime.WriteDebug(text);
else
throw new System.NotImplementedException("WriteDebug");
}
}
///
/// Route information to the user or host.
///
/// The object / message data to transmit to the hosting application.
///
/// Any tags to be associated with the message data. These can later be used to filter
/// or separate objects being sent to the host.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteInformation may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// Use WriteInformation to transmit information to the user about the activity
/// of your Cmdlet. By default, informational output will
/// be displayed, although this can be configured with the
/// InformationPreference shell variable or the -InformationPreference command-line option.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
public void WriteInformation(object messageData, string[] tags)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
ICommandRuntime2 commandRuntime2 = commandRuntime as ICommandRuntime2;
if (commandRuntime2 != null)
{
string source = this.MyInvocation.PSCommandPath;
if (string.IsNullOrEmpty(source))
{
source = this.MyInvocation.MyCommand.Name;
}
InformationRecord informationRecord = new InformationRecord(messageData, source);
if (tags != null)
{
informationRecord.Tags.AddRange(tags);
}
commandRuntime2.WriteInformation(informationRecord);
}
else
{
throw new System.NotImplementedException("WriteInformation");
}
}
}
///
/// Route information to the user or host.
///
/// The information record to write.
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// WriteInformation may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// Use WriteInformation to transmit information to the user about the activity
/// of your Cmdlet. By default, informational output will
/// be displayed, although this can be configured with the
/// InformationPreference shell variable or the -InformationPreference command-line option.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
public void WriteInformation(InformationRecord informationRecord)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
ICommandRuntime2 commandRuntime2 = commandRuntime as ICommandRuntime2;
if (commandRuntime2 != null)
{
commandRuntime2.WriteInformation(informationRecord);
}
else
{
throw new System.NotImplementedException("WriteInformation");
}
}
}
#endregion Write
#region ShouldProcess
///
/// Confirm the operation with the user. Cmdlets which make changes
/// (e.g. delete files, stop services etc.) should call ShouldProcess
/// to give the user the opportunity to confirm that the operation
/// should actually be performed.
///
///
/// Name of the target resource being acted upon. This will
/// potentially be displayed to the user.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// If ShouldProcess returns true, the operation should be performed.
/// If ShouldProcess returns false, the operation should not be
/// performed, and the Cmdlet should move on to the next target resource.
///
///
/// A Cmdlet should declare
/// [Cmdlet( SupportsShouldProcess = true )]
/// if-and-only-if it calls ShouldProcess before making changes.
///
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
/// ShouldProcess will take into account command-line settings
/// and preference variables in determining what it should return
/// and whether it should prompt the user.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire,
///
/// will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
///
///
/// namespace Microsoft.Samples.Cmdlet
/// {
/// [Cmdlet(VerbsCommon.Remove,"myobjecttype1")]
/// public class RemoveMyObjectType1 : Cmdlet
/// {
/// [Parameter( Mandatory = true )]
/// public string Filename
/// {
/// get { return filename; }
/// set { filename = value; }
/// }
/// private string filename;
///
/// public override void ProcessRecord()
/// {
/// if (ShouldProcess(filename))
/// {
/// // delete the object
/// }
/// }
/// }
/// }
///
///
///
///
///
///
///
public bool ShouldProcess(string target)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
return commandRuntime.ShouldProcess(target);
else
return true;
}
}
///
/// Confirm the operation with the user. Cmdlets which make changes
/// (e.g. delete files, stop services etc.) should call ShouldProcess
/// to give the user the opportunity to confirm that the operation
/// should actually be performed.
///
/// This variant allows the caller to specify text for both the
/// target resource and the action.
///
///
/// Name of the target resource being acted upon. This will
/// potentially be displayed to the user.
///
///
/// Name of the action which is being performed. This will
/// potentially be displayed to the user. (default is Cmdlet name)
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// If ShouldProcess returns true, the operation should be performed.
/// If ShouldProcess returns false, the operation should not be
/// performed, and the Cmdlet should move on to the next target resource.
///
///
/// A Cmdlet should declare
/// [Cmdlet( SupportsShouldProcess = true )]
/// if-and-only-if it calls ShouldProcess before making changes.
///
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
/// ShouldProcess will take into account command-line settings
/// and preference variables in determining what it should return
/// and whether it should prompt the user.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
///
///
/// namespace Microsoft.Samples.Cmdlet
/// {
/// [Cmdlet(VerbsCommon.Remove,"myobjecttype2")]
/// public class RemoveMyObjectType2 : Cmdlet
/// {
/// [Parameter( Mandatory = true )]
/// public string Filename
/// {
/// get { return filename; }
/// set { filename = value; }
/// }
/// private string filename;
///
/// public override void ProcessRecord()
/// {
/// if (ShouldProcess(filename, "delete"))
/// {
/// // delete the object
/// }
/// }
/// }
/// }
///
///
///
///
///
///
///
public bool ShouldProcess(string target, string action)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
return commandRuntime.ShouldProcess(target, action);
else
return true;
}
}
///
/// Confirm the operation with the user. Cmdlets which make changes
/// (e.g. delete files, stop services etc.) should call ShouldProcess
/// to give the user the opportunity to confirm that the operation
/// should actually be performed.
///
/// This variant allows the caller to specify the complete text
/// describing the operation, rather than just the name and action.
///
///
/// Textual description of the action to be performed.
/// This is what will be displayed to the user for
/// ActionPreference.Continue.
///
///
/// Textual query of whether the action should be performed,
/// usually in the form of a question.
/// This is what will be displayed to the user for
/// ActionPreference.Inquire.
///
///
/// Caption of the window which may be displayed
/// if the user is prompted whether or not to perform the action.
/// may be displayed by some hosts, but not all.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// If ShouldProcess returns true, the operation should be performed.
/// If ShouldProcess returns false, the operation should not be
/// performed, and the Cmdlet should move on to the next target resource.
///
///
/// A Cmdlet should declare
/// [Cmdlet( SupportsShouldProcess = true )]
/// if-and-only-if it calls ShouldProcess before making changes.
///
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
/// ShouldProcess will take into account command-line settings
/// and preference variables in determining what it should return
/// and whether it should prompt the user.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
///
///
/// namespace Microsoft.Samples.Cmdlet
/// {
/// [Cmdlet(VerbsCommon.Remove,"myobjecttype3")]
/// public class RemoveMyObjectType3 : Cmdlet
/// {
/// [Parameter( Mandatory = true )]
/// public string Filename
/// {
/// get { return filename; }
/// set { filename = value; }
/// }
/// private string filename;
///
/// public override void ProcessRecord()
/// {
/// if (ShouldProcess(
/// string.Format($"Deleting file {filename}"),
/// string.Format($"Are you sure you want to delete file {filename}?"),
/// "Delete file"))
/// {
/// // delete the object
/// }
/// }
/// }
/// }
///
///
///
///
///
///
///
public bool ShouldProcess(
string verboseDescription,
string verboseWarning,
string caption)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
return commandRuntime.ShouldProcess(verboseDescription, verboseWarning, caption);
else
return true;
}
}
///
/// Confirm the operation with the user. Cmdlets which make changes
/// (e.g. delete files, stop services etc.) should call ShouldProcess
/// to give the user the opportunity to confirm that the operation
/// should actually be performed.
///
/// This variant allows the caller to specify the complete text
/// describing the operation, rather than just the name and action.
///
///
/// Textual description of the action to be performed.
/// This is what will be displayed to the user for
/// ActionPreference.Continue.
///
///
/// Textual query of whether the action should be performed,
/// usually in the form of a question.
/// This is what will be displayed to the user for
/// ActionPreference.Inquire.
///
///
/// Caption of the window which may be displayed
/// if the user is prompted whether or not to perform the action.
/// may be displayed by some hosts, but not all.
///
///
/// Indicates the reason(s) why ShouldProcess returned what it returned.
/// Only the reasons enumerated in
///
/// are returned.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// If ShouldProcess returns true, the operation should be performed.
/// If ShouldProcess returns false, the operation should not be
/// performed, and the Cmdlet should move on to the next target resource.
///
///
/// A Cmdlet should declare
/// [Cmdlet( SupportsShouldProcess = true )]
/// if-and-only-if it calls ShouldProcess before making changes.
///
/// ShouldProcess may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
/// ShouldProcess will take into account command-line settings
/// and preference variables in determining what it should return
/// and whether it should prompt the user.
///
///
/// If the pipeline is terminated due to ActionPreference.Stop
/// or ActionPreference.Inquire, this method will throw
/// ,
/// but the command failure will ultimately be
/// ,
///
///
///
/// namespace Microsoft.Samples.Cmdlet
/// {
/// [Cmdlet(VerbsCommon.Remove,"myobjecttype3")]
/// public class RemoveMyObjectType3 : Cmdlet
/// {
/// [Parameter( Mandatory = true )]
/// public string Filename
/// {
/// get { return filename; }
/// set { filename = value; }
/// }
/// private string filename;
///
/// public override void ProcessRecord()
/// {
/// ShouldProcessReason shouldProcessReason;
/// if (ShouldProcess(
/// string.Format($"Deleting file {filename}"),
/// string.Format($"Are you sure you want to delete file {filename}?"),
/// "Delete file",
/// out shouldProcessReason))
/// {
/// // delete the object
/// }
/// }
/// }
/// }
///
///
///
///
///
///
///
public bool ShouldProcess(
string verboseDescription,
string verboseWarning,
string caption,
out ShouldProcessReason shouldProcessReason)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
return commandRuntime.ShouldProcess(verboseDescription, verboseWarning, caption, out shouldProcessReason);
else
{
shouldProcessReason = ShouldProcessReason.None;
return true;
}
}
}
#endregion ShouldProcess
#region ShouldContinue
///
/// Confirm an operation or grouping of operations with the user.
/// This differs from ShouldProcess in that it is not affected by
/// preference settings or command-line parameters,
/// it always does the query.
/// This variant only offers Yes/No, not YesToAll/NoToAll.
///
///
/// Textual query of whether the action should be performed,
/// usually in the form of a question.
///
///
/// Caption of the window which may be displayed
/// when the user is prompted whether or not to perform the action.
/// It may be displayed by some hosts, but not all.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// ShouldContinue may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// If ShouldContinue returns true, the operation should be performed.
/// If ShouldContinue returns false, the operation should not be
/// performed, and the Cmdlet should move on to the next target resource.
///
///
/// Cmdlets using ShouldContinue should also offer a "bool Force"
/// parameter which bypasses the calls to ShouldContinue
/// and ShouldProcess.
/// If this is not done, it will be difficult to use the Cmdlet
/// from scripts and non-interactive hosts.
///
/// Cmdlets using ShouldContinue must still verify operations
/// which will make changes using ShouldProcess.
/// This will assure that settings such as -WhatIf work properly.
/// You may call ShouldContinue either before or after ShouldProcess.
///
/// ShouldContinue may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
/// Cmdlets may have different "classes" of confirmations. For example,
/// "del" confirms whether files in a particular directory should be
/// deleted, whether read-only files should be deleted, etc.
/// Cmdlets can use ShouldContinue to store YesToAll/NoToAll members
/// for each such "class" to keep track of whether the user has
/// confirmed "delete all read-only files" etc.
/// ShouldProcess offers YesToAll/NoToAll automatically,
/// but answering YesToAll or NoToAll applies to all subsequent calls
/// to ShouldProcess for the Cmdlet instance.
///
///
///
/// namespace Microsoft.Samples.Cmdlet
/// {
/// [Cmdlet(VerbsCommon.Remove,"myobjecttype4")]
/// public class RemoveMyObjectType4 : Cmdlet
/// {
/// [Parameter( Mandatory = true )]
/// public string Filename
/// {
/// get { return filename; }
/// set { filename = value; }
/// }
/// private string filename;
///
/// [Parameter]
/// public SwitchParameter Force
/// {
/// get { return force; }
/// set { force = value; }
/// }
/// private bool force;
///
/// public override void ProcessRecord()
/// {
/// if (ShouldProcess(
/// string.Format($"Deleting file {filename}"),
/// string.Format($"Are you sure you want to delete file {filename}"),
/// "Delete file"))
/// {
/// if (IsReadOnly(filename))
/// {
/// if (!Force && !ShouldContinue(
/// string.Format($"File {filename} is read-only. Are you sure you want to delete read-only file {filename}?"),
/// "Delete file"))
/// )
/// {
/// return;
/// }
/// }
/// // delete the object
/// }
/// }
/// }
/// }
///
///
///
///
///
///
public bool ShouldContinue(string query, string caption)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
return commandRuntime.ShouldContinue(query, caption);
else
return true;
}
}
///
/// Confirm an operation or grouping of operations with the user.
/// This differs from ShouldProcess in that it is not affected by
/// preference settings or command-line parameters,
/// it always does the query.
/// This variant offers Yes, No, YesToAll and NoToAll.
///
///
/// Textual query of whether the action should be performed,
/// usually in the form of a question.
///
///
/// Caption of the window which may be displayed
/// when the user is prompted whether or not to perform the action.
/// It may be displayed by some hosts, but not all.
///
///
/// true iff user selects YesToAll. If this is already true,
/// ShouldContinue will bypass the prompt and return true.
///
///
/// true iff user selects NoToAll. If this is already true,
/// ShouldContinue will bypass the prompt and return false.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// ShouldContinue may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// If ShouldContinue returns true, the operation should be performed.
/// If ShouldContinue returns false, the operation should not be
/// performed, and the Cmdlet should move on to the next target resource.
///
///
/// Cmdlets using ShouldContinue should also offer a "bool Force"
/// parameter which bypasses the calls to ShouldContinue
/// and ShouldProcess.
/// If this is not done, it will be difficult to use the Cmdlet
/// from scripts and non-interactive hosts.
///
/// Cmdlets using ShouldContinue must still verify operations
/// which will make changes using ShouldProcess.
/// This will assure that settings such as -WhatIf work properly.
/// You may call ShouldContinue either before or after ShouldProcess.
///
/// ShouldContinue may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
/// Cmdlets may have different "classes" of confirmations. For example,
/// "del" confirms whether files in a particular directory should be
/// deleted, whether read-only files should be deleted, etc.
/// Cmdlets can use ShouldContinue to store YesToAll/NoToAll members
/// for each such "class" to keep track of whether the user has
/// confirmed "delete all read-only files" etc.
/// ShouldProcess offers YesToAll/NoToAll automatically,
/// but answering YesToAll or NoToAll applies to all subsequent calls
/// to ShouldProcess for the Cmdlet instance.
///
///
///
/// namespace Microsoft.Samples.Cmdlet
/// {
/// [Cmdlet(VerbsCommon.Remove,"myobjecttype4")]
/// public class RemoveMyObjectType5 : Cmdlet
/// {
/// [Parameter( Mandatory = true )]
/// public string Filename
/// {
/// get { return filename; }
/// set { filename = value; }
/// }
/// private string filename;
///
/// [Parameter]
/// public SwitchParameter Force
/// {
/// get { return force; }
/// set { force = value; }
/// }
/// private bool force;
///
/// private bool yesToAll;
/// private bool noToAll;
///
/// public override void ProcessRecord()
/// {
/// if (ShouldProcess(
/// string.Format($"Deleting file {filename}"),
/// string.Format($"Are you sure you want to delete file {filename}"),
/// "Delete file"))
/// {
/// if (IsReadOnly(filename))
/// {
/// if (!Force && !ShouldContinue(
/// string.Format($"File {filename} is read-only. Are you sure you want to delete read-only file {filename}?"),
/// "Delete file"),
/// ref yesToAll,
/// ref noToAll
/// )
/// {
/// return;
/// }
/// }
/// // delete the object
/// }
/// }
/// }
/// }
///
///
///
///
///
///
[SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
public bool ShouldContinue(
string query, string caption, ref bool yesToAll, ref bool noToAll)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
return commandRuntime.ShouldContinue(query, caption, ref yesToAll, ref noToAll);
else
return true;
}
}
///
/// Confirm an operation or grouping of operations with the user.
/// This differs from ShouldProcess in that it is not affected by
/// preference settings or command-line parameters,
/// it always does the query.
/// This variant offers Yes, No, YesToAll and NoToAll.
///
///
/// Textual query of whether the action should be performed,
/// usually in the form of a question.
///
///
/// Caption of the window which may be displayed
/// when the user is prompted whether or not to perform the action.
/// It may be displayed by some hosts, but not all.
///
///
/// true if the operation being confirmed has a security impact. If specified,
/// the default option selected in the selection menu is 'No'.
///
///
/// true iff user selects YesToAll. If this is already true,
/// ShouldContinue will bypass the prompt and return true.
///
///
/// true iff user selects NoToAll. If this is already true,
/// ShouldContinue will bypass the prompt and return false.
///
///
/// The pipeline has already been terminated, or was terminated
/// during the execution of this method.
/// The Cmdlet should generally just allow PipelineStoppedException
/// to percolate up to the caller of ProcessRecord etc.
///
///
/// Not permitted at this time or from this thread.
/// ShouldContinue may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
///
/// If ShouldContinue returns true, the operation should be performed.
/// If ShouldContinue returns false, the operation should not be
/// performed, and the Cmdlet should move on to the next target resource.
///
///
/// Cmdlets using ShouldContinue should also offer a "bool Force"
/// parameter which bypasses the calls to ShouldContinue
/// and ShouldProcess.
/// If this is not done, it will be difficult to use the Cmdlet
/// from scripts and non-interactive hosts.
///
/// Cmdlets using ShouldContinue must still verify operations
/// which will make changes using ShouldProcess.
/// This will assure that settings such as -WhatIf work properly.
/// You may call ShouldContinue either before or after ShouldProcess.
///
/// ShouldContinue may only be called during a call to this Cmdlet's
/// implementation of ProcessRecord, BeginProcessing or EndProcessing,
/// and only from that thread.
///
/// Cmdlets may have different "classes" of confirmations. For example,
/// "del" confirms whether files in a particular directory should be
/// deleted, whether read-only files should be deleted, etc.
/// Cmdlets can use ShouldContinue to store YesToAll/NoToAll members
/// for each such "class" to keep track of whether the user has
/// confirmed "delete all read-only files" etc.
/// ShouldProcess offers YesToAll/NoToAll automatically,
/// but answering YesToAll or NoToAll applies to all subsequent calls
/// to ShouldProcess for the Cmdlet instance.
///
///
///
/// namespace Microsoft.Samples.Cmdlet
/// {
/// [Cmdlet(VerbsCommon.Remove,"myobjecttype4")]
/// public class RemoveMyObjectType5 : Cmdlet
/// {
/// [Parameter( Mandatory = true )]
/// public string Filename
/// {
/// get { return filename; }
/// set { filename = value; }
/// }
/// private string filename;
///
/// [Parameter]
/// public SwitchParameter Force
/// {
/// get { return force; }
/// set { force = value; }
/// }
/// private bool force;
///
/// private bool yesToAll;
/// private bool noToAll;
///
/// public override void ProcessRecord()
/// {
/// if (ShouldProcess(
/// string.Format($"Deleting file {filename}"),
/// string.Format($"Are you sure you want to delete file {filename}"),
/// "Delete file"))
/// {
/// if (IsReadOnly(filename))
/// {
/// if (!Force && !ShouldContinue(
/// string.Format($"File {filename} is read-only. Are you sure you want to delete read-only file {filename}?"),
/// "Delete file"),
/// ref yesToAll,
/// ref noToAll
/// )
/// {
/// return;
/// }
/// }
/// // delete the object
/// }
/// }
/// }
/// }
///
///
///
///
///
///
[SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
public bool ShouldContinue(
string query, string caption, bool hasSecurityImpact, ref bool yesToAll, ref bool noToAll)
{
using (PSTransactionManager.GetEngineProtectionScope())
{
if (commandRuntime != null)
{
ICommandRuntime2 runtime2 = commandRuntime as ICommandRuntime2;
if (runtime2 != null)
{
return runtime2.ShouldContinue(query, caption, hasSecurityImpact, ref yesToAll, ref noToAll);
}
else
{
return commandRuntime.ShouldContinue(query, caption, ref yesToAll, ref noToAll);
}
}
else
return true;
}
}
///
/// Run the cmdlet and get the results as a collection. This is an internal
/// routine that is used by Invoke to build the underlying collection of
/// results.
///
/// Returns an list of results.
internal List