Summary: Boe Prox uses the Set-PSDebug cmdlet to assist in troubleshooting.
Honorary Scripting Guy and Windows PowerShell MVP, Boe Prox, here today filling in for my good friend, The Scripting Guy. This is the second part in a series of five posts about troubleshooting Windows PowerShell scripts and functions. The series includes:
- Provide Support by Using Verbose and Debug Streams
- Troubleshoot by Using Set-PSDebug (this post)
- Enforce Better Script Practices by Using Set-StrictMode
- Trace Your Commands by Using Trace-Command
- Use the PowerShell Debugger
Today I am going to talk about using the Set-PSDebug cmdlet to assist in troubleshooting a script or function. This cmdlet provides some basic debugging capabilities and allows you to set up trace levels, depending on how you want to view the execution of a script or function. This is nice when you do not want to put together a lot of debug lines in your code. Besides that, you can track whether you are correctly assigning values to variables by using StrictMode.
First let’s take a look at the parameters that are available with Set-PSDebug and see what we can work with:
Get-Help Set-PSDebug
We have two parameter sets, one that supports turning off the debugging and another that allows us to turn on Strict mode, set a trace level, and the option to step through each line of the statement in the code.
Turning on Strict mode allows us to ensure that we are defining variables in our code. For a quick example, we can run the following code:
1..10 | ForEach {
$i++
}
$i
In this case (and assuming you have only run it once), the value of $i would be 10. The issue here is that we never actually defined the variable up front. Now let’s set up Strict mode by using Set-PSDebug and try this again to see what happens.
Remove-Variable i
Set-PSDebug -Strict
1..10 | ForEach {
$i++
}
$i
The variable $i cannot be retrieved because it has not been set.
At line:6 char:1
+ $i
+ ~~
+ CategoryInfo : InvalidOperation: (i:String) [], RuntimeExceptio
n
+ FullyQualifiedErrorId : VariableIsUndefined
I removed the variable after my last example to show that if you attempt to increment the variable before assigning it, it will throw an error message (in this case, up to 10) stating that the variable has not yet been defined. This is pretty useful if you want to make sure that you have defined all of your variables in your script or function.
I do not want to keep Strict mode enabled, so I will turn it off:
Set-PSDebug –Off
This not only turns off the Strict mode, but it will also turn off the other enabled properties, such as the trace level and stepping through each statement.
That was pretty cool. But now let’s dive into my favorite part about using Set-PSDebug: trace levels! This is where we can really see what is happening during the execution of the code. With Trace, we have the following options:
0 | Turn off script tracing. |
1 | Traces each line of code that is being executed. Non-executed lines are not displayed. |
2 | Traces each line of code that is being executed. Non-executed lines are not displayed. |
We already can tell that setting the trace level to 0 turns it off, so there really is no need to demo that piece. Instead, we will go into the first level, 1, and see what happens with the code when it is executed:
Set-PSDebug –Trace 1
Now let’s run some code to see what is displayed in the console.
## Traces
Function Test {
Param (
[int]$Value
)
$Value++
Write-Output $Value
}
Set-PSDebug -Trace 1
[int]$z=0
$Return = $Null
Get-ChildItem | Select -First 5 | ForEach {
If ($_.name -match '^p') {
$File = $_
$Return += ("{0} [{1}]`r`n" -f $File,(Test ($z++)))
}
}
$Return
The trace level has been set to 1, meaning that only the lines that are executed will be displayed on the console. With that, we can see each iteration of Get-ChildItem and sometimes we have calls to the Test function, which increments a counter before finally displaying the files we are expecting.
Pretty cool stuff! Now let’s up the trace level to 2 and see the output!
Set-PSDebug -Trace 2
[int]$z=0
$Return = $Null
Get-ChildItem | Select -First 5 | ForEach {
If ($_.name -match '^p') {
$File = $_
$Return += ("{0} [{1}]`r`n" -f $File,(Test ($z++)))
}
}
$Return
We see that variable assignments are now displayed on the console along with calls to functions and script blocks. The variable assignments really help to determine if the script is functioning the way it should.
That is all there is to using Set-PSDebug to help with troubleshooting scripts. Join me tomorrow when I discuss using Set-StrictMode.
We invite you to follow the Scripting Guy on Twitter and Facebook. If you have any questions, send email to the Scripting Guy at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Until then, see ya!
Boe Prox, Windows PowerShell MVP and Honorary Scripting Guy