Back to top

FREE eBook: The Most USEFUL PowerShell CmdLets and more…

Grab a copy!

How To Debug PowerShell Scripts

How To Debug PowerShell Scripts Featured
Approx Reading Time: 17 minutes

Debugging is putting the execution of code at pause and continuing to run the code either line by line or some other way that you choose in manual fashion and managed by you.

Why Would You Debug The Code?

There are several reasons why would programmer decide to do debugging of code and here are few:

  • to troubleshoot the errors and to help determine the cause of an error.
  • to see how code runs and understand it better, especially if you are not the one who wrote it in the first place.

NOTE: If you want to learn more about Error Handling please read How To Log PowerShell Errors And Much More

Useful Keyboard Shortcuts

While you are debugging the code the fastest way to navigate is by using the keyboard shortcuts so it is very important to know them. Here is a short table of the most important keyboard shortcuts while debugging.

CommandKeyboard ShortcutConsole Pane Shortcut
Toggle BreakpointF9
Run/ContinueF5Type C and then press ENTER to continue debugging
Step IntoF11Type S and then press ENTER to continue debugging
Step OverF10Type V and then press ENTER to continue debugging
Step OutShift + F11Type O and then press ENTER to continue debugging
Stop DebuggerShift + F5Type Q and then press ENTER to continue debugging
Remove All BreakpointsCtrl + Shift + F9
List BreakpointsCtrl + Shift + L
Display Call StackCtrl + Shift + DType K and then press ENTER to continue debugging
Break AllCtrl + B
Go to Console PaneCtrl + D
Go to Script PaneCtrl + I
Table 1 - Debugging keyboard shortcuts

How To Debug PowerShell Scripts

To debug PowerShell script follow these easy steps:

  1. In order to set breakpoints in the script that you want to debug you need to save it first. An unsaved script cannot set breakpoints.
  2. Now you want to set one or more breakpoints by selecting the line of code where you want to place the breakpoint and then right-click mouse and click on “Toggle Breakpoint” or press F9 or go to menu Debug and click on “Toggle Breakpoint”.
  3. Run the code by pressing F5 or make a call to the script and the code will run as usual until it reaches breakpoint that will switch to debugging mode and we can go through the code to debug it.
  4. We can continue line by line by pressing F11 – Step Into. If the current statement is a function or a script call, then the debugger steps into that function or script, and we can continue debugging in that function.
  5. If we want to avoid debugging in function or script calls we can press F10 – Step over and we will not enter into function or script in debugging mode. This will be executed without debugging line by line and we can move one with debugging in the current function.
  6. If we want to remove breakpoint click on that line of code and press F9. Basically F9 is to turn on and off breakpoint on the line where is cursor or mouse point.

PowerShell Debugging Example

For this example, I will use my own CmdLets Get-CPUInfo and Get-ComputerInfo and they are part of the Efficiency Booster PowerShell Project. This project is a library of many awesome CmdLets that help us IT experts to be more efficient in our daily IT tasks. Please feel free to download the zip file with source code so you can follow along.

$computer = $env:COMPUTERNAME
Toggle Breakpoint (F9)
  • Make the call to Get-CPUInfo CmdLet using the following code in PowerShell ISE Code Pane and wait for a breakpoint to be reached.
Get-CPUInfo -client "OK" -solution "FIN"
Call to Get-CPUInfo
  • Wait for execution to hit the breakpoint.
The breakpoint has been hit

NOTE: It is important to notice a few visual indications in the Windows PowerShell ISE that tell us that the code is in debugging mode. Please read this section to learn about them.

  • Now we can Step into the code with F11
  • When you come to the following line of code and press F11 you well step into Get-ComputerInfo CmdLet
$computerinfo = Get-ComputerInfo -computername $computer -client $client -solution $solution
Debugging moved to Get-ComputerInfo CmdLet
  • While you are still in Get-ComputerInfo press Ctrl + Shift + D to get Call Stack
Call Stack Displayed (We have nested functions)
Debugging come back to Get-CPUInfo CmdLet
  • When you come back to Get-CPUInfo CmdLet press again Ctrl + Shift + D to get Call Stack again.
Call Stack Displayed (We have exited from nested functions)

NOTE: Notice the difference between call stacks while we were in Get-ComputerInfo CmdLet and when we returned back to Get-CPUInfo CmdLet.

  • Press F5 to continue execution. The execution finishes and we get our result
Execution finished and we got the result

How Do We Know That Code Execution Is In Debugging Mode

We have some obvious visual indications that we have switched to Debugging Mode and here are some:

  • All the tabs in Windows PowerShell ISE get [Read Only] next to the script name.
  • The breakpoint highlights color has changed from red to brown.
  • In the Console pane, it is written “Hit Line breakpoint…” or another type of breakpoint and
  • We get [DBG] in front of the last line in Console Pane
Debugging Mode indications
  • Many menu items in the Debug menu are now enabled and we can use them for debugging the code.
Debug Menu Items are enabled and not grayed out

What Are The Types Of Breakpoints

There are three types of breakpoints in the Windows PowerShell debugging environment.

#Type of breakpointDescriptionEnvironment to setup breakpoint
1Line breakpointExecution of the script pauses when the designated line is reached.Can be set in PowerShell ISE
2Variable breakpointExecution of the script pauses when the designated variable’s value changes.Use Set-PSBreakpoint CmdLet
3Command breakpointExecution of the script pauses whenever the designated command, function or CmdLet is about to be run.Use Set-PSBreakpoint CmdLet
Table 2 - The Types Of Breakpoints

Here we can see all types of breakpoints listed in Console Pane using Get-PSBreakpoint CmdLet:

List all type of breakpoints: line, command, and variable

I have described how to set up Variable and Command breakpoints using Set-PSBreakpoint CmdLet in later sections with few nice examples so check it out following subheadings:

How To Manage A Debugging Session

REMEMBER: Even before starting debugging your script, save it first, then set one or more breakpoints and you are ready to start debugging.

How To Start Debugging

There are several ways to start debugging:

  • Click on Run Script icon on the toolbar.
  • Press F5 key shortcut.
  • Go to the Debug menu and click Run/Continue.

The script will run until it encountered the first breakpoint. It pauses execution there and highlights the line on which it paused. In Script pane all the open tabs will have [Read Only] next to the name of the script. In the Console pane, we will get information that execution Hit Line breakpoint with [DBG] starting next line meaning that we are in debugging mode right now.

How To Continue Debugging

There are several ways to continue debugging:

  • Press F5 key shortcut.
  • Go to the Debug menu and click the Run/Continue.
  • Click on Run Script Icon in the toolbar.
  • In Console Pane, type C and then press ENTER.

How To View The Call Stack

There are several ways to view the call stack:

  • Press Ctrl + Shift + D.
  • Go to the Debug menu and click on Display Call Stack.
  • In Console Pane, press K and then press ENTER.
  • Run Get-PSCallStack CmdLet like in the following example.
Get-PSCallStack
Call Stack Displayed

How To Stop Debugging

There are several ways to stop debugging:

  • Press Shift + F5.
  • Go to the Debug menu and click Stop Debugger.
  • In Console Pane, type Q and then press ENTER.

How To Step Into, Step Over, Step Out And Continue While Debugging

When the breakpoint is hit and execution of code has paused and the Windows PowerShell ISE environment is in debugging mode we as developers have several options to step through the code and see what is happening.

Debugging Task: Step Into
Description: The difference between Step Into and Over is that Over when executes statement that is function or script call will not step into that function or script but rather execute them and continue to next statement within the current code. Basically we are not leaving the current function. This is very useful when there is no need to step through the other functions or scripts and stepping of code is much faster.

How to accomplish it in PowerShell ISE:

  • Press F10 keyboard shortcut.
  • Go to the Debug menu and then click on Step Over.
  • In the Console Pane, Type V and then press ENTER to continue debugging.

Debugging Task: Step Out
Description: Step Out is a very useful option if we are in nested functions and we can easily step out from nested functions and return to the main function. Use Ctrl + Shift + D keyboard shortcut to check if the current code statement is in the nested function (We are checking the Call Stack basically). If we are in the main body of the function than script executes to the end, or to the next breakpoint. We do not step through the skipped statements but rather executes them.

How to accomplish it in PowerShell ISE:

  • Press Shift + F11 keyboard shortcut.
  • Go to the Debug menu and then click on Step Out.
  • In the Console Pane, Type O and then press ENTER to continue debugging.

Debugging Task: Continue
Description: Continues execution to the end, or to the next breakpoint. The skipped functions and invocations were not stepped through but rather executed.

How to accomplish it in PowerShell ISE:

  • Press F5 keyboard shortcut.
  • Go to the Debug menu and then click on Run/Continue.
  • In the Console Pane, Type C and then press ENTER to continue debugging.

How To Display The Values Of Variables While Debugging

To display the values of standard variables use one of these methods:

  • Script pane, hover over the variable to display its value as a tooltip
  • Console pane, type the variable name and press ENTER
Variable showed as Tooltip while debugging
Variable values in Console Pane while debugging

To display the values of almost all automatic variables use the same methods.

Previously mentioned methods apply for most automatic variables but for following automatic variables doesn’t apply:

  • $_
  • $Args
  • $Input
  • $MyInvocation
  • $PSBoundParameters

If you try to display the value of any of these variables, you will not get the value of the variable in the script but rather the value of the variable from an internal pipeline that the debugger uses.

The workaround is as follows:

  1. In the script, create a new variable and assign the value of the automatic variable
  2. Now you can display the value of the new variable using the same methods as for standard variables.

How To List Breakpoints

You have several ways to list breakpoints and get the result in Console Pane:

  • Press Ctrl + Shift + L key shortcut (that will call Get-PSBreakpoint CmdLet).
  • Go to menu Debug and pick List Breakpoints.
  • Run Get-PSBreakpoint CmdLet in Console Pane.

As a result, you will get all the breakpoints from all scripts that have breakpoints.

Get-PSBreakpoint CmdLet lists all breakpoints from all open scripts

If you want to see all breakpoints from certain script only use Get-PSBreakpoint with Script parameter pointing to the location where the script is located like in the following example:

Get-PSBreakpoint -Script .\Documents\WindowsPowerShell\Modules\03common\GetCPUInfo.ps1

If you want to list certain breakpoint(s) use Get-PSBreakpoint with Id parameter like in these examples:

Get-PSBreakpoint -Id 0,2
Listed breakpoints with certain Ids

How To Set A Breakpoint On A Function Or CmdLet

To set up a breakpoint on a function we use Set-PSBreakpoint CmdLet with Script parameter pointing to the script file and Command parameter with the name of function or CmdLet which call will hit the breakpoint.

In Get-CPUInfo CmdLet I have a call to Get-ComputerInfo CmdLet and if I want to set up a breakpoint when this CmdLet is called I do this with this command.

Set-PSBreakpoint -Script .\Documents\WindowsPowerShell\Modules\03common\GetCPUInfo.ps1 -Command Get-ComputerInfo

So when I call Get-CPUInfo CmdLet and execution of code comes to the line when a call to Get-ComputerInfo CmdLet needs to be executed we hit the breakpoint and PowerShell ISE switches to debugging mode. Now we can go through the code in Get-ComputerInfo CmdLet.

Use Set-PSBreakpoint CmdLet to set Command type of breakpoint

NOTE: Here we listed both line and command type of breakpoints.

List both line and command breakpoints

How To Set A Breakpoint For A Variable In A Function

We should use Set-PSBreakpoint CmdLet with Script parameter pointing to the script file and Variable parameter with the name of the variable and we need to choose Mode like in example:

Set-PSBreakpoint -Script '.\Documents\WindowsPowerShell\Modules\03common\GetCPUInfo.ps1' -Variable "computer" -Mode Write
Use Set-PSBreakpoint CmdLet to set variable type breakpoint

If we list again all breakpoints set so far we will see all the types of breakpoints: line, command, and variable.

List all type of breakpoints: line, command, and variable

Valid values for Mode parameter are:

  • Write (default). Execution of code is stoped immediately before a new value is written to the variable.
  • Read. Stops execution when the variable is read. In reading mode, the execution of code doesn’t stop when the value of the variable changes.
  • ReadWrite. Execution of code is stoped when the variable is read or written.

How To Set A Breakpoint Depending On The Value Of A Variable

This is a very interesting option that might be useful in some special circumstances for example when some variable reaches certain value to activate the breakpoint and debug the code.

We use Set-PSBreakpoint CmdLet with parameters: Variable, Mode, and Action. A breakpoint has been created on a variable ‘sum’ when its value has been written to it and there is an action check to write the value of the variable and break the code when Command CallCounter is used and value of “sum” variable is greater than 15.

NOTICE: When the Counter function is used and the value of the “sum” variable is greater than 15 breakpoint action is not triggered and we do not hit a break of the code and do not enter debugging mode. Only when CallCounter function is used the breakpoint is hit.

Copy the following code in PowerShell ISE Script pane and run the code (F5):

Function Counter
{
    Param ($limit = 10)
    $sum =0
    foreach ($i in 1..$limit)
    {
        $sum += $i
    }
    $sum
 }
 # Clear breakpoints
 Get-PSBreakpoint | Remove-PSBreakpoint
 $bp = Set-PSBreakpoint -Variable "sum" -Mode Write -Action {
    #Check Call state if called by 'CallCounter'
    if ((Get-PSCallStack).Command -contains "CallCounter" -and  $sum -gt 15)
    {
        Write-Host -ForegroundColor Yellow "            sum > 15 with i was $i; sum == $sum"
        break
     }
  }
  Counter
  function CallCounter
  {
    Counter
  }
  CallCounter

Here is a breakpoint message wrote to the host and hit of breakpoint after variable reached a certain value.

Breakpoint hit with action

Run the following command to list the breakpoint:

Get-PSBreakpoint | Out-GridView

Here is the result:

Variable type breakpoint with Action

How To Enable/Disable Breakpoints

To disable all breakpoint run these commands:

Get-PSBreakpoint | Disable-PSBreakpoint

NOTE: After all breakpoints have been disabled the highlights color has changed from red into light blue in Script Pane so we can see visually that breakpoints are disabled.

Disable all breakpoints using Disable-PSBreakpoint
All breakpoints disabled

To enable all breakpoints to run these commands:

Get-PSBreakpoint | Enable-PSBreakpoint

NOTE: After all breakpoints have been enabled again the highlights color has changed from light blue back into red in Script Pane so we can see visually that breakpoints are enabled again.

Enable all breakpoints using Enable-PSBreakpoint CmdLet
All breakpoints enabled again

We can enable/disable breakpoints by using their Ids.

Get the list of breakpoints Ids.

Get-PSBreakpoint

Disable breakpoints with Id values 1 and 3.

Disable-PSBreakpoint -Id 1, 3

NOTE: We can even visually see that breakpoint id 1 is disabled (light blue) and breakpoint id 0 is enabled (red).

Disable breakpoints using Disable-PSBreakpoint CmdLet Id parameter

Look at the value for the Enabled column and Ids 1 and 3. It should be false and that means disabled breakpoint.

Get-PSBreakpoint | Select-Object ID, Enabled, Line, Command, Variable, AccessMode, HitCount,  @{label="Script"; Expression={$_.Script.Substring( $_.Script.LastIndexOf("\") + 1 )}} | Out-GridView
List of breakpoints and id 1 and 3 are disabled

Re-Enable breakpoints with Id 1 and 3 again.

Enable-PSBreakpoint -Id 1, 3

Here is a cool example that sets breakpoint first and saves the breakpoint as variable and then use that variable to pass thru to CmdLet to disable the breakpoint and then to re-enable the same breakpoint.

 $B = Set-PSBreakpoint  -Script '.\Documents\WindowsPowerShell\Modules\03common\GetCPUInfo.ps1' -Variable "computer"

Disable breakpoint with PassThru parameter of Disable-PSBreakpoint

$B | Disable-PSBreakpoint -PassThru

Enable the same breakpoint with PassThru parameter of Enable-PSBreakpoint

$B | Enable-PSBreakpoint -PassThru

How To Remove Breakpoints

Consider disabling the breakpoints before removing them since removing is destructive action and demands from you to set again breakpoints while disabling is the non-destructive and only thing to do is to enable it again in order to continue using the same breakpoint.

To remove all breakpoints we have these options:

  • Go to Menu Debug and click on Remove All Breakpoints.
  • Press key shortcut Ctrl + Shift + F9.
  • Run the following commands in Code Pane.
Get-PSBreakpoint | Remove-PSBreakpoint

To remove certain breakpoint we can move the mouse to that line of code and:

  • Go to Menu Debug and click on Toggle Breakpoint.
  • Press F9 keyboard shortcut.
  • Right-click mouse on that line and click on Toggle Breakpoint.

To remove the breakpoint for a script we should use Get-PSBreakpoint CmdLet with Script parameter pointing to the script file and pipe the result to Remove-PSBreakpoint CmdLet like in the following example

Get-PSBreakpoint

We have 5 breakpoints that belong to two different scripts.

Breakpoints from two different scripts

To remove breakpoints from Get-CPUInfo CmdLet script we run the following command:

Get-PSBreakpoint -Script .\Documents\WindowsPowerShell\Modules\03common\GetCPUInfo.ps1 | Remove-PSBreakpoint

If we list the breakpoints again with Get-PSBreakpoint CmdLet we will see the only breakpoint from Get-LastBootUpTime CmdLet

Breakpoint just from one script after deleting of all breakpoints from another script

How To Manipulate Breakpoints With Their Ids

In order to get Ids of breakpoints, we run Get-PSBreakpoint CmdLet.

Get-PSBreakpoint

Now when we know the Ids of breakpoints we can enable, disable, or remove breakpoints by their Ids.

To disable breakpoint with Id 4 we run following command:

Disable-PSBreakpoint -Id 4

Use this to see the Enable status of breakpoints.

Get-PSBreakpoint | Select-Object ID, Line, Enabled,  @{label="Script"; Expression={$_.Script.Substring( $_.Script.LastIndexOf("\") + 1 )}}

To disable more breakpoints use Id parameter with Id values separated with a comma.

Disable-PSBreakpoint -Id 6,8

To enable breakpoints to use Enable-PSBreakpoint CmdLet with Id parameter.

Enable-PSBreakpoint -Id 4,6,8

To remove breakpoints use Remove-PSBreakpoint with Id values. (Removal is a destructive command so be careful running it).

Remove-PSBreakpoint -Id 4, 6

Verbose Common Parameter

Verbose Common Parameter is not directly debugging but it can help us showing the workflow of our code execution. Personally I use the execution of CmdLet with Verbose when I need assistance where I need to put and turn on the breakpoints in the code.

Get-CPUInfo -client "OK" -solution "FIN" -Verbose
Verbose Common Parameter

Here is the code of Get-CPUInfo CmdLet and how I implement Write-Verbose CmdLet that will show the messages when CmdLet is run with Verbose Common Parameter.

Implementation of Write-Verbose CmdLet

Useful Commands And Keyboard Shortcuts

List of useful keyboard shortcuts.

CommandKeyboard ShortcutConsole Pane Shortcut
Toggle BreakpointF9
Run/ContinueF5Type C and then press ENTER to continue debugging
Step IntoF11Type S and then press ENTER to continue debugging
Step OverF10Type V and then press ENTER to continue debugging
Step OutShift + F11Type O and then press ENTER to continue debugging
Stop DebuggerShift + F5Type Q and then press ENTER to continue debugging
Remove All BreakpointsCtrl + Shift + F9
List BreakpointsCtrl + Shift + L
Display Call StackCtrl + Shift + DType K and then press ENTER to continue debugging
Break AllCtrl + B
Go to Console PaneCtrl + D
Go to Script PaneCtrl + I
Table 1 - Debugging keyboard shortcuts

Call Stack displayed:

Get-PSCallStack

List the breakpoints:

Get-PSBreakpoint

Set a breakpoint on a function:

Set-PSBreakpoint -Script .\Documents\WindowsPowerShell\Modules\03common\GetCPUInfo.ps1 -Command Get-ComputerInfo

Disable breakpoints:

Get-PSBreakpoint | Disable-PSBreakpoint

Enable breakpoints:

Get-PSBreakpoint | Enable-PSBreakpoint

List the breakpoints:

Get-PSBreakpoint | Select-Object ID, Enabled, Line, Command, Variable, AccessMode, HitCount,  @{label="Script"; Expression={$_.Script.Substring( $_.Script.LastIndexOf("\") + 1 )}} | Out-GridView

Remove breakpoints (Remember this is a destructive command so be careful):

Get-PSBreakpoint | Remove-PSBreakpoint

Useful PowerShell Debugging Articles

Here are some useful articles and resources:

About Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals!
I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials
About Me...

My Posts | Website

Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals! I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials About Me...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Recent Content