5,702,921 members and growing! (14,299 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » Vista API » General     Intermediate

Build a PowerShell cmdlet

By Shahar Gvirtz

Learn how to build a simple Windows PowerShell cmdlet, use parameters, wildcards, CustomPSSnapin and the Extended Type System
.NET 2.0, WinXP, Win2003, Vista, Windows, .NET, Visual Studio, IIS, IIS 7, Dev

Posted: 13 Oct 2007
Updated: 20 Oct 2007
Views: 10,953
Bookmarked: 18 times
Announcements
Loading...



Search    
Advanced Search
Sitemap
8 votes for this Article.
Popularity: 3.71 Rating: 4.11 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
1 vote, 12.5%
3
2 votes, 25.0%
4
5 votes, 62.5%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Download codeproject3.zip - 24.0 KB

What is Windows PowerShell?

Windows PowerShell (AKA Monad) is new CLI (Command Line Interface) provided by Microsoft.
PowerShell based on .NET Framework 2.0 and pass data as .NET objects.

What are we going to do?

In this article, you'll see how to develop command let (cmdlet, powershell commands) which support wildcard, and use ETS (Extended Type System) and how to use CustomPSSnapIn.

The sample use the IIS 7 and the IIS 7 .net libraries (Microsoft.Web.Administration) to reterive the list of websites in the local IIS 7 server.

How to begin?

  1. First, download Windows PowerShell, ofcouse.
  2. Download Windows SDK
  3. Download PowerShell template for Visual Studio (optional).

What's are actually Cmdlets?

Cmdlets are tiny .NET class, which derived from System.Management.Automation.Cmdlet or from System.Management.Automation.PSCmdlet and override few methods with your own logic.
These cmdlets installed to the powershell and can be used from powershell or from other applications which use the powershell to Invoke cmdlets.

Cmdlet Vs. PSCmelet

Cmdlet class can derived from 2 different classes: Cmdlet and PSCmdlet. The difference is how much you depence on windows powershell environment.
When deriving from Cmdlets, you aren't really depend on powershell. You are not impacted by any changes in powershell runtime.
In addition, your cmdlet can invoke directly from any application instead of invoking it through the Windows PowerShell runtime.

In most cases, deriving from Cmdlet is the best choice except when you need fully integration with powershell runtime, access to session state data, call scripts etc. Then, you'll derive from PSCmdlet.

Cmdlet Attribute

Every cmdlet have a name in the same template verb-noun. The verb (get,set,new,add etc.) is from built in list of verbs name. The noun, is for you'r choice.

The first part in the cmdlet class (getWebsites.cs) is:

[Cmdlet(VerbsCommon.Get, "ws" SupportsShouldProcess = true)]

The verb is "Get" (from the enum VerbsCommon), the noun is "ws" and we supports ShouldProcess.
It's very important to use the verb from one of the Enums.

Note, that in the top of the code, i have this using statement:

using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Collections;
using Microsoft.Web.Administration;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection;

The bolds are the "Special" namespaces which relevant for powershell except Microsoft.Web.Administration which used to manage IIS 7.

Parameters

Almost any powershell cmdlet use parameters to help users get relevant information. The parameters are, actually, properties which have ParameterAttribute before:

[Parameter(Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "Enter filter by site name (support wildcard)")]
[Alias("SiteName")]

public string Name

{

set { names = value; }

}

Parameters can ve user by position or by property name. It's mean that if we set the parameter in position 0 you can call the cmdlet like this:
get-websites *
The "*" is the parameter, or by propery name:
get-websites -Name *Here, we also defined alias:
get-websites -SiteName *

The mandatory means that the user must enter value to this parameter.

The main logic

In our cmdlet, we can override few methods. We must override at least on to this list:

BeginProcessing

The code here used, in most cases, to preapare the cmdlet. this code runs only once, when the cmdlet calls.

ProcessRecord

This is the most common overrided method. This method include the main logic. this code can run even more than once, as requied.

EndProcessing

This overrided method used to finalize the cmdlet operation.

We can also override StopProcessing Method, which include code that will run in unexpected stop of the cmdlet (for example, the user use ctrl+c).

I override only the ProcessRecord method.
First, I create instance of the generic System.Collections.ObjectModel.Collection<> collection. This is the collection type powershell use. The type is PSObject, which is the main object powershell used.

Because we want to support wildcard, I use the buil-in wildcard classes that comes with powershell:

WildcardOptions options = WildcardOptions.IgnoreCase |WildcardOptions.Compiled;
WildcardPattern wildcard = new WildcardPattern(names, options); 

Then, we create instance of Microsoft.Web.Administration.ServerManager, the object used to manage IIS 7 websites.

In the foreach loop , We check for every site if his name match the wildcard. If it is, we convert it to PSObject.

Extended Type System

Extended Type System is one of the main and most interesting powershell concepts. it's mean that we can extend any type we just want, and add members in addition to the built in members.
The PSObject object is the main object in powershell, because it's include the original object and the extended members in the same object, and give the user or other developer who invokes this cmdlet the option to use any member - the original members and the extended one.

ps.Properties.Add(new PSNoteProperty("MaxBandwidthMB", site.Limits.MaxBandwidth / 1024));

Here, we add a new property called MaxBandwidthMB and his value is the the original bandwidh value / 1024.

Types can be extended from code, or from XML files in specific format. Here, we see example to extend type with new property - but we can add properties and methods from a lot of types: aliases, scripts, code methods etc.

Finally, we add the PSObject instance which include the original (early bound object) and the extended members to the collection, and use WriteHost method to write it to the host (can be powershell command line host, or other application that invoke our cmdlet).

After you'll finish the cmdlet, you can get a list of members of the object returns from the cmdlet. look, that here you can see our extended property (marked):

Screenshot - Capture.jpg

In case of Exception....

We use try...catch statement, and if exception occured we use WriteError method to write information about the error to the host.

Formats

If we use this cmdlet now from the console, we will get strange output, which include objects type and few values. We have to specify the default output view we want. We do this in the format.ps1xml file. note that we use MaxBandwidthMB property, which is extended one.

This is the output without the format file:

Screenshot - Capture1.jpg

Snap In

The snap In include the detiles powershell needs to install the cmdlet. We can derived from PSSnapIn which is the "default" - install everything you can, or from CustomPSSnapIn then we set exactly what to do.

Here, we add the cmdlet and the format file.

First, we define collection for cmdlets, formats,types,providers. in the constructor, we add the cmdlet and the format file.
We also override few properties to include information about our snapin. And, we override properties to return our collection of cmdlets and formats.

Installation

From powershell, we install the snap in with installutil.exe, part of the .NET Framework SDK.
I Wrote a little function you can add to your profile:

function installutil
{
param([string]$dllPath=$(throw "Please Enter the DLL path to Install!"))
set-alias installutil $env:windir\Microsoft.NET\Framework\v2.0.50727\installutil
if(test-path $dllPath)
{
installutil /u $dllpath
installutil $dllpath
write-host "snap-in installed. now, you can add it to your shell instance"
}
else{
write-error "The file does not exist"
}
}

Now, you just have to enter:

installutil dllPath

Instead of dllPath, enter the full path to the dll which include the dll of the project.

Now, you have to add the snap-in:

add-pssnapin cpdemo

Note that you may have to change the path of the format file in snapin.cs class.

And that's all! The cmdlet is ready to use and return Collection of PSObject which include Microsoft.Web.Administration.Site and extended property.

In PowerShell, you can use the object that the cmdlet return for more things. this command, for example, will save the output to csv file:

get-ws d* | Where{$_.MaxBandwidthMB -gt 4000000} | Select-Object Name,MaxBandwidthMB | out-csv c:\csv.csv

This command, will save new csv file which include list of the name and the MaxBandwidthMB property for all sites that theyr name begin with "d" where the value of the property MaxBandwidthMB > 4000000.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Shahar Gvirtz



Occupation: Web Developer
Location: Israel Israel

Other popular Vista API articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 2 of 2 (Total in Forum: 2) (Refresh)FirstPrevNext
GeneralNice!memberJean-Paul Mikkers11:48 15 Oct '07  
GeneralRe: Nice!memberShahar Gvirtz20:43 15 Oct '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 20 Oct 2007
Editor:
Copyright 2007 by Shahar Gvirtz
Everything else Copyright © CodeProject, 1999-2008
Web09 | Advertise on the Code Project