This is the second part of the series on customizing Windows PowerShell. This time I’m going to explain how to create your own commandlets. Commandlets are a very powerful way to extend the functionality of Windows PowerShell, it’s also one of the most common scenario’s people will use for extending PowerShell.
Commandlet basics
Every non-system command (executable or script) is a commandlet, alias or a function. I will not discuss how functions and aliases work, the manual has a great explaination on how microsoft handles these and also describes what to do with them.
A commandlet is a .NET class which inherits from either Cmdlet or PSCmdlet. If you inherit from Cmdlet you are creating a commandlet which doesn’t require information or funcionality from Microsoft Powershell. This enables scenario’s where you want to use the commandlet in your own application outside of powershell. However if you need sessionstate or other functionality from Microsoft PowerShell, it’s best to inherit from PSCmdlet.
A basic commandlet looks like this:
[Cmdlet("Greet","Person")]
public class CreatePackageCmdlet: Cmdlet { /// <summary> /// Writes hello world to the console /// </summary> protected override void ProcessRecord() { WriteObject("Hello World"); } }
Commandlet processing
When PowerShell invokes a commandlet it invokes several methods in a specific order. Depending on what you are trying to do you need to override one of these methods or several of these methods. The order in which microsoft invokes the methods on the commandlets is as follows:
- BeginProcessing
At the beginning of the processing cycle PowerShell invokes BeginProcessing. In this method the commandlet should initialize itself so that it can process the records that are available on the current pipeline. - ProcessRecord
ProcessRecord gets invoked for each object on the pipeline. The commandlet can handle each record and write the results back to the pipeline. - EndProcessing
At the end of the processing cycle PowerShell invokes the EndProcessing method. The commandlet should use this method to clean up any resources that were used and close all handles that were opened by the commandlet.
Parameters
A commandlet can have two kinds of parameters. Each of type of parameter gets initialized at a different moment during the processing lifecycle. The first kind of parameter is the commandline parameter. This parameter gets initialized just before BeginProcessing gets invoked. Consequently, these parameters only get set once for each commandlet. The second kind of parameter is the pipeline parameter. This kind of parameter gets initialized just before ProcessRecord is invoked.
Commandline parameters come in two variaties, positional and named parameters. A parameter gets named by default, PowerShell will look for the name of the property to determine the name of the parameter. To make a parameter positional, add the Position = … argument to the attribute of a parameter.
A sample of a basic commandline parameter looks like this:
[Cmdlet("Greet","Person")] public class CreatePackageCmdlet: Cmdlet { /// <summary> /// Gets or sets the name of the person who needs to be greeted /// </summary> [Parameter(Position=0)] public string Name { get; set; } /// <summary> /// Writes hello world to the console /// </summary> protected override void ProcessRecord() { WriteObject("Hello " + Name); } }
The second kind of parameters is done in the same manner. By setting the InputFromPipeline argument on the attribute to true you enable the parameter to be filled each pass of the processing cycle (for as long as there are objects available on the pipeline of course).
A sample of a pipeline parameter is shown below:
[Cmdlet("Greet","Person")] public class CreatePackageCmdlet: Cmdlet { /// <summary> /// Gets or sets the name of the person who needs to be greeted /// </summary> [Parameter(ValueFromPipeline=true)] public string Name { get; set; } /// <summary> /// Writes hello world to the console /// </summary> protected override void ProcessRecord() { WriteObject("Hello " + Name); } }
You can now use this commandlet in sequences like this:
$people = ‘Bob’,’Eve’,’Mark’
$people | greet-person
More information
There’s loads more I could tell about commandlets and I will in later on in the series, but this is it for now. For more information on how Windows PowerShell works:
- Adding parameters to the commandlet: http://msdn2.microsoft.com/en-us/library/ms714663(VS.85).aspx
- How Windows PowerShell works: http://msdn2.microsoft.com/en-us/library/ms714658(VS.85).aspx