Ever since I found out about PowerShell’s extensible type system, I’ve been in love with it. The ability to add methods and properties to existing .NET types is just too cool. For example, I’ve added a CanPing() method to the String type. Whenever I have a variable containing an address:
[string]$computer = “Server2”
I can quickly see if it’s pingable or not:
$computer.CanPing()
Very cool. However, I was confused about two points: First, I was under the impression that all type extensions had to go in the types.ps1xml file that comes with PowerShell. Second, I was a bit confused on when it was appropriate to add a method to a type, and when you should instead be creating a whole new cmdlet (or function, or whatever). PowerShell architect Jeffrey Snover to the rescue! I passed along my two uncertainties and he had great responses.
First – silly me – you can actually load any .ps1xml file as a type extension, so you can leave Microsoft’s default one alone and create your own. Simply run:
Update-TypeData MyExtensions.ps1xml
And poof, your custom types are available. So that’s very cool – you can actually organize your custom types into multiple files and share them with your friends and family. Or co-workers. Whatever.
For my second question – should I use a method in an extended type, or an all-new cmdlet? – Snover had another great answer. There’s no hard-and-fast rule, but there are some great guidelines. He suggested that a cmdlet be used whenever you’re dealing with a collection, or a list of objects; a method is, by it’s nature, designed to act against only a single object.
So, if I made a Ping-Address cmdlet (Ping is an officially-allowed verb for cmdlets according to the SDK), that cmdlet coudl accept a collection of addresses to ping, and return a collection of results (perhaps just the objects which were pingable successfully). A CanPing() method, on the other hand, would only work against a single address – the one contained in the instance of String that the method was working against.
Cmdlets have some other advantages – they can have help, for example, and they support PowerShell’s ubiquitous parameters. They can use the -whatif and -confirm parameters if they’re taking potentially harmful actions. So if you want to include those features, a cmdlet is the best choice.
Part of my second question came from the PowerShell Community Extensions project at http://www.codeplex.com/Wiki/View.aspx?ProjectName=PowerShellCX, which is including a Split-String cmdlet. I had some concerns about that, because it essentially duplicates the functionality in the String type’s built-in Split() method. I’m still coming down in favor of the method, not a cmdlet, for this one. First, “Split” isn’t an “official” PowerShell cmdlet verb, and while that list of official verbs isn’t hard-and-fast, I’m trying to stick with it for any cmdlets I design. Second, I can’t picture a lot of instances where Split-String would operate against multiple sets – in other words, where you’d pass in multiple delimited strings and get back multiple resulting arrays. I’m used to Split() (the method) taking a single delimited string and returning a single array, and that fits that way I’d use the functionality most. Because splitting a string isn’t an especially harmful action, there’s little reason to support -whatif or -confirm arguments, making another argument for a method rather than a cmdlet.
But that’s not to ding the folks working on the Community Extensions! They may have entirely other ideas about how string splitting is used and a cmdlet might be the perfect format for the functionality they’re after. Certainly, it’s nice just to see someone working on extensions like this for PowerShell!
All in all, it’s good to have these kinds of tips as PowerShell begins its new life, to help make its usage and future development more consistent for everyone.