Effective PowerShell Item 5: Use Set-PSDebug -Strict In Your Scripts – Religiously

Windows PowerShell is like most dynamic languages in that it allows you to use a variable without declaring its type and without having assigned to it.  This is handy for interactive use, you can do stuff like this:

PS C:\Temp> Get-ChildItem | Foreach -Process {$sum += $_.Name.Length} -End {$sum}

Here $sum isn’t a defined variable and yet we are adding a value to it and assigning to it.  PowerShell just assumes a value of $null and coerces that 0 in the case above.  Try this at the prompt:

PS C:\Temp> $xyzzy -eq $null
True

It is not likely that this variable is already defined somewhere.  Of course we could verify that like so:

PS C:\> Test-Path Variable:\xyzzy
False

and indeed it isn’t defined.  So what has this to do with using Set-PSDebug -Strict in scripts – religiously?  Well, once you get burned by an unfortunate typo that takes time to notice and time to track down, you will want a way to avoid repeating that mistake.  Take this script for example:

$Suceeded = test-path C:\ProjectX\Src\BuiltComponents\Release\app.exe

if ($Succeeded) {
    … <archive bits, label build, etc>
}
else {
    … <email team that build failed, etc>
}

This script has a problem with it that PowerShell won’t tell you about.  It will happily indicate that every build fails even though that may not be true.  This is all because of a minor typo where I misspelled $Succeeded when testing the path.  In this snippet, the typo may be obvious to you but when you have a several hundred line script file, typos aren’t always so obvious. 

You can prevent this particular problem from ever happening by placing Set-PSDebug -Strict at the top of your script file just after the param() statement (if any).   For example, given this script as FOO.PS1:

Set-PSDebug -Strict

$Suceeded = test-path C:\ProjectX\Src\BuiltComponents\Release\app.exe

if ($Succeded) {
    "yeah"
}
else {
    "doh"
}

PS C:\Temp> .\foo.ps1
The variable $Succeded cannot be retrieved because it has not been set yet.
At C:\Temp\foo.ps1:6 char:14
+ if ($Succeded) <<<<  {

What would have happened if we had omitted the Set-PSDebug -Strict invocation?  This script would have output "doh".  NOTE: that in some cases we may need to initialize a variable in order to avoid the error above.  This is a small price to pay to avoid this sort of problem.  BTW the title of this post was perhaps a bit "over the top".  There may very well be times not to use Set-PSDebug -Strict in your scripts.  As always, use your judgment.  There you have it.  A simple way to avoid a major headache with debugging large scripts.

Advertisements
This entry was posted in Effective PowerShell. Bookmark the permalink.

5 Responses to Effective PowerShell Item 5: Use Set-PSDebug -Strict In Your Scripts – Religiously

  1. Stephen says:

    While this does help your script, it doesn\’t seem to go out of scope.  For example PowerTab no longer works after doing this in a script.  You also get an error if you type a undefined variable at the command prompt after running a script that contains the -strict command.  If I run "Set-PSDebug -Off", then everything works as expected.
     
    Right now I wouldn\’t recommend using -Strict.
     
    Thanks

  2. Keith says:

    Yeah that is a downside.  However after having spent way too many hours debugging dumb mistakes that Set-PSDebug -Strict would have caught.  I can live with that downside.  It is easy to rectify.  🙂

  3. Chris says:

    I realise I’m coming very, very late to this one, but in case anyone stumbles across this like I did, one possible way round Stephen’s problem is to use ‘set-strictmode’ as an alternative, which explicitly states that it “affects only the current scope and child scopes, so you can use it in a script or function without affecting the global scope”.

  4. JohnC says:

    How can I trap a non-existent parameter sent to a function? Neither Set-PSDebug -Strict nor Set-StrictMode -Version Latest seems to do that.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s