More PowerShell Script Tracing and Strict Mode

Doctor Scripto

Summary: Ed Wilson, Microsoft Scripting Guy, talks more about Windows PowerShell script tracing and enabling strict mode.

Microsoft Scripting Guy, Ed Wilson, is here. It can be somewhat painful to troubleshoot intermittent errors with Windows PowerShell. Two things that can lead to this are variables that do not get initialized properly (and therefore their values change over subsequent running of the script) and functions that do not get accessed properly. To solve both of these problems, we can use Windows PowerShell cmdlets.

Yesterday in Tracing the Execution of a PowerShell Script, I introduced the tracing levels and discussed working with trace level 1. Today, I'll investigate working with trace level 2.

When the trace level is set to 2, each line in the script that executes is displayed in the Windows PowerShell console. In addition, each variable assignment, function call, and outside script call is displayed. These additional tracing details are prefixed with an exclamation mark to make them easier to see. When the -trace parameter from Set-PSDebug is set to 2, an extra line is displayed, indicating a variable assignment.

When I run the CreateRegistryKey.ps1 script (which I published yesterday), the function trace points first to the script, stating that it is calling a function called CreateRegistryKey.ps1. Calls to functions are prefixed with ! CALL, which makes them easy to see.

Windows PowerShell treats scripts as functions. The next function that is called is the Add-RegistryValue function. The trace also states where the function is defined by indicating the path to the file. This is shown here:

PS C:\> Set-PSDebug -Trace 2

PS C:\> C:\fso\CreateRegistryKey.ps1

DEBUG:    1+  >>>> C:\fso\CreateRegistryKey.ps1

DEBUG:     ! CALL function '<ScriptBlock>'

DEBUG:   30+  >>>> Add-RegistryValue -key forscripting -value test

DEBUG:     ! CALL function '<ScriptBlock>'  (defined in file

'C:\fso\CreateRegistryKey.ps1')

DEBUG:   12+  >>>> {

DEBUG:     ! CALL function 'Add-RegistryValue'  (defined in file

'C:\fso\CreateRegistryKey.ps1')

The ! SET keyword is used to preface variable assignments. The first variable that is assigned is the $scriptRoot variable:

DEBUG:     ! SET $scriptRoot = 'HKCU:\software\ForScripting'.
DEBUG:   15+  if( >>>> -not (Test-Path -path $scriptRoot))
DEBUG:   23+     >>>> Set-ItemProperty -Path $scriptRoot -Name $key -Value
$value | `
DEBUG:   27+  >>>> } #end function Add-RegistryValue
PS C:\>

When the CreateRegistryKey.ps1 script is run with trace level 2, the detailed tracing shown here is displayed:

Image of command output

Enabling strict mode

One easily correctable problem that can cause debugging nightmares in a script involves variables. Variables are often used incorrectly, are nonexistent, or are initialized improperly. An easy mistake to make when using variables is a simple typing error. Simple typing errors can also cause problems when they are contained in a large complex script.

Enabling strict mode causes Windows PowerShell to display an error if a variable is not declared. This helps you avoid the problem of nonexistent or improperly initialized variables.

Using Set-PSDebug -Strict

An example of a simple typing error in a script is shown in the SimpleTypingError.ps1 script:

SimpleTypingError.ps1

$a = 2
$b = 5
$d = $a + $b
'The value of $c is: ' + $c

When the SimpleTypingError.ps1 script is run, the following output is shown:

PS C:\> C:\fso\SimpleTypingError.ps1
The value of $c is:
PS C:\>

As you can see, the value of the $c variable is not displayed. If you use the -Strict parameter from the Set-PSDebug cmdlet, an error is generated. The error tells you that the value of $c has not been set:

PS C:\> Set-PSDebug -Strict

PS C:\> C:\fso\SimpleTypingError.ps1

The variable '$c' cannot be retrieved because it has not been set.

At C:\fso\SimpleTypingError.ps1:13 char:26

+ 'The value of $c is: ' + $c

+                          ~~

    + CategoryInfo          : InvalidOperation: (c:String) [], RuntimeExceptio

   n

    + FullyQualifiedErrorId : VariableIsUndefined

When you go back to the SimpleTypingError.ps1 script and examine it, you can see that the sum of $a and $b was assigned to $d, not $c. The way to correct the problem is to assign the sum of $a and $b to $c instead of $d (which was probably the original intention).

It is possible to include the Set-PSDebug -Strict command in your scripts to provide a quick check for uninitialized variables while you are actually writing the script. You can therefore avoid the error completely.

If you routinely use an expanding string to display the value of your variables, you need to be aware that an uninitialized variable is not reported as an error. The SimpleTypingErrorNotReported.ps1 script uses an expanding string to display the value of the $c variable.

The first instance of the $c variable is escaped by the use of the backtick character ( ` ). This causes the variable name to be displayed, and does not expand its value. The second occurrence of the $c variable is expanded. Here is the line of code that does this:

"The value of `$c is: $c"

When the SimpleTypingErrorNotReported.ps1 script is run, the following is displayed:

PS C:\> Set-PSDebug -Strict

PS C:\> C:\fso\SimpleTypingErrorNotReported.ps1

The value of $c is:

PS C:\>

The complete SimpleTypingErrorNotReported.ps1 script is shown here:

SimpleTypingErrorNotReported.ps1

$a = 2
$b = 5
$d = $a + $b
"The value of `$c is: $c"

To disable strict mode, you use the Set-PSDebug -off command.

Now you know how to use trace level 2 and strict mode in a Windows PowerShell script. Debugging Week will continue tomorrow when I will talk about more cool debugging 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

0 comments

Discussion is closed.

Feedback usabilla icon