Summary: Ed Wilson, Microsoft Scripting Guy, talks about understanding Windows PowerShell debugging.
Microsoft Scripting Guy, Ed Wilson, is here. Today I am working a little bit on my presentation for the Atlanta TechStravagenza that will be held at the Georgia Tech Research Institute Conference Center in midtown Atlanta on Friday August 21, 2015. It is not going to be held at the Microsoft Office this year, because the event has simply grown too large for the facilities. It will be an absolutely awesome day, and I look forward to seeing Mark Minasi and others who will be there.
As Debugging Week continues, I want to talk about the extremely powerful and flexible debugger that is built into Windows PowerShell.
Debugging the script
The debugging features of Windows PowerShell make working with a troubled script relatively painless. When you are more familiar with the debugging features of Windows PowerShell, you may decide that it becomes your go-to tool for troubleshooting.
Several cmdlets enable debugging from the Windows PowerShell console and from the Windows PowerShell ISE. The Windows PowerShell debugging cmdlets are shown in the following table.
Cmdlet name | Cmdlet function |
Set-PSBreakpoint | Sets breakpoints on lines, variables, and commands |
Get-PSBreakpoint | Gets breakpoints in the current session |
Disable-PSBreakpoint | Turns off breakpoints in the current session |
Enable-PSBreakpoint | Re-enables breakpoints in the current session |
Remove-PSBreakpoint | Deletes breakpoints from the current session |
Get-PSCallStack | Displays the current call stack |
Setting breakpoints
The debugging features in Windows PowerShell use breakpoints. A breakpoint is something that is very familiar to developers who have used products such as Microsoft Visual Studio. But for many IT professionals without a programming background, the concept of a breakpoint is somewhat foreign.
A breakpoint is a place in the script where you would like the script to pause. You control where the breakpoint will occur instead of halting on each line of the script, so stepping through the code is much faster. In addition, because many methods for setting breakpoints are available, you can tailor your breakpoints to reveal precisely the information you are looking for.
Setting a breakpoint on a line number
To set a breakpoint, you use the Set-PSBreakpoint cmdlet. The easiest way to set a breakpoint is to set it on line 1 of the script. To set a breakpoint on the first line of the script, you use the –Line parameter and the –Script parameter.
When you set a breakpoint, an instance of the System.Management.Automation.LineBreak .NET Framework class is returned. It lists the ID, Script, andLine properties that were assigned when the breakpoint was created:
PS C:\> Set-PSBreakpoint -line 1 -script C:\fso\BadScript.ps1
ID Script Line Command Variable Action
-- ------ ---- ------- -------- ------
0 BadScript.ps1 1
After a breakpoint is set, the next time the script runs, it causes the script to break into the code immediately. You can then step through the function in the same way you did using the Set-PSDebug cmdlet with the –Step parameter.
When you run the script, it stops at the breakpoint that was set on the first line of the script, and Windows PowerShell enters the script debugger, permitting you to use the debugging features of Windows PowerShell.
Windows PowerShell will enter the debugger every time the BadScript.ps1 script is run from the C:\fso folder. When Windows PowerShell enters the debugger, the Windows PowerShell prompt changes to [DBG]: PS C:\>>> to visually alert you that you are inside the Windows PowerShell debugger.
To step to the next line in the script, you type s. To quit the debugging session, you type q. (The debugging commands are not case sensitive.)
This technique is shown here:
PS C:\> Set-PSBreakpoint -Line 1 -Script C:\fso\BadScript.ps1
ID Script Line Command Variable Action
-- ------ ---- ------- -------- ------
4 BadScript.ps1 1
PS C:\> C:\fso\BadScript.ps1
Hit Line breakpoint on 'C:\fso\BadScript.ps1:1'
At C:\fso\BadScript.ps1:43 char:1
+ $num = 0
+ ~~~~~~~~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:44 char:1
+ SubOne($num) | DivideNum($num)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:22 char:1
+ {
+ ~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:23 char:2
+ $num-1
+ ~~~~~~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:24 char:1
+ } #end function SubOne
+ ~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:37 char:1
+ {
+ ~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:38 char:2
+ 12/$num
+ ~~~~~~~
[DBG]: PS C:\>> s
Attempted to divide by zero.
At C:\fso\BadScript.ps1:38 char:2
+ 12/$num
+ ~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
At C:\fso\BadScript.ps1:39 char:1
+ } #end function DivideNum
+ ~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:45 char:1
+ AddOne($num) | AddTwo($num)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:12 char:1
+ {
+ ~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:13 char:2
+ $num+1
+ ~~~~~~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:14 char:1
+ } #end function AddOne
+ ~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:17 char:1
+ {
+ ~
[DBG]: PS C:\>> s
At C:\fso\BadScript.ps1:18 char:2
+ $num+2
+ ~~~~~~
[DBG]: PS C:\>> s
2
At C:\fso\BadScript.ps1:19 char:1
+ } #end function AddTwo
+ ~
[DBG]: PS C:\>> s
PS C:\>
Remember that breakpoints depend on the location of the specific script when you specify a breakpoint in a script. When you create a breakpoint for a script, you specify the location. Often, I have several copies of a script that I keep in different locations (for version control). At times, I get confused in a long debugging session, and may open up the wrong version of the script to debug it. This will not work.
If the script is identical to another in all respects except the path to the script, it will not break. If you want to use a single breakpoint that could apply to a specific script that is stored in multiple locations, you can set the breakpoint for the condition inside the Windows PowerShell console, and not use the –Scriptparameter.
Debugging Week will continue tomorrow when I will talk about more cool 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