Problem
You want to diagnose failures or unexpected behavior in a script interactively.
Solution
To generate debugging statements from your script, Use the WriteDebug cmdlet. If you want to step through a region carefully, surround it with SetPsDebug –Step calls. To explore the environment at a specific point of execution, add a line that calls $host.EnterNestedPrompt().
Discussion
By default, PowerShell allows you to assign data to variables you haven’t yet created (thereby creating those variables). It also allows you to retrieve data from variables that don’t exist—which usually happens by accident and almost always causes bugs. To help save you from getting stung by this problem, PowerShell provides a strict mode that generates an error if you attempt to access a nonexisting variable. Example 132 demonstrates this mode.
Example 132. PowerShell operating in strict mode
PS >$testVariable = "Hello" PS >$tsetVariable += " World" PS >$testVariable Hello PS >RemoveItem Variable:\tsetvariable PS >SetPsDebug Strict PS >$testVariable = "Hello" PS >$tsetVariable += " World" The variable $tsetVariable cannot be retrieved because it has not been set
yet. At line:1 char:14
+ $tsetVariable <<<< += " World"
For the sake of your script debugging health and sanity, strict mode should be one of the first additions you make to your PowerShell profile.
When it comes to interactive debugging (as opposed to bug prevention), PowerShell supports several of the most useful debugging features that you might be accustomed to: tracing (through the SetPsDebug –Trace statement), stepping (through the SetPsDebug –Step statement), and environment inspection (through the $host. EnterNestedPrompt() call).
As a demonstration of these techniques, consider Example 133.
Example 133. A complex script that interacts with PowerShell’s debugging features
############################################################################## ## ## InvokeComplexScript.ps1 ## ## Demonstrates the functionality of PowerShell's debugging support. ## ##############################################################################
WriteHost "Calculating lots of complex information"
$runningTotal = 0 $runningTotal += [Math]::Pow(5 * 5 + 10, 2)
WriteDebug "Current value: $runningTotal"
SetPsDebug Trace 1 $dirCount = @(GetChildItem $env:WINDIR).Count
SetPsDebug Trace 2 $runningTotal = 10 $runningTotal /= 2
SetPsDebug Step $runningTotal *= 3 $runningTotal /= 2
$host.EnterNestedPrompt()
SetPsDebug off
As you try to determine why this script isn’t working as you expect, a debugging session might look like Example 134.
Example 134. Debugging a complex script
PS >$debugPreference = "Continue" PS >InvokeComplexScript.ps1 Calculating lots of complex information DEBUG: Current value: 1225
Example 134. Debugging a complex script (continued)
DEBUG: 17+ $dirCount = @(GetChildItem $env:WINDIR).Count DEBUG: 17+ $dirCount = @(GetChildItem $env:WINDIR).Count DEBUG: 19+ SetPsDebug Trace 2 DEBUG: 20+ $runningTotal = 10 DEBUG: ! SET $runningTotal = '1215'. DEBUG: 21+ $runningTotal /= 2 DEBUG: ! SET $runningTotal = '607.5'. DEBUG: 23+ SetPsDebug Step
Continue with this operation? 24+ $runningTotal *= 3
[Y]
Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):y DEBUG: 24+ $runningTotal *= 3 DEBUG: ! SET $runningTotal = '1822.5'.
Continue with this operation? 25+ $runningTotal /= 2
[Y]
Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):y DEBUG: 25+ $runningTotal /= 2 DEBUG: ! SET $runningTotal = '911.25'.
Continue with this operation? 27+ $host.EnterNestedPrompt()
[Y]
Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):y DEBUG: 27+ $host.EnterNestedPrompt() DEBUG: ! CALL method 'System.Void EnterNestedPrompt()' PS >$dirCount
PS >$dirCount + $runningTotal 1207.25 PS >exit
Continue with this operation? 29+ SetPsDebug off
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):y DEBUG: 29+ SetPsDebug off
While not built into a graphical user interface, PowerShell’s interactive debugging features are bound to help you diagnose and resolve problems quickly.
For more information about the SetPsDebug cmdlet, type GetHelp SetPsDebug.