Debugging in VS Code

A breakpoint pauses a script on a line in VS Code, so you can look at every variable, step through it one line at a time with F10, and watch an expression until a value surprises you; Set-PSBreakpoint does the same at the prompt.

Journeyman · PowerShell · Updated

After this lesson you can

  • Pause a script at a breakpoint in VS Code and run it one line at a time with F10, F11 and F5
  • Watch variables and expressions while a script is paused, to find the line where a value isn't what you expected

Key takeaways

  • A breakpoint, the red dot beside a line number (F9), pauses the script before that line runs. F5 starts the script under the debugger.
  • While it's paused, the Variables list and a hover over any variable show their values right now.
  • F10 runs one line and pauses again; F11 goes into a function the line calls; F5 carries on to the next breakpoint; Shift+F5 stops.
  • Add an expression to Watch, such as Test-Path $to, to see its answer at every step.
  • Without VS Code, Set-PSBreakpoint -Script file -Line 9 pauses at the prompt, where you can type any variable's name.

The receipt mover runs without a single red line, and moves nothing. Every receipt "is already there", yet the backup drive is empty. There's no error to read: the script does exactly what you wrote, but not what you meant. That's a bug, and reading the code over and over is a slow way to find one. Instead, pause the script on a line and look at every variable, the way you'd pause a movie to see what's in the frame. VS Code's debugger does that, and developers use it every day, on scripts and on whole applications.

You need VS Code with the PowerShell extension from Writing Scripts in VS Code, and the mover from Where Output Goes: Write-Output, Write-Host and Friends. Run the practice-folder lines from Reading Errors, and -ErrorAction and empty the backup drive with Remove-Item backup-drive\*. Then make a bug to hunt: change line 9 of move-receipts.ps1 from if (Test-Path $to) { to this, as a tired you might have typed it:

        if (Test-Path $Destination) {
.\move-receipts.ps1
Moving receipts to C:\Users\Sam\terminal-practice\mover\backup-drive
WARNING: 2026-10-03-groceries.pdf is already there. Left it in the inbox.
WARNING: 2026-10-05-gas.pdf is already there. Left it in the inbox.
WARNING: 2026-10-09-pharmacy.pdf is already there. Left it in the inbox.

Pretend you don't know what you changed. Where would you start?

A breakpoint: where to pause

Open the mover folder in VS Code and open move-receipts.ps1. The warning comes from line 10, so the decision is made on line 9. Click in the margin left of the number 9: a red dot appears. That's a breakpoint, a mark that says "pause before this line runs". Click it again to remove it, or put the cursor on a line and press F9.

Start, pause and look

Press F5 (or Run > Start Debugging). The PowerShell extension runs the script in its terminal and stops before line 9, with the line highlighted in yellow. The Run and Debug view opens on the left, and its Variables list shows the script's variables as they are right now. Hover over any variable in the editor and its value pops up too.

VS Code paused at a breakpoint in move-receipts.ps1: a red dot beside line 9, line 9 highlighted in yellow, the debug toolbar at the top, and the Variables list on the left showing the values of file and to for the groceries receipt, 2026-10-03-groceries.pdf

$to looks right: the path where this receipt would go. So why does the script think it's already there?

One line at a time

The toolbar at the top steps through the script:

Key Button What it does
F10 Step Over Run this line, then pause on the next
F11 Step Into Go into a function this line calls, and pause there
Shift+F11 Step Out Finish the function you're in, and pause after it
F5 Continue Run on to the next breakpoint, or the end
Shift+F5 Stop Stop the script

Press F10. The highlight jumps to line 10, the warning, so the if on line 9 answered yes. To see why, use Watch: in the Run and Debug view, click + beside Watch and type Test-Path $Destination, then add Test-Path $to. Watch shows each answer, and updates it after every step:

The Watch section of VS Code's Run and Debug view while move-receipts.ps1 is paused: Test-Path $Destination shows True and Test-Path $to shows False

There it is: the folder is there (True), but this receipt isn't (False), and line 9 asks about the folder. Press Shift+F5 to stop, change line 9 back to if (Test-Path $to) {, save, and press F5 again: it pauses at the breakpoint for each receipt, and F5 carries on. Click the red dot to remove it when you're done.

That's the habit: make the bug happen, pause right before where it goes wrong, then step and watch until a value surprises you. One more help: in VS Code's terminal, an error's location shows as file, line and column, such as move-receipts.ps1:6:5, and Ctrl+click opens the file at that spot.

Without VS Code: `Set-PSBreakpoint`

On a computer without VS Code, PowerShell's own debugger works at the prompt:

Set-PSBreakpoint -Script .\move-receipts.ps1 -Line 9
.\move-receipts.ps1
  ID Script                      Line Command                     Variable                    Action
  -- ------                      ---- -------                     --------                    ------
   1 move-receipts.ps1              9

Moving receipts to C:\Users\Sam\terminal-practice\mover\backup-drive
Entering debug mode. Use h or ? for help.

Hit Line breakpoint on 'C:\Users\Sam\terminal-practice\mover\move-receipts.ps1:9'

At C:\Users\Sam\terminal-practice\mover\move-receipts.ps1:9 char:13
+         if (Test-Path $Destination) {
+             ~~~~~~~~~~~~~~~~~~~~~~

The prompt now starts with [DBG]:. Type a variable's name or any command to look around:

$to
Test-Path $Destination
Test-Path $to
C:\Users\Sam\terminal-practice\mover\backup-drive\2026-10-03-groceries.pdf
True
False

At the [DBG]: prompt, v steps over a line, s steps into one, c carries on, and q stops the script. Get-PSBreakpoint | Remove-PSBreakpoint removes the breakpoint when you're done.

On a Mac or Linux, VS Code and Set-PSBreakpoint work the same. On many laptops, and on a Mac, hold Fn to press F5, F9, F10 or F11.

Check yourself

2 questions to try on the lesson page.

So what

When a script does the wrong thing quietly, don't guess: pause it where the decision is made, look at the values, and the bug usually points at itself.

Key terms

Cheat sheets

Related