Creating a Cmdlet that Modifies the System
Sometimes a cmdlet must modify the running state of the system, not just the state of the Windows PowerShell runtime. In these cases, the cmdlet should allow the user a chance to confirm whether or not to make the change.
To support confirmation a cmdlet must do two things.
Declare that the cmdlet supports confirmation when you specify the CmdletAttribute attribute by setting the SupportsShouldProcess keyword to true.
Call ShouldProcess during the execution of the cmdlet (as shown in the following example).
By supporting confirmation, a cmdlet exposes the Confirm and WhatIf parameters that are provided by Windows PowerShell, and also meets the development guidelines for cmdlets (For more information about cmdlet development guidelines, see Cmdlet Development Guidelines.).
Changing the System
The act of "changing the system" refers to any cmdlet that potentially changes the state of the system outside Windows PowerShell. For example, stopping a process, enabling or disabling a user account, or adding a row to a database table are all changes to the system that should be confirmed. In contrast, operations that read data or establish transient connections do not change the system and generally do not require confirmation. Confirmation is also not needed for actions whose effect is limited to inside the Windows PowerShell runtime, such as set-variable. Cmdlets that might or might not make a persistent change should declare SupportsShouldProcess and call ShouldProcess only if they are about to make a persistent change.
|ShouldProcess confirmation applies only to cmdlets. If a command or script modifies the running state of a system by directly calling .NET methods or properties, or by calling applications outside of Windows PowerShell, this form of confirmation will not be available.|
The StopProc Cmdlet
This topic describes a Stop-Proc cmdlet that attempts to stop processes that are retrieved using the Get-Proc cmdlet (described in Creating a Cmdlet without Parameters).
|The complete sample code is no longer available on MSDN. You can download the C# source file (stopproc01.cs) for this cmdlet as part of the Microsoft® Windows® Software Development Kit Update for Windows Vista™. You can download the SDK at http://www.microsoft.com/download/details.aspx?id=23719. The downloaded source files are available in the <PowerShell Samples> directory. For updated code samples based on Windows PowerShell 2.0, see Cmdlet Samples.|
Topics in this section include the following:
Defining the Cmdlet
The first step in cmdlet creation is always naming the cmdlet and declaring the .NET class that implements the cmdlet. Because you are writing a cmdlet to change the system, it should be named accordingly. This cmdlet stops system processes, so the verb name chosen here is "Stop", defined by the VerbsLifeCycle class, with the noun "Proc" to indicate that the cmdlet stops processes. For more information about approved cmdlet verbs, see Approved Verbs for Windows PowerShell Commands.
The following is the class definition for this Stop-Proc cmdlet.
Be aware that in the CmdletAttribute declaration, the SupportsShouldProcess attribute keyword is set to true to enable the cmdlet to make calls to ShouldProcess and ShouldContinue. Without this keyword set, the Confirm and WhatIf parameters will not be available to the user.
Extremely Destructive Actions
Some operations are extremely destructive, such as reformatting an active hard disk partition. In these cases, the cmdlet should set ConfirmImpact = ConfirmImpact.High when declaring the CmdletAttribute attribute. This setting forces the cmdlet to request user confirmation even when the user has not specified the Confirm parameter. However, cmdlet developers should avoid overusing ConfirmImpact for operations that are just potentially destructive, such as deleting a user account. Remember that if ConfirmImpact is set to High, script writers must explicitly work around the confirmation every time they use the command. When in doubt, stay with the default setting of Medium.
Similarly, some operations are unlikely to be destructive, although they do in theory modify the running state of a system outside Windows PowerShell. Such cmdlets can set ConfirmImpact to Low. This will bypass confirmation requests where the user has asked to confirm only medium-impact and high-impact operations.
Defining Parameters for System Modification
This section describes how to define the cmdlet parameters, including those that are needed to support system modification. See Adding Parameters That Process Command-Line Input if you need general information about defining parameters.
The Stop-Proc cmdlet defines three parameters: Name, Force, and PassThru.
The Name parameter corresponds to the Name property of the process input object. Be aware that the Name parameter in this sample is mandatory, as the cmdlet will fail if it does not have a named process to stop.
The Force parameter allows the user to override calls to ShouldContinue. In fact, any cmdlet that calls ShouldContinue should have a Force parameter so that when Force is specified, the cmdlet skips the call to ShouldContinue and proceeds with the operation. Be aware that this does not affect calls to ShouldProcess.
The PassThru parameter allows the user to indicate whether the cmdlet passes an output object through the pipeline, in this case, after a process is stopped. Be aware that this parameter is tied to the cmdlet itself instead of to a property of the input object.
Here is the parameter declaration for the Stop-Proc cmdlet.
Overriding an Input Processing Method
The cmdlet must override an input processing method. The following code illustrates the ProcessRecord override used in the sample Stop-Proc cmdlet. For each requested process name, this method ensures that the process is not a special process, tries to stop the process, and then sends an output object if the PassThru parameter is specified.
Calling the ShouldProcess Method
The input processing method of your cmdlet should call the ShouldProcess method to confirm execution of an operation before a change (for example, deleting files) is made to the running state of the system. This allows the Windows PowerShell runtime to supply the correct “WhatIf” and “Confirm” behavior within the shell.
|If a cmdlet states that it supports should process and fails to make the ShouldProcess call, the user might modify the system unexpectedly.|
The call to ShouldProcess sends the name of the resource to be changed to the user, with the Windows PowerShell runtime taking into account any command-line settings or preference variables in determining what should be displayed to the user.
Calling the ShouldContinue Method
The call to the ShouldContinue method sends a secondary message to the user. This call is made after the call to ShouldProcess returns true and if the Force parameter was not set to true. The user can then provide feedback to say whether the operation should be continued. Your cmdlet calls ShouldContinue as an additional check for potentially dangerous system modifications or when you want to provide yes-to-all and no-to-all options to the user.
Stopping Input Processing
The input processing method of a cmdlet that makes system modifications must provide a way of stopping the processing of input. In the case of this Stop-Proc cmdlet, a call is made from the ProcessRecord method to the Kill method. Because the PassThru parameter is set to true, ProcessRecord also calls WriteObject to send the process object to the pipeline.
The complete sample code is no longer available on MSDN.
You can download the C# source file (stopproc01.cs) for this cmdlet as part of the Microsoft® Windows® Software Development Kit Update for Windows Vista™. You can download the SDK at http://www.microsoft.com/en-us/download/details.aspx?id=23719.
The downloaded source files are available in the <PowerShell Samples> directory.
For updated code samples based on Windows PowerShell 2.0, see Cmdlet Samples.
Defining Object Types and Formatting
Windows PowerShell passes information between cmdlets using .Net objects. Consequently, a cmdlet may need to define its own type, or the cmdlet may need to extend an existing type provided by another cmdlet. For more information about defining new types or extending existing types, see Extending Object Types and Formatting.
Building the Cmdlet
After implementing a cmdlet, it must be registered with Windows PowerShell through a Windows PowerShell snap-in. For more information about registering cmdlets, see Registering a Program Module with Windows PowerShell.
Testing the Cmdlet
When your cmdlet has been registered with Windows PowerShell, you can test it by running it on the command line. Here are several tests that test the Stop-Proc cmdlet. For more information about using cmdlets from the command line, see the Windows PowerShell Getting Started Guide.
Start Windows PowerShell and use the Stop-Proc cmdlet to stop processing as shown below. Because the cmdlet specifies the Name parameter as mandatory, the cmdlet queries for the parameter.
Cmdlet stop-proc at command pipeline position 1 Supply values for the following parameters: Name:
Now let's use the cmdlet to stop the process named "NOTEPAD". The cmdlet asks you to confirm the action.
PS> stop-proc -Name notepad
Confirm Are you sure you want to perform this action? Performing operation "stop-proc" on Target "notepad (4996)". [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): Y
Use Stop-Proc as shown to stop the critical process named "WINLOGON". You are prompted and warned about performing this action because it will cause the operating system to reboot.
PS> stop-proc -Name Winlogon
Confirm Are you sure you want to perform this action? Performing operation "stop-proc" on Target "winlogon (656)". [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): Y Warning! The process " winlogon " is a critical process and should not be stopped. Are you sure you wish to stop the process? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): N
Let's now try to stop the WINLOGON process without receiving a warning. Be aware that this command entry uses the Force parameter to override the warning.
PS> stop-proc -Name winlogon -Force
Confirm Are you sure you want to perform this action? Performing operation "stop-proc" on Target "winlogon (656)". [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): N