We’ve been working with PowerShell a lot lately for our new PeopleProvision application that automates the account and mailbox creation process in Active Directory and Exchange environments. We turned to PowerShell instead of using purely managed .NET code to take advantage of the great array of cmdlets built for working with Active Directory and Exchange. Many of Microsoft’s own products—especially MMC snap-ins like Active Directory Users and Computers as well as tools like the Exchange Management Console—use PowerShell on the back end to do work and we are adopting this model, too.
This post (and possibly future posts) addresses one of the many “quirks” that we have seen while working with PowerShell. Now don’t get me wrong here. I understand that PowerShell (sometimes abbreviated as POSH) was not created with developers in mind and instead is targeted at system administrators. However, I wanted to highlight some weird behaviors from a developer viewpoint to hopefully help some of you avoid many of the issues we’ve incurred.
Coming from a development background to PowerShell is difficult because of all the quirks in PowerShell. Nothing behaves like you would expect in a typical high-level programming language like C# or Java and it’s hard to understand the intentions of the language designers. You end up writing a lot of bad-practice defensive code just to get around the quirks of the language.
Case in point:
Cannot bind argument to parameter 'SomeParam' because it is an empty string or null.
What does this message mean? Why does this occur? Because you have a required string parameter and you pass a zero-length string or a null value to your script or function. Most run-times treat this exactly as you would expect: by passing the argument on through and letting the script or function deal with the parameter value, which might be a perfectly acceptable value or even a sentinel value. But PowerShell chokes on this and freaks out and won’t even call the script or function.
In the end, POSH feels a little too much like Visual Basic for my liking (no rub on you VB guys and gals…I have always had trouble with it coming from a C/C++ and Java/C# background where you have more control over exactly what your code does) and it seems like there are a lot of assumptions about what I might mean as a programmer. Here’s my thought: don’t make assumptions. If I pass an empty or null string to my POSH script or function then process it; don’t holler about parameter binding because you assume I need a non-null or greater-than-zero-length string. These values may be perfectly acceptable for me to work on and these parameter values work fine in languages like C# and Java.
To address this quirk, I have to rewrite my function parameter to *not* be required so that I can pass in a perfectly valid zero-length string. But I want the parameter to be required and accept a null or zero-length string. Not in PowerShell…sheesh!
Every language has nuances. It is the major contributor as to why there are so many different languages. In my opinion, version 2 has a lot of features that should have been in version 1. Things like Try/Catch, and Advanced Parameters.
When a parameter is set as required, it expects a value to be specified; however, you can specify AllowNull to pass a null value into the parameter. See about_Functions_Advanced_Parameters. There are a lot of parameter options that can be specified beyond the basics, which includes input validation.
Thanks for the feedback, Robert. You’re right: every language has its nuances and PowerShell is no different. The most difficult transition coming from languages like Java and C# is the set of assumptions made by the language designers and mapping those assumptions into the programming model we have in mind. I’m sure that C/C++ developers had the same challenges moving to Java and .NET languages, too. Where are my pointers? How the heck do you address memory? 😉
That’s very good insight on the parameter options and thanks for the tip. I’ll look at the full range of options in more detail so that I can hopefully avoid some of the more painful run-time errors caused by my ignorance of POSH.