Remote Script Debugging in Windows PowerShell

Remote Script Debugging in Windows PowerShell

  • Comments 4
  • Likes

Summary: Learn about remote debugging support in Windows PowerShell 4.0.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest blog written by Paul Higinbotham who is a software design engineer on the Windows PowerShell team…

Windows PowerShell 4.0 includes two major enhancements to the script debugger: script debugging now works in remote sessions, and we’ve added debugging support for workflow scripts. This blog post describes the new remote debugging support, and a following post will describe the new workflow script debugging.

Previously, script debugging in Windows PowerShell was limited to scripts running on the local machine.  If you tried to set script breakpoints in a remote session, it caused an error. In Windows PowerShell 4.0, you can set breakpoints in remote sessions and debug remote running scripts from the console in the same way that you debug local running scripts.

To use remote debugging, the client machine and the target machine must be running Windows PowerShell 4.0. Also, remote debugging is supported in the Windows PowerShell console, but it is not supported in the Windows PowerShell ISE. Check the program documentation for other host programs to learn if it is supported. 

Script debugging in the Windows PowerShell console always begins in the same way. You use the Set-PSBreakpoint cmdlet to set a line, command, or variable breakpoint in a script, and then run the script.  When the breakpoint is hit, the script execution stops, and the console transitions into debugger mode. 

The command prompt changes to indicate that the console is in debug mode, and from this prompt, you can execute debugger commands such as Help ('h', '?'), List source ('list', 'l'), Show call stack ('k'), and execution resume commands (for example, Continue, StepInto, and StepOut).

You can examine script variables by typing the variable name and run new commands or script at the debug prompt…all while stopped in the debugger.

Example 1:  Console script debugging

PS C:\> Set-PSBreakpoint –Script c:\DebugTest1.ps1 –Line 5

  ID Script                           Line Command                          Variable                        Action

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

   0 DebugTest1.ps1                      5

 PS C:\> c:\DebugTest1.ps1

Entering debug mode. Use h or ? for help.

 Hit Line breakpoint on 'C:\DebugTest1.ps1:5'

 At C:\DebugTest1.ps1:5 char:1

+ $Title = "Debugging Test"

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

 

[DBG]: PS C:\>> stepOver

 

At C:\DebugTest1.ps1:6 char:1

+ $Count = 100

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

[DBG]: PS C:\>> $Title

 Debugging Test

 [DBG]: PS C:\>> Get-Process powershell

 Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

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

    357      26    66276      70800   621     0.72   4152 powershell

[DBG]: PS C:\>>

Windows PowerShell remote script debugging provides an almost identical console debugging experience. Debugging is an interactive endeavor, so to debug a script in a remote session, you must first establish an interactive session from which you can debug. This is done by using the Enter-PSSession cmdlet, where you can enter an existing remote session or establish a new one. 

Example 2:  Create a new remote session and enter into an interactive session

PS C:\> Enter-PSSession –ComputerName localhost

[localhost]: PS C:\>  

There is one significant difference between local script and remote script debugging. When debug and output data are stopped in the debugger during remote script debugging, the data arrives at the client through separate and unsynchronized streams. Because we didn’t want the output data to overwrite the prompt or other debugging information, Windows PowerShell suppresses script output data while the debugger is in Stop mode. The downside is that some script output might arrive later than expected.

For example, if you step over a statement that generates output, you might not see that output at the next debugger stop. Instead, you will see it after you step through one more statement.

Following are a few detailed examples to show you how remote debugging works.

Example 3:  Console remote script debugging

# The local and remote computers must both be running Windows PowerShell 4.0.

# For demo purposes the remote machine is the local machine using ‘localhost’ as

# the computer name.

 # Create a new interactive session on the remote computer.

PS C:\ > Enter-PSSession -ComputerName localhost

 # Set a line breakpoint on script in the remote session.

[localhost]: PS C:\> Set-PSBreakpoint C:\DebugTest1.ps1 5

   ID Script                      Line Command                     Variable                   Action

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

   3 DebugTest1.ps1                 5

 [localhost]: PS C:\> C:\DebugTest1.ps1

 Entering debug mode.  Use h or ? for help.

 Hit Line breakpoint on 'C:\DebugTest1.ps1:5'

 At C:\DebugTest1.ps1:5 char:1

+ $Title = "Debugging Test"

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

 [localhost]: [DBG]: PS C:\>> list 1

    1:  ##

    2:  ## Simple Script Debugging Test

    3:  ##

    4:

    5:* $Title = "Debugging Test"

    6:  $Count = 100

    7:

    8:  "Starting Test: $Title"

    9:

   10:  "$env:ComputerName Hello" > c:\TText.txt

   11:

   12:  $i = 0

   13:  while ($i -lt $Count)

   14:  {

   15:      Start-Sleep -Seconds 1

   16:

   17:      Write-Output ("Output " + ++$i)

   18:  }

   19:

   20:  "Test Complete"

   21:

 [localhost]: [DBG]: PS C:\>> stepOver

 At C:\DebugTest1.ps1:6 char:1

+ $Count = 100

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

 [localhost]: [DBG]: PS C:\>> $Title

 Debugging Test

Debugging with disconnected sessions

Windows PowerShell remote debugging also supports the disconnected and connected session semantics that were added in Windows PowerShell 3.0. A script debug Stop state is preserved in a disconnected session to allow you to debug the script when the connection is re-established. 

In Windows PowerShell 3.0, a remote session can be disconnected in one of two ways. The first is a manual disconnect that you initiate by using the Disconnect-PSSession cmdlet or the Invoke-Command -InDisconnectedSession cmdlet. The second is through robust connections auto-disconnect. That is, if a network connection is lost in a session, that session is automatically disconnected after four minutes of trying to re-establish the network connection. 

In Windows PowerShell 4.0, there is a third way a remote session is disconnected when you hit a breakpoint in a script in the remote session. The script in the remote session is stopped in the debugger, and the remote session is disconnected from the client. To debug or continue the script, you have to use the Enter-PSSession cmdlet to enter into an interactive debug session from the Windows PowerShell console. In the debug session, you can debug the script or continue execution. 

You can determine whether a disconnected session is stopped in the debugger by connecting to it via Connect-PSSession, and looking at the session Availability field. If it is stopped in the debugger, Availability == 'RemoteDebug'.

After a remote session is stopped in the debugger and disconnected, you have only two choices about how to proceed with the session. You can debug the session by using the Enter-PSSession cmdlet, or you can kill the session by using the Remove-PSSession cmdlet.

When you run a script in a disconnected session, the script runs on the remote machine and the output data is buffered on the remote machine. You normally connect and retrieve the script output by running the Receive-PSSession cmdlet. However, if the script is stopped in the remote session at a breakpoint in the debugger, Receive-PSSession will not work, and you will receive a warning message that the session is stopped in the debugger.

To continue, you must debug the remote script in an interactive session by using Enter-PSSession. In this interactive session, you can debug the script or let the script run to completion by removing all breakpoints and using the debugger Continue command.

Example 4:  Debugging a disconnected session

# Run script with line breakpoint in disconnected session.

PS C:\> $session = Invoke-Command -Cn localhost -ScriptBlock { Set-PSBreakpoint C:\DebugTest1.ps1 5; C:\DebugTest1.ps1 } -InDisconnectedSession

PS C:\> $session

  Id Name            ComputerName    State         ConfigurationName     Availability

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

  3 Session2        localhost       Disconnected  Microsoft.PowerShell          None

 # Connect to session.  See that it is stopped in the debugger.

PS C:\> Connect-PSSession $session

  Id Name            ComputerName    State         ConfigurationName     Availability

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

  3 Session2        localhost       Opened        Microsoft.PowerShell   RemoteDebug

# Try to use Receive-PSSession.

PS C:\> Receive-PSSession $session

WARNING: The remote session command is currently stopped in the debugger. Use the Enter-PSSession cmdlet to connect interactively to the remote session and automatically enter into the console debugger.

# Use Enter-PSSession to debug.

PS C:\> Enter-PSSession $session

WARNING: You have entered a session that is currently stopped at a debug breakpoint inside a running command or script. Use the Windows PowerShell command line debugger to continue debugging.

Hit Line breakpoint on 'C:\DebugTest1.ps1:5'

At C:\DebugTest1.ps1:5 char:1

+ $Title = "Debugging Test"

+ ~

[localhost]: [DBG]: PS C:\>> continue

Debugging remote sessions with Invoke-Command

Windows PowerShell supports running scripts synchronously on remote machines by using the Invoke-Command cmdlet. In the previous section, I talked about using Invoke-Command to set line breakpoints and run script files on a remote machine by using the InDisconnectedSession parameter. As you saw, Invoke-Command immediately disconnected the session and let the script run asynchronously in the remote session. 

We then debugged the remote session by using Enter-PSSession. In this scenario, we do the same thing except we leave the session connected while the script is running. When the line breakpoint that we set is hit, the session is automatically disconnected. We then connect to the remote session again and debug as before.

Example 5:  Debugging a disconnected session, part 2

# Create a remote session.

PS C:\> $session = New-PSSession -ComputerName localhost

PS C:\> $session

  Id Name            ComputerName    State         ConfigurationName     Availability

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

  1 Session1        localhost       Opened        Microsoft.PowerShell     Available

# Set a line breakpoint in the remote session.

PS C:\> Invoke-Command -Session $session -ScriptBlock { Set-PSBreakpoint C:\DebugTest1.ps1 -Line 8 }

  ID Script                    Line Command                   Variable                  Action                    PSComputerName

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

   0 DebugTest1.ps1               8                                                                               localhost

# Run the script in the remote session.  Observe that the session is automatically disconnected

# when the line breakpoint is hit.

PS C:\> Invoke-Command -Session $session -ScriptBlock { C:\DebugTest1.ps1 }

 WARNING: Session Session1 with instance ID 7b2c5c81-5361-4bef-87fe-83a81ee40e18 on computer localhost has been disconnected because the script running on the session has stopped at a breakpoint. Use the Enter-PSSession cmdlet on this session to connect back to the session and begin interactive debugging.

# See that the session is now disconnected.

PS C:\> $session

Id Name            ComputerName    State         ConfigurationName     Availability

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

  1 Session1        localhost       Disconnected  Microsoft.PowerShell          None

# Debug the session.  Note that Enter-PSSession automatically reconnects the session for you.

PS C:\> Enter-PSSession $session

WARNING: You have entered a session that is currently stopped at a debug breakpoint inside a running command or script. Use the Windows PowerShell command line debugger to continue debugging.

Entering debug mode. Use h or ? for help.

Hit Line breakpoint on 'C:\DebugTest1.ps1:8'

At C:\DebugTest1.ps1:8 char:1

+ "Starting Test: $Title"

+ ~

[localhost]: [DBG]: PS C:\Users\paulhi\Documents>> stepOver

Debugging remote running scripts is an important and powerful extension of Windows PowerShell script debugging. No longer do you need to copy script files from a remote machine to your local machine so you can debug it. Now you can debug the script directly on the remote machine and in that context.

~Paul

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
  • Very good sample. This is a very important resource to further improve control.

  • very informative article.....and explained nicely.

    Will there be an article on the Workflow debugging as well ?

    Regards

  • Yes, Dexter. Coming soon: December 17, I think.

  • Awesome.... :)