Use the PowerShell Debugger to Check Variable Values

Use the PowerShell Debugger to Check Variable Values

  • Comments 6
  • Likes

Summary: Learn how to inspect variable values by using the Windows PowerShell debugger.

 

Microsoft Scripting Guy Ed Wilson here. In yesterday’s post, I talked about using the Set-PSBreakpoint cmdlet to set a breakpoint on a specific script. Today, I want to continue looking at the Set-PSBreakpoint cmdlet.

One of the things I mentioned was that when setting a breakpoint on a script, the script specified must be the same script that breaks. For example, if I set a breakpoint for the c:\fso\mydebug.ps1 script, the only script that breaks when a breakpoint reaches is the c:\fso\mydebug.ps1 script. This is the exact script, from the exact location.

If, on the other hand, I do not specify the script when I create the breakpoint, any script I run causes the breakpoint to trigger. To test this out, I create a script with several commands in it. The script is shown here:

Get-Process.ps1

Get-EventLog application -Newest 1

get-process powershell

Get-Date

I also use the test script from yesterday. The mydebug.ps1 script is shown here:

MyDebug.ps1

$cn = "localhost"

$process = "notepad"

Get-WmiObject -Class win32_bios -cn $cn

Start-Process $process

Get-Process $process

I use the Set-PSBreakpoint cmdlet to create a breakpoint that will break when the command Get-Process appears in a script. The command and associated output are shown here:

PS C:\> Set-PSBreakpoint -Command get-process

 

  ID Script                      Line Command                     Variable

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

   1                                  get-process

 

 

PS C:\>

When the Get-Process command from the MyDebug.ps1 script appears, the debugger breaks into the script. This allows for the use of debugging commands (the commands appear in a table from yesterday’s article). The C command tells the debugger to continue. In the Get-Process.ps1 script, the script also contains a call to Get-Process, so that script causes the breakpoint to break as well. These two scripts and the associated output including debugger are shown in the following figure.

Image of two scripts and associated output including debugger

One of the really cool things to do with a breakpoint is to specify an action to take when a condition occurs. The action to occur is placed inside a scriptblock. In the following command, I specify that when the Get-Process command appears, the debugger will start the notepad process:

Set-PSBreakpoint -Command get-process -Action {notepad}

I modify the Mydebug.ps1 script so that I comment out the Start-Process line. The revised script is shown in the following figure.

Image of modified Mydebug.ps1 script

When run, the script generates an error because it attempts to use Get-Process to retrieve a nonexistent process. In the breakpoint previously specified, however, when the breakpoint is reached, the scriptblock creates the notepad process, so the script works without causing an exception. This is shown in the following figure.

Image of script working without causing an exception

When debugging a script, often I am concerned about the value of a variable. There are three ways to break on a variable. The three ways are read, write, and readwrite. The default value is write. When working with breakpoints on variables, read or write do not talk about the way the variable is declared in the script, but each determines when the script breaks. For example, when breaking on a variable in write mode, it means the script breaks before a new value is written to a variable. In the case of a variable that is not yet declared, the script breaks just before a value is written or assigned to the variable. I used the code that follows to set a breakpoint on the variable cn when a value is written to the variable:

Set-PSBreakpoint -Variable cn -Mode write

I run the script, and the script breaks before the value “localhost” is assigned to the $cn variable. I then check the value of the $cn variable; nothing is displayed because the variable has not been created. Next, I use the L command to see the code, and I see the script is on the first line, waiting to assign a value to the $cn variable. I then use the C command, and continue execution of the script. The error is generated because I have commented out the Start-Process command (this can be seen in the code listing from the previous command).

Image of generated error

In the following figure, I run the C:\fso\debug.ps1 script. The script hits the $cn variable breakpoint and breaks into the script. I check the value of the $cn variable and see it has not been set; thereforem nothing returns. I then assign the value mred to the $cn variable, and I use the L command to view the code. Next, I use the S command to step to the next line in the script. I see that it sets the value notepad for the $process variable. I then step (S) to the next line in the script where I see that it will make a WMI call to retrieve BIOS information via the Win32_BIOS WMI class. I then step past that (S) and see that the script is getting ready to retrieve process information about the notepad process. However, Notepad is not running because the Start-Process command is commented out. I therefore type Start-Process $Process and then step into the remainder of the script.

Image of running the C:\fso\debug.ps1 script

When I break on a variable in read mode, the value of the variable has already been read. This means I can inspect the value of the variable to ensure the script works as intended. In the code that follows, I remove all the current breakpoints, and then I create a new breakpoint that watches the variable $cn to see when it reads the value of the variable. When the value of the $cn variable is read, the script breaks and enters the debugger:

Get-PSBreakpoint | Remove-PSBreakpoint

Set-PSBreakpoint -Variable cn -Mode read

When I query the value of the $cn variable inside the debugger, I see that the variable contains the value “localhost.” That is what I want, so I step over the remainder of the code, thereby executing the remainder of the script. These commands and associated output appear in the following figure.

Image of commands and associated output

That’s it for now. Join me tomorrow for more fun with Windows PowerShell.

 

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,

    another good feature of the PS debugger!

    What I'm missing is the ability to add conditions to breakpoint which depend on the value of variables. It would be nice to be able to break on conditions like: "break when the value of $myvar is set to a value over 1000!"

    This is something higher programming languages offer but it maybe a bit difficult to implement this for powershell because of the very relaxed type system.

    Well, maybe there are some new features in the PS3 debugger too ...

    Klaus.

  • I find that when breaking on a variable on write, the variable has already been written:

    PS C:\Scripts> .\mydebug.ps1

    Hit Variable breakpoint on '$cn' (Write access)

    At C:\Scripts\myDebug.ps1:1 char:1

    + $cn = "localhost"

    + ~~~~~~~~~~~~~~~~~

    [DBG]: PS C:\Scripts>> $cn

    localhost

    [DBG]: PS C:\Scripts>> l

       1:* $cn = "localhost"

       2:

       3:  $process = "notepad"

       4:

       5:  Get-WmiObject -Class win32_bios -cn $cn

       6:

       7:  Start-Process $process

       8:

       9:  Get-Process $process

      10:

    [DBG]: PS C:\Scripts>>

  • A cool thing to put in the -Action parameter is {Write-Host "`a"}.  This will cause a beep if a certain break conditon is met.

  • @Klaus Schulte I am glad you like the article. PowerShell has the ability to break on a value of a variable. To do this, use both the variable and the value parameter of Set-PSBreakpoint. Here is an example command: Set-PSBreakpoint -Variable d -Action {IF($d -gt 6){Break} }

    I think perhaps I need one more article on debugging :-)

  • @BigTeddy Yes I find that as well. Remember, there are three ways to break on variables: Read, Write, or ReadWrite. But if I am having a specific problem, then I will often just break on the line before the variable. I can then step through the commands to see where what is happening.

  • @BigTeddy I LOVE this idea! I would have NEVER thought of using the beep in the action ... this is soooo cool. Hmm, I could also play various wav files ... dude, this could be LOTS of fun!