Use the PowerShell Debugger to Troubleshoot Scripts

Use the PowerShell Debugger to Troubleshoot Scripts

  • Comments 8
  • Likes

Summary: Learn how to use the Windows PowerShell script debugger to troubleshoot problems with scripts.

 

Microsoft Scripting Guy Ed Wilson here. One of the fun things about traveling, especially to warm places when it is winter back home, is calling to talk to friends and relatives. When they say things like, “It snowed yesterday,” I grimace a little and reluctantly tell them it was 70 degrees Fahrenheit (21 degrees Celsius according to my unit conversion module) in sunny Southern California. But the best thing is getting to work with customers and talking to people about Windows PowerShell.

Invariably, when I am talking to people about writing Windows PowerShell scripts, someone comes up with the question about script debugging. To be honest, I rarely fire up a debugger. Never have, even back in the VBScript days. I generally write code in such a way that when a problem occurs, it is obvious where the problem lies and how to correct it. Every once in a while, however, the problem is not obvious, and being able to actually debug the script comes in helpful.

In Windows PowerShell 2.0, we introduced several Windows PowerShell cmdlets that make it easier to debug scripts. Today, I want to spend a little time looking at some of the things to do with one of the cmdlets.

Debugging a Windows PowerShell script often involves setting a breakpoint, which is something that causes the Windows PowerShell script to pause execution. When the script pauses execution, the Windows PowerShell console drops into debug mode. This special mode permits the use of certain commands. The commands appear in the table that follows (this table is copied from my Microsoft Press book, Windows PowerShell 2.0 Best Practices book).

Keyboard shortcut

Command name

Command meaning

s

Step-into

Executes the next statement and then stops.

v

Step-over

Executes the next statement, but skips functions and invocations. The skipped statements are executed, but not stepped through.

o

Step-out

Steps out of the current function up one level, if nested. If in the main body, it continues to the end or the next breakpoint. The skipped statements are executed, but not stepped through.

c

Continue

Continues to run until the script is complete or until the next breakpoint is reached. The skipped statements are executed, but not stepped through.

l

List

Displays the part of the script that is executing. By default, it displays the current line, five previous lines, and 10 subsequent lines. To continue listing the script, press Enter.

l <m>

List

Displays 16 lines of the script beginning with the line number specified by <m>.

l <m> <n>

List

Displays <n> lines of the script, beginning with the line number specified by <m>.

q

Stop

Stops executing the script, and exits the debugger.

k

Get-PsCallStack

Displays the current call stack.

<Enter>

Repeat

Repeats the last command if it was Step-into (s), Step-over (v), or List (l). Otherwise, represents a submit action.

h or ?

Help

Displays the debugger command Help.

 

There are several ways to configure breakpoints. For the next several examples, I am going to use the script that is shown here:

MyDebug.ps1

$cn = "localhost"

$process = "notepad"

Get-WmiObject -Class win32_bios -cn $cn

Start-Process $process

Get-Process $process

Keep in mind that the path to the script matters. I am going to set a breakpoint on a command on a script that appears in a specific location. If I run the script with the same name from a different location, the script will not break upon that command.

When the command Get-Process cmdlet appears, the script breaks and enters debug mode. In the code that follows, I use the Set-PSBreakpoint cmdlet to set the breakpoint on the Get-Process cmdlet for the script c:\fso\mydebug.ps1. The code and associated output are shown here:

PS C:\> Set-PSBreakpoint -Command get-process -Script C:\fso\mydebug.ps1

 

  ID Script                      Line Command                     Variable

  -- ------                      ---- -------                     --------

   0 mydebug.ps1                      get-process

Now, I execute the Windows PowerShell script. When the script hits the command Get-Process, it does not execute the command. Instead, it enters the debugger. I now have access to the commands listed in the table above.

I type the letter L to list the portion of the script that executes. By default, this displays the current line, five previous lines, and 10 subsequent lines. After examining the code, I decide to continue with script execution, and I press the letter C to continue running the script. In this example, it runs the Get-Process cmdlet, and ends the script, because the Get-Process cmdlet is the last line in the script. The setting of the breakpoint, launching of the script, using the L and the C commands in the debugger, and execution of the last line in the script are shown in the following figure.

I next decide to use the Set-PSBreakpoint cmdlet to set another breakpoint. This time, I break on a variable. The key thing to remember here is that when specifying a variable as a breakpoint, do not include the $ prefix; instead, use the variable name without the dollar sign. The command is shown here:

Set-PSBreakpoint -script c:\fso\mydebug.ps1 -Variable cn

When the script reaches the cn variable, it enters the debugger. I change the value assigned to the cn variable from “localhost” to “mred” and use the C command to continue execution of the script. After the script executes a couple lines of code, the script enters the second breakpoint—the breakpoint I first set on the Get-Process command. Once again, the script enters the debugger, and once again I use the C command to continue script execution. These commands and associated output are shown in the following figure.

Image of commands and associated output

Now, I decide to see how many breakpoints I have set. I use the Get-PSBreakpoint cmdlet:

Get-PSBreakpoint

The command and associated output are shown here:

PS C:\> Get-PSBreakpoint

 

  ID Script                      Line Command                     Variable

  -- ------                      ---- -------                     --------

   0 mydebug.ps1                      get-process

   1 mydebug.ps1                                                  cn

Now, I decide to get rid of all the breakpoints. To do this, I use the Get-PSBreakpoint cmdlet and pipe it to the Remove-PSBreakpoint cmdlet. Next, I use Get-PSBreakpoint to ensure I removed all the breakpoints. The commands and associated output are shown here:

PS C:\> Get-PSBreakpoint | Remove-PSBreakpoint

PS C:\> Get-PSBreakpoint

 

That is all there is to using a command to break into a script. Join me tomorrow when I will continue talking about debugging Windows PowerShell scripts.

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

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed,

    even if I prefer to have a GUI like the ISE when debugging a script, it is really good to know that the debugging capabilities are not restricted to GUI hosts.

    It is a bit more work to debug on the commandline, but it is a great feature that enables us to step through the script, examine the current context and inspect or change the state of the script on the fly.

    I think it is worth learning and typing a bit!

    Klaus.

  • [TYPO] "In the code that follows, I use the Set-PSBreakpoint cmdlet to set the breakpoint on the Get-Process cmdlet for the script c:\fso\psdebug.ps1."

    It should be c:\fso\mydebug.ps1.

  • I think it is worth mentioning that you can also set a break point by line-number.  In fact, this is the kind of breakpoint that will be set if you choose "Toggle Breakpoint" in the "Debug" menu of the ISE.

    Example:

    Set-PSBreakpoint -Line 3 -Script mydebug.ps1

    In the ISE, this will highlight the line with a brown background, the same as pressing F9 when on the beginning of that line.

  • @Klaus Schulte Yes, you are right debugging scripts from the command line in the PowerShell console can be very productive. It takes a bit of effort, but can be powerful. Thank you for your comment.

  • @Aleksandar Nikolic Thank you for your close reading of the post. I have corrected my typo. In addition, the Scripting Wife also found another typo ... I have fixed that one as well.

  • @BigTeddy :-) I cover setting breakpoints by line number, and using the debugger in the ISE on Thursday. But you are absolutely correct ... about setting breakpoints by line number ... in fact, I know lots of people that seem to set a breakpoint on line 1, and then they step through the code to do their debugging. It is quick, and effecient, and it works.

  • I am having a problem following this blog entry.

    I get an error when I execute the MyDebug.ps1 script even if I use the .\ format. The error is

    Suggestion [3,General]: The command MyDebug.ps1 was not found, but does exist in the current location. Windows PowerShel

    l doesn't load commands from the current location by default. If you trust this command, instead type ".\MyDebug.ps1". S

    ee "get-help about_Command_Precedence" for more details.

    It does open the Notepad window and does enter the debug mode if I have set that.

    What am i doing wrong?

  • Please ignore my comment.

    I was not familiar with your method of illustrating scripts and had included the MyDebug.ps1 as the first line. Doh!