V2 Script Cmdlets

One feature of PowerShell V2 that is being touted by many developers and hard core scripters is Script Cmdlets. This is essentially the ability to build full blown cmdlets natively in PowerShell. You will no longer have to venture into the world of C# or VB .NET to build a  real Cmdlet. I've been working on a Cmdlet in C# over the last week or so and up until then I don't think I was able to fully appreciate the power that is coming with Script Cmdlets. Now that I have seen what you can do in C# and really how ridiculously easy it is to do, I can't wait to start developing Cmdlets in PowerShell.

One of the most frustrating problems in Version 1 was having to deal with parameters. Specifically, figuring out how to get input from the pipeline if its available, and from specifying the parameter name directly. Script Cmdlets solve this problem beautifully!

When developing a cmdlet in C#, you use something called attributes that get tacked on to the parameter that is being declared. Just as an example, lets say we were writing a cmdlet to create a new Hyper-V Virtual Machine. When you create a new VM, you want to be able to specify the number of CPU's.

You can do this with the following code:

            Position = 2,
            Mandatory = false,
            ValueFromPipeline = true,
            ValueFromPipelineByPropertyName = true,
            HelpMessage = "Please enter the number of Processors to add to the VM (1-4)"
        [ValidateRange(1, 4)] //can only have up to 4 processors
        public int NumberOfCpus { get; set; }

In this code, there is a bunch of things going on, but they are fairly self-explanatory if you dig in to them. First of all, the actual parameter is just an integer named NumberOfCpus that is being declared at the very bottom. All the attributes are declared above the object that they are tied to.

In this case I have added the Parameter attribute with a few options. The first is that this is this parameter is the second parameter if no name is specified. The second is saying that this parameter is not required, by declaring "Mandatory" to be false.

The next two options are the ones that solve the pipeline problem. I can't tell you how great this will be in V2. Just by declaring these options, you can grab objects from the pipeline and inject them into the argument of your parameter.

There is a reason there are two options here. The first one is used for basic pipeline input. Take, for example, get-content servers.txt | new-vm. If there was a parameter called Name that accepted values from the pipeline, that would work.

The ValueFromPipelineByPropertyName is a little more tricky. This is the reason this command works

get-process notepad | get-childitem



This is because get-process notepad produces a "Process Object" which has a property called path. When that object gets sent to get-childitem, get-childitem has a parameter called path and PowerShell links the two up and moves on.

The last couple options are pretty self explanatory, but worth mentioning. You get interactive help for free, just by declaring the HelpMessage string, and you can do all kinds of validations on the input. Here I have specified a range of valid numbers for the Number of CPU's, so someone doesn't try to create a VM with 197 processors.

It is truly amazing how much plumbing that the PowerShell engine does that we can use for free. Its gonna be awesome. Oh yeah, and then distributing and sharing these things within the community is going to be orders of magnitude easier with the advent of modules.

Comments (1) -

Appreciate the info guys, thanks

Comments are closed