Introduction
This is the first article in the series How to Write a Custom Powershell Cmdlet. I will try to keep these articles to the point without missing any important details. I will elaborate on things that are not very clear in the Microsoft documentation or may be missing. For most part, Microsoft has done a wonderful job of documentation for the programmer's SDK for PowerShell programming.
The first step in writing a PowerShell cmdlet is to pick what you want your cmdlet to do. What is the value that this cmdlet is going to add? Microsoft has already provided a lot of cmdlets that facilitate system management and administration. As you will use PowerShell more and more, you will find out that there are a lot of other things that you can do with the PowerShell piping architecture. I will not go into the details of the uses of PowerShell, other than system management or administration, in this article. That will be the discussion for another day. In this article, I will explains the steps that you will need to put together to write a PowerShell cmdlet.
I am writing a cmdlet to automate the testing of a search engine API. And, in the process of writing the test automation for the API, I realized that I can use this cmdlet to perform a lot of searches just by using PowerShell instead of using the GUI. And, taking advantage of the Where-Object cmdlet, I can pipe the results of my cmdlet to it and filter the results. See how easy it is to put together a quick Use Case of a custom PowerShell cmdlet and use it to ease a lot of tasks. Well, I can't publish the cmdlet that I am developing for my search engine. But I thought I will write a cmdlet to search Amazon.com from PowerShell. So, I will develop my cmdlet on top of my C# API for Amazon.com.
The Cmdlet class
The first step is to write a class that will implement the heart of your cmdlet. For this basic article and cmdlet, I will not go into the details of if you should be deriving your class from Cmdlet
or PSCmdlet
. For most cases, you will be deriving your class from Cmdlet
unless you are developing a cmdlet that requires access to the PowerShell runtime or need to perform some complex tasks related to the runtime. Picking the name of your cmdlet is very important. Your class name comprises of two parts: Verb and Noun. The Verb defines the action that this cmdlet will perform, and the Noun defines the object on which the Verb acts. For example, for my cmdlet, I want to search books in Amazon.com. So, the Verb for my class is "Search" or "Get", and the Noun is "Book". So I have created a class named GetBookCommand
. You must be asking why I did not call it GetBooksCommand
. As per Microsoft naming guidelines, to keep names consistent, avoid the use of plurals on nouns.
public class GetBookCommand : Cmdlet {...}
Defining the command line parameters
If your cmdlet can perform its action without using any input parameters, there is nothing that you need to do. But, if you need input parameters, then, you need to define the properties in your class for those parameters. And, the most important part of defining properties is naming them. Microsoft has provided some guidelines for naming the properties so that your cmdlet is consistent with all other cmdlets. See the Cmdlet Parameter Names guideline by Microsoft for more details.
One thing you need to decide is what parameters are mandatory and what are optional for the execution of your cmdlet. This is where the use of the Parameter
attribute on your property will be important. This attribute class has properties that you can use to fine tune the use of a parameter. For example, if you want to mark your parameter to be mandatory, you can set the Mandatory
property of the attribute. I will demonstrate this with the use of this attribute in my cmdlet. For the operation of my Get-Book
cmdlet, it is absolutely mandatory that the user provides the following four command line parameters:
AssociateTag
AccessKey
SearchTerm
Count
So, I defined properties in my cmdlet class for these values, and put attributes on them to mark them as mandatory. The following code snippet shows the definition of the AssociateTag
property.
[Parameter(Mandatory = true,
HelpMessage="Specify associate tag issued by Amazon.com")]
[ValidateNotNullOrEmpty]
public string AssociateTag
{
get { return _associateTag; }
set{ _associateTag = value;}
}
Notice the use of the Manadatory
and HelpMessage
properties on the attribute. Also notice the use of the ValidationNotNullOrEmpty
attribute. You can use validation attributes to allow the PowerShell runtime to validate a user's input.
Overriding Methods
There are four methods that you can override to execute your cmdlet: BeginProcessing
, ProcessRecord
, EndProcessing
, and StopProcessing
. Most cmdlet implementations only need to worry about the ProcessRecord
method. This is where you will manipulate your input objects and write them to the output. But, if your cmdlet requires some pre-processing or needs some initialization, you can override the BeforeProcessing
method and do your work there. For example, if you are implementing a cmdlet that needs to open connections with a database before taking any action, you can do that in BeginProcessing
. And, if you need to do some clean up after record(s) are processed, you can implement the EndProcessing
method and do your clean up there. For example, if you have opened a database connection in your cmdlet, you can always implement the clean up in EndProcessing
. The implementation of StopProcessing
will be important if you have some resources open in your cmdlet that need clean up. If for some reason, the user decides to cancel or stop your cmdlet, then this method will give you a chance to clean up. Otherwise, you will have leaked resources. The following code snippet shows how I did an override on the BeginProcessing
method to perform search. In the actual implementation, I have put a method to check if the target location of the search data is available of not. If the target URL is down, there is no need to go any further.
protected override void BeginProcessing()
{
base.BeginProcessing();
CreateDataAPI();
ExecuteSearch();
}
Process Records
The PowerShell runtime will call the ProcessRecord
method of your cmdlet to allow you to send objects of your cmdlet to the output. This is the place where you can put together an implementation to gather records that you need to display and then call WriteObject
to send them to the output. There are other ways to send to the output as well. But, for this article, I will keep the implementation simple and call the WriteObject
method to allow the PowerShell runtime to take care of the rendering of my record.
protected override void ProcessRecord()
{
base.ProcessRecord();
foreach (Book book in _books)
{
WriteObject(book);
}
}
That is the end of the implementation of your cmdlet. You can see how easy it is. I will write about how to register your cmdlet with PowerShell and other good stuff in my next article. In the mean time, you can download the whole implementation of this cmdlet from the following location: