Thursday, 20 March 2014

Finding an Alternative to Is- and Has- in PowerShell

I’ve been playing with PowerShell script modules as a way of factoring out a load of boilerplate PowerShell code into a re-usable library. These functions generally revolve around error handling, logging and command-line parsing at the moment. One issue I quickly ran into was the Import-Module call failing with a warning about badly named functions:-

WARNING: Some imported command names include unapproved verbs which might make them less discoverable. Use the Verbose parameter for more detail or type Get-Verb to see the list of approved verbs.

Whilst I was sort of aware that there were a standard set of verbs in PowerShell I haven’t really paid that much attention to the practice as most of my scripts are standalone. Naturally the usage of a PowerShell module implies code-sharing and so I can see why the warning exists. It also forces me to re-evaluate my laziness.

Is- and Has- Verbs

I started by Googling what the standard verbs were and discovered that in a few cases they explicitly provide alternatives (e.g. Search instead of Locate), but there was no PowerShell Thesaurus to help me understand what I should be using in place of the Is-Xxx and Has-Xxx functions I’d written. As an example here is the original function I wrote for detecting if the user has provided a specific command line switch:-

function Is-SwitchSet($options, $switch)
{
    if ( $options | where { $_ -eq $switch }  )
    { $true } else { $false }
}

if (Is-SwitchSet($args, ‘--help’))
{
    . . .
}

I originally played around with the naming and ended up with Has-Switch as that seemed shorter and closer, but I was still aware it wasn’t right because at the time I didn’t know of any other cmdlets that started Is- or Has-.

Noun-Verb versus Verb-Noun

As an aside I think what makes this more difficult is that the naming convention in PowerShell is the reverse of what you’d do in an object-orientated language like C++ or C#. Given that I’ve been doing that for close to 20 years its a hard habit to break. For example, in PowerShell, I always want to write Path-Exists, which would became Exists-Path, which is wrong (on many levels) but also exactly how you’d write it in a batch file.

C# PowerShell
Path.Combine Join-Path
Path.Exists Test-Path

Set Membership

I started looking for the closest verb that I felt would be appropriate by scanning the list from Get-Verb. I was expecting to see something in the Data category related to set membership - some kind of verb relating specifically to existence / containment but I didn’t see anything. There is Find, Search and Get but all these return an object and I just want to return a boolean value indicating its presence or absence. In the Lifecycle category there is Assert and Confirm, but Assert-SwitchExists or Confirm-SwitchExists doesn’t sound right either.

Obviously I noticed early on that the equivalent of the Path.Exists() method was the Test-Path cmdlet. It seems like the only candidate that might be expected to provide a boolean response but its categorisation in the Diagnostics section makes it feel more heavyweight to me than a simple existence check in a container. I know these are only guidelines but if the point of standardising the verbs is to make them more discoverable then I don’t see Test-Switch really works and Test-SwitchExists just feels like a tautology.

Conclusion

In the end I felt dissatisfied with all the alternatives and so I just appended a “-WarningAction SilentlyContinue” to the Import-Module statement to make the warning go away, for now. I’m sure I’m missing something obvious here and I just need to play with the (English*) language a bit more, or perhaps I’m not “getting” the (PowerShell) language and should just expect the user to rely on a boolean conversion from the result of using Where-Object?

[*] Despite it supposedly being my native language I’m under no illusion that I know how to weald it correctly.