My new favorite cmdlet: set-strictmode

If you’ve ever written Visual Basic or VB.Net code, you’re aware that it’s highly recommended that you use “Option Strict” in all of your code.  Similarly, Perl scripters have a “use strict” that comes highly suggested.

The idea of these options is that there’s quite a bit of flexibility built into these languages, and sometimes that flexibility backfires on you.  Using these options actually limits the flexibility of the languages in question in ways that help coders to keep from making certain types of mistakes in their code.  Writing code professionally in VB.Net (you may scoff, but it happens quite a lot) or Perl (it’s not my language of choice, but again, there’s a lot out there) without using these options is not a good idea at all.

I’ve been writing code in PowerShell for about 2 years, and have probably written about 10,000 lines, mostly code that’s used on a daily basis.  I’ve read several PowerShell books, online tutorials, and watched several webcasts.  I may have not been paying attention, but I’ve completely missed any emphasis on the analogous option in PowerShell, “set-strictmode”.  One of my co-workers asked if there was something like this in PowerShell, and I found it almost instantly.  Google, and the PowerShell help file both explain how the cmdlet works.  He and I started using it, and to our dismay, found dozens of errors in code that we had been trusting, in some case, for over a year.

First of all, let me explain that I’m not complaining that there’s not any information about how set-strictmode works in the “ecology” of the PowerShell community.  I’m confident that each book and tutorial explains how this cmdlet works.  What I’m concerned about is how I could have read as much as I have from as many people are talking about PowerShell without hearing anyone (or everyone) shouting at the top of their collective voices, “Add this to your profile…it will save you countless hours and tears in the long run”.  Hopefully, I’ve just missed it, and everyone has been saying this all along.  In case this has not been the case, let me say:

Add set-strictmode to your profile.

It will save you countless hours and tears in the long run.

So….how do I use set-strictmode, and what does it help with?  First, to turn on “strict mode” you need to decide which version of strictmode you want.  The options are:

Version Effect
1.0 References to uninitialized variables(except in a string) are errors
2.0
  • References to uninitialized variables(including in a string) are errors
  • References to undefined properties are errors
  • Calling a function using method-call syntax is an error
  • ${} (an un-named variable) is a syntax error
Latest Uses the most strict mode available for this version of PowerShell.  (Currently the same as 2.0)

I would advise that you use “set-strictmode –version Latest” in your profile.

Let’s look at the different restrictions.  First, if you’ve written any PowerShell scripts, you’re aware that you don’t have to declare your variables.  That’s a “good thing”, and strictmode 1.0 doesn’t change that in any way.  What it does do is make sure that you’re not retrieving values from variables you haven’t assigned anything to.  Here’s some sample code that strictmode will choke on.

$servername=read-host -prompt "Enter name of server"
$wmi=get-wmiobject -class Win32_Service -computername $server_name

This is a pretty simple example, but it’s almost certain that sooner or later you’ll typo a variable name in a script.  Strictmode will help keep you from getting in this kind of trouble.  With strictmode Version 1.0, you won’t be warned about using uninitialized variables in double-quoted string, e.g. “Server=$server_name”…(they’ll be replaced with $null).  Version 2.0 will cause references to uninitialized variablesinside strings to be an error as well.

Here’s an example of code that illustrates property restrictions in StrictMode 2.0.

$servername="Server123"
$length=$servername.lenght

I would write up an example of using the method-call syntax for a function, but Thomas Lee just blogged about this in his blog Under the Stairs.

The final “restriction” in strict mode 2.0 says that you can’t have a variable with no name.  The syntax ${varname} is a way of expressing $varname, when varname contains characters that are not generally allowed in variable names.  I haven’t ever had a really convincing use for this syntax (I’ve thought about using it to associate variables with filenames using the full path as the variable name, but it seems like a dictionary would be cleaner).

I should note that Lee Holmes has done a great thing in his recently published PowerShell Cookbook V2.  Each script in the cookbook starts with “set-strictmode –version Latest”.   In my opinion, this is a best practice.

If you’re just now hearing about set-strictmode for the first time, and already have a body of powershell scripts in your toolbox (I’m in this category), I’d recommend the following steps:

  1. Add set-strictmode –version Latest to the profile on the machine you do your script development on
  2. Add set-strictmode –version Latest  to any scripts you create from this time forward
  3. Add set-strictmode –version Latest to scripts that you have tested to make sure they comply with strictmode.

I’m going to avoid turning on strictmode on servers that I’m running PowerShell on for now, because I’m sure stuff will break.  I’m slowly refurbishing scripts as I run them on my development box and see the strictmode errors pop up, and since set-strictmode is a scoped change (if you set it in a script or function, it reverts to the old setting when you exit the script or function), I can take advantage of it in a script-by-script basis.

If you are just starting to build a PowerShell script library, I would recommend turning strictmode on in the profile on every machine that you run PowerShell scripts.  You’ll be glad you did.

Hopefully this was not too much of a rant.  Please let me know what experiences you’ve had with with set-strictmode.

Mike

3 Comments

  1. This doesn’t protect against this type of error:
    $myVariable = “first value”
    $myVaraible = “second value”
    $myVariable

    this prints first value — not the expected “second value”.

    When I found that psh couldn’t/wouldn’t enforce pre-declaration (like option explicit or use strict) I experienced my First Great Disillusionment with MS’ shiny new scripting (almost) language.

    ..mike..

    • It might be nice if there was a switch that required declarations (e.g. with new-variable) in the current scope. Nonetheless, set-strictmode does catch a lot of things that would get missed.

  2. Yea — set-strictmode is better than nothing, and I don’t want to sound ungrateful… but it seems to me to be such a fundamental component in an industrial strength scripting language and I’m surprised (grieved) to see it missing from PowerShell.
    ..mike..

Comments are closed.