# 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 November 10, 2026

## 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:

```powershell
        if (Test-Path $Destination) {
```

```powershell
.\move-receipts.ps1
```

```text
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](https://www.ask-codey.com/lessons/TODO)

`$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](https://www.ask-codey.com/lessons/TODO)

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:

```powershell
Set-PSBreakpoint -Script .\move-receipts.ps1 -Line 9
.\move-receipts.ps1
```

```text
  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:

```powershell
$to
Test-Path $Destination
Test-Path $to
```

```text
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

- [VS Code](https://www.ask-codey.com/glossary/vs-code)
- [Breakpoint](https://www.ask-codey.com/glossary/breakpoint-powershell)
- [Debugger](https://www.ask-codey.com/glossary/debugger-powershell)
- [Set-PSBreakpoint](https://www.ask-codey.com/glossary/set-psbreakpoint)

## Cheat sheets

- [Debugging in VS Code](https://www.ask-codey.com/cheat-sheets/powershell-debugging-in-vs-code-cheat-sheet)

## Related

- [Writing Scripts in VS Code](https://www.ask-codey.com/lessons/powershell-scripts-in-vs-code)
- [Where Output Goes: \`Write-Output\`, \`Write-Host\` and Friends](https://www.ask-codey.com/lessons/powershell-output-streams)
- [Reading Errors, and \`-ErrorAction\`](https://www.ask-codey.com/lessons/powershell-errors)

Source: https://www.ask-codey.com/lessons/powershell-debugging-in-vs-code
