March 21st, 2012

Avoid PowerShell Errors by Initializing Variables

Doctor Scripto
Scripter

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Set-StrictMode Windows PowerShell cmdlet to aid in detecting uninitialized variables.

Microsoft Scripting Guy, Ed Wilson, is here. Charlotte, North Carolina is alive with color this morning. There is a blue jay sitting on the light post at the end of the driveway, and a cardinal munching on our newly sewn grass seed in the front yard. The various bushes, trees, and shrubs are blooming in the neighborhood. But the chief color right now is the yellowish-green color of the pollen from all the tall willowy southern pines. These evergreens guarantee color all year long; although right now, their chief contribution is the color of pollen. It will be this way for the next few weeks. The rain yesterday knocked it from the air, and left it on the grass, the drive, and the sidewalks of our neighborhood. The Scripting Wife promptly closed the windows and turned on the air conditioner. Me? The pollen does not bother me too badly, so I prefer to sit on the lanai with my laptop, the ceiling fan, a cup of English Breakfast tea, and a freshly baked blueberry scone.

That’s the nice thing about wireless—I can now work the way I prefer to work instead of being tied to a within 10 feet of a LAN drop. Beyond peaceful coexistence with my feathered friends, there is another reason I am sitting on the lanai…I am looking for the cable truck because my Internet connection suddenly dropped off this morning while I was checking my email. This is a real shame because I am missing a meeting I really wanted to attend. Oh well. At least I have my Windows7 phone. (Disclaimer: my employer, the Microsoft Corporation, bought me a Windows7 phone. They did not buy the Windows7 phone that the Scripting Wife uses, but she had to have one after she saw how cool my phone was.) So I can keep in touch with all the members of my team—in fact, I used it to look up the support phone number of my ISP.

The problem of uninitialized variables

One of the cool things about writing Windows PowerShell scripts (indeed, writing most scripting languages) is that you can quickly whip up a bit of code to solve problems. Some languages make this easier than others, some are quite verbose, and others are rather terse, but one advantage of scripting is that it permits rapid development.

This advantage is also a disadvantage. It permits bad habits. As long as you are aware of the bad habits and their attendant consequences, you can use this to your advantage. After all, the goal is to quickly solve a problem. But every so often, these bad habits can cause horrible consequences. This situation usually occurs when an impending deadline is rapidly barreling down the track, and the svelte one-liner has morphed into a 550-line FrankenScript. Having stood at the end of a darkened tunnel with a single light looming large upon my countenance whilst frantically attempting to unravel a mess of spaghetti code, I decided to embark upon a quest for Windows PowerShell best practices (indeed, that was one reason for my book). 

In the script that follows, the value of the $a variable increments five times each time the script runs. This is because the value of $a is never initialized.

UnitializedVariable.ps1

1..5 | foreach{

 $a++}

$a

The result of running this script three times is shown in the image that follows.

Image of script

The problem with such a script, especially when it is run from within the Windows PowerShell ISE, is that the initial value of $a changes each time the script runs. Therefore, you never know the final value of the $a variable. If you are counting something like running processes, stopped services, or errors in a particular event log, it is difficult to know what the expected value might be; and therefore, it is easy to let the error slip by undetected.

Detecting and solving the problem of uninitialized variables

The easiest way to detect the problem of uninitialized variables is to use the Set-Strictmode cmdlet. To do this, add the command at the top of the script. One of the great things about the Set-Strictmode cmdlet is that it only affects the current scope and all child scopes (as opposed to using the older Set-PSDebug –strict command, which affects the global scope).

When it is added, the Set-Strictmode cmdlet detects uninitialized variables and generates an error. The Set-Strictmode cmdlet does this whether the value of the Version parameter is 1, 2, or Latest. The following code shows adding the Set-StrictMode cmdlet to the top of the previous script.

Set-StrictMode -Version 1

1..5 | foreach{

 $a++}

$a

 Image of script

Use the version to apply the right amount of protection

It is important to keep in mind what –Version 1 and -Version 2 check for in strict mode. -Version 1 checks for uninitialized variables. See yesterday’s blog, Use Strict Mode for PowerShell to Help You Write Good Code, for a discussion of the -Version 2 checks.

Correcting the problem of the uninitialized variable requires declaring the variable and assigning a value to it. This technique is shown here.

InitializedVariable.ps1

Set-StrictMode -Version 1

$a = 0

1..5 | foreach{

 $a++}

$a

Now when the script runs, the correct value returns. This is shown in the following image.

Image of script

One thing to keep in mind about uninitialized variables and using Set-StrictMode and –Version 1, is that while it will detect an uninitialized variable that is directly accessed, it permits access to an uninitialized variable within a string. For example, when I use the Set-StrictMode cmdlet to set strict mode -Version 1, an error occurs when directly accessing an uninitialized variable. This technique is shown here.

Set-StrictMode -Version 1

$a

However, if I attempt to access the value of the variable from within an expanding string, no error generates. This technique is shown here.

“the value of `$a is $a”

The previous commands and their associated output are shown in the image that follows.

Image of command output

If accessing an uninitialized variable from within a string is a problem, the answer is to use Set-StrictMode –Version 2. When I set strict mode -Version 2, uninitialized variables within strings also generate an error. The command is shown here.

Set-StrictMode -Version 2

When set, both of the two commands that follow generate errors.

$a

“the value of `$a is $a”

The previous commands and their associated output are shown in the image that follows.

Image of command output

Join me tomorrow for more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.