Every programming language has it’s idiosyncrasies, and sometimes it seems like language authors go out of the way to be different. Enough that a seasoned polyglot can benefit from a cheat sheet for keeping track of even the simplest things like if/then/else syntax (elif? elsif? elseif? else if?).

Coming from a bash/Perl background, I am beginning to like Windows PowerShell. The object pipeline capability brings the familiarity of Unix pipes with a more modern object-oriented approach. But you must take the bad with the good, and there is some bad. There is a special hell reserved for the developer of this particular ‘feature’ that I was wrestling with today…

Purely from a readability standpoint, one would think the following code snippet should be just fine:

##Modules
Import-Module ActiveDirectory
$Domain = Get-ADDomain

Param (
[String][Parameter(Mandatory=$True)] $GroupName,
[String][Parameter(Mandatory=$False)] $SearchBase=$Domain.DistinguishedName,
[String][Parameter(Mandatory=$False)] $MailServer="mail.$($Domain.DNSRoot)",
[Parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)] $Args
)

As sensical as it may appear, it won’t run. The error message is a puzzling “left hand side” assignment complaint on the contents within the Param block.

The fix? The Param block has to be the absolute first line of code. How this corresponds to a left-hand-side error is beyond me. C’mon, how about a more decipherable error? If Param needs to be first, why not just say so?!!

But the problem with the ‘fix’, is that now what makes syntactic sense doesn’t necessarily make execution sense:

Param (
[String][Parameter(Mandatory=$True)] $GroupName,
[String][Parameter(Mandatory=$False)] $SearchBase=$Domain.DistinguishedName,
[String][Parameter(Mandatory=$False)] $MailServer="mail.$($Domain.DNSRoot)",
[Parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)] $Args
)

##Modules
Import-Module ActiveDirectory
$Domain = Get-ADDomain

Here we have a Param block with default values that are dependent upon a module that hasn’t yet been loaded. That would seem to be an indeterminate value condition, and, in my tests, that proves to be true. Sometimes the script runs fine, others the “$($Domain.<property>)” results in a blank.

The only way I could make it work consistently was through a much more explicit and verbose version:

Param (
[String][Parameter(Mandatory=$True)] $GroupName,
[String][Parameter(Mandatory=$False)] $SearchBase,
[String][Parameter(Mandatory=$False)] $MailServer,
[Parameter(Mandatory=$False,Position=0,ValueFromRemainingArguments=$True)] $Args
)

##Modules
Import-Module ActiveDirectory
$Domain = Get-ADDomain

If ($SearchBase -eq "") {
$SearchBase = $Domain.DistinguishedName
}
If ($MailServer -eq "") {
$MailServer = "mail.$($Domain.DNSRoot)"
}

Not sure why things are the way they are, but for a relative PowerShell novice, it was very frustrating. I’m sure there are better ways to do what I needed, so I am open to suggestions.

Share/Bookmark