How To Write Custom Powershell Cmdlet - Part 1

Download Amazon Search Cmdlet (111.93 kb)

 

This is first article in series of How to write custom Powershell Cmdlet. I will try to keep these articles to the point without missing any important details. I will elobrate on things that are not very clear in Microsoft documentation or may be missing. For most part Microsoft has done wonderful job of documentation for programmer's SDK for powershell programming.

First step in writing powershell Cmdlet is to pick what do you want your Cmdlet to do. What is value that this Cmdlet is going to add. Microsoft has already provided lot of Cmdlets that facilitate system management and administration. As you will use Powershell more and more, you will find out that there are lot of other things that you can do with powershell piping architecture. I will not go into details of uses of powershell other than system management or adminstration in this article. That will be discussion for another day. In this article I will explains steps that you will need to put together to write a Powershell Cmdlet.

I am writing a Cmdlet to automate testing of a search engine API. And in process of wriitng the test automation for API, I realized that I can use this Cmdlet to perform lot of searches just by using Powershell instead of using GUI. And taking advantage of Where-Object Cmdlet, I can pipe results of my Cmdlet to it and filter the results. See how easy it is to put together a quick use case of custom Powerhshell and use it to ease 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 C# API for Amazon.com that I wrote.

Cmdlet Class

First step is to write a class that will implement heart of your Cmdlet. For this basic article and Cmdlet, i will not go into 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 powershell run time or need to perform some complex tasks related to runtime. Picking name of your Cmdlet is very important. Your class name is comprised of two parts, Verb and Noun. Verb defines the action that this Cmdlet will perform and Noun defines the object on which the Verb act. For example for my Cmdlet I want to search books in Amazon.com. So verb for my class is "Search" or "Get" and noun is "Book". So I have created a class names GetBookCommand. You must be asking why I did not call it GetBooksCommand. As per Microsoft naming guidelines to keep the names consistent, avoid use of plurals on nouns.

public class GetBookCommand : Cmdlet {...}

Define Commandline Parameters

If your Cmdlet can perform i ts 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 properties in your class for those parameters. And most important part of defining properties is naming them as well. Microsoft has provided some guidlines for naming the properties so that your Cmdlet is consistent with all other Cmdlets. See Cmdlet Parameter Names guideline by Microosft for more details.

In thing you need to decide is what parameters are mandatory and what are optional for execution of your Cmdlet. This is where use of Parameter attribute on your property will be important. This attribute class has properties that you can use to fine tune use of parameter. For example if you want to mark your parameter to be mandatory, you can set Mandatory proprty of the attribute. I will demonstrate this will use of this attribute in my Cmdlet. For operation of my Get-Book Cmdlet, it is absolutely manadatory that user provides following four commnd line parameters.

  • AssociateTag
  • AccessKey
  • SearchTerm
  • Count

So i defined properties in my Cmdlet class for these values and put attribute on them to mark them mandatory. Following code snippet shows definition of AssociateTag poperty.

[Parameter(Mandatory = true, 
HelpMessage="Specify associate tag issued by Amazon.com")]
[ValidateNotNullOrEmpty]
public string AssociateTag
{
get { return _associateTag; }
set{ _associateTag = value;}
}

Notice use of Manadatory and HelpMessage properties on attribute. Also notice use of ValidationNotNullOrEmpty attribute. You can use validation attributes to allow powershell run time to validate user's input.

Override Methods

There are four methods that you can override to execute your Cmdlet, BeginProcessing, ProcessRecord, EndProcessing and StopProcessing. Most of Cmdlet implementations only need to worry about ProcessRecord method. This is where you will manipulate your input objects and write them to output. But if your Cmdlet requires some pre processing or needs some initialization, you can override BeforeProcessing method and do your work there. For example, if you are implementing Cmdlet that needs to open connection 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 EndProcessing method and do your clean up there. For example if you have opened a database connection in your Cmdlet, you can always implement clean up in EndProcessing. Implementation of StopProcessing will be important if you have some resources open in your Cmdlet that need clean up. If for some reason user decided to cancel or stop your Cmdlet, then this method will give you a chance to clean up. Otherwise you will have leaked resources. Following code snippet shows how i did an override on BeginProcessing method to perform search. In actual implementation, I have put method to check if taret location of search data is available of not. If target URL is down, there is no need to go any further.

protected override void BeginProcessing()
{
base.BeginProcessing();
CreateDataAPI();
ExecuteSearch();
}

Process Records

Powershell run time will call ProcessRecord method of your Cmdlet to allow you to send objects of your Cmdlet to output. This is the place where you can put together implementation to gather records that you need to display and then call WriteObject to send them to output. There are other ways to send output as well. But for this article I will keep the implementation simple and call WriteObject method to allow Powershell runtime to take care of rendering of my record.

protected override void ProcessRecord()
{
base.ProcessRecord();
foreach (Book book in _books)
{
WriteObject(book);
}
}

That is the end of implementation of your Cmdlet. You can see how easy it is. Rest if now book keeping about how to register your Cmdlet with Powershell and oher good stuff.

Custom Powershell Cmdlet - Part2

Search

Social

Weather

Monthly Posts