Click here to Skip to main content
Click here to Skip to main content
Go to top

How to Write a Custom PowerShell Cmdlet - Part I

, 11 Feb 2009
Rate this:
Please Sign up or sign in to vote.
How to write custom PowerShell cmdlet.

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:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

ByteBlocks

United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 4 PinmemberNOURANE KOULI28-Sep-12 2:55 
GeneralAwsome series Pinmemberglgcore11-Feb-09 4:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 11 Feb 2009
Article Copyright 2009 by ByteBlocks
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid