Understanding PowerShell Script Debugging


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, and Line 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 –Script parameter.

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


Comments (0)

Skip to main content