# Did It Work? \`$?\`, \`$LASTEXITCODE\`, \`&&\` and \`||\`

$? says whether the last command worked, $LASTEXITCODE holds the number a program ended with (0 when it worked), && runs the next command only if the last one worked, and || runs it only if the last one failed.

Apprentice · PowerShell · Updated November 10, 2026

## After this lesson you can

- Tell whether the last command worked with $?, and read a program's exit code with $LASTEXITCODE
- Chain commands with && to run the next only if one worked, and || to run it only if one failed

## Key takeaways

- $? is True when the last command worked and False when it didn't. It changes after every command, so check it right away.
- $? is about whether a command worked, not what it answered: Test-Path can answer False and still have worked.
- A program ends with an exit code, 0 when it worked, which $LASTEXITCODE holds until the next program runs.
- a && b runs b only if a worked: read && as "and then, if it worked". a || b runs b only if a failed: read || as "or else".
- Windows PowerShell 5.1 has $? and $LASTEXITCODE, but not && or ||.

Your camera's memory card is full. Before you wipe it, every photo has to be safe on the laptop, so you copy them, glance at the screen, and wipe the card. But what if the copy failed, a typo in a folder name, and the red line scrolled past while you looked away? When one step depends on another, let PowerShell do the checking. Every command reports whether it worked, and two marks make the next command wait for the answer. People who look after computers chain steps this way every day ("back up, and only if that worked, install the update"), and every script that runs at night while nobody watches depends on it.

The examples use the `photo-book` folder from *Keyboard Shortcuts at the Prompt*.

## Did the last command work? \`$?\`

`$?` (read "dollar question mark") is a variable PowerShell fills in for you, an **automatic variable**. It holds the answer about the last command: `True` if it worked, `False` if it didn't. A yes-or-no value like that is a **Boolean** (*Is It There? Test-Path*).

```powershell
Set-Location ~\terminal-practice\photo-book
Get-ChildItem edited\2026\08-august\birthday -Name
$?
```

```text
IMG_0815-edit.jpg
IMG_0817-edit.jpg
True
```

```powershell
Get-ChildItem edited\2026\06-june
$?
```

```text
Get-ChildItem: Cannot find path 'C:\Users\Sam\terminal-practice\photo-book\edited\2026\06-june' because it does not exist.
False
```

`$?` is about whether the command *worked*, not about what it answered. `Test-Path` answers False for a missing folder, and that answer is the job done:

```powershell
Test-Path edited\2026\06-june
$?
```

```text
False
True
```

`$?` changes after every command, even one that only reads a variable, so check it right away.

## Programs answer with a number: \`$LASTEXITCODE\`

Programs that aren't PowerShell commands, such as `robocopy`, `ping` or `git`, finish with a number instead: their **exit code**. 0 means it worked; any other number means it didn't, and the number can say why. PowerShell keeps the last program's number in `$LASTEXITCODE` (read "dollar last exit code").

`where.exe` is a small Windows program that finds where a program lives: a quick way to ask "is it installed?" Write it with `.exe`, because in PowerShell `where` on its own is a short name for `Where-Object`.

```powershell
where.exe robocopy
$LASTEXITCODE
```

```text
C:\Windows\System32\Robocopy.exe
0
```

```powershell
where.exe rsync
$LASTEXITCODE
```

```text
INFO: Could not find files for the given pattern(s).
1
```

`robocopy` is Windows' own copying program for backups. `rsync`, a backup program from Mac and Linux, isn't here, so `where.exe` ended with 1. Right after a program, `$?` follows its number: False for anything but 0. `$LASTEXITCODE` changes only when a program runs; PowerShell's own commands leave it as it was. **On a Mac or Linux**, `which` does the job of `where.exe`, with the same exit codes.

## And then, if it worked: \`&&\`

`&&` (read "and then, if it worked") joins two commands on one line: the second runs only if the first worked. That's the memory card's rule, written down. Copy the edited photos into the backup folder, and only then say so:

```powershell
Copy-Item edited -Destination backup -Recurse -Force && Write-Output 'Backup done'
```

```text
Backup done
```

`-Recurse` copies the folder with everything in it, and `-Force` lets a second run copy over the first, so the line is safe to run again. `Write-Output` prints its text. Now the same line with a slip of the keyboard:

```powershell
Copy-Item edtied -Destination backup -Recurse -Force && Write-Output 'Backup done'
```

```text
Copy-Item: Cannot find path 'C:\Users\Sam\terminal-practice\photo-book\edtied' because it does not exist.
```

No "Backup done", so you'd know not to wipe the card. Compare a semicolon, `;`, which puts two commands on one line and runs the second whatever happened:

```powershell
Copy-Item edtied -Destination backup -Recurse -Force; Write-Output 'Backup done'
```

```text
Copy-Item: Cannot find path 'C:\Users\Sam\terminal-practice\photo-book\edtied' because it does not exist.
Backup done
```

That's a message you'd believe. Use `&&` whenever the second step depends on the first.

![Two tracks from one command: Copy-Item edited into backup, then && sends PowerShell on to Write-Output 'Backup done' only when the copy worked, and || sends it on to Write-Output 'Backup failed: check the folder name' only when the copy failed](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/11/fc6e6711296245dcbc8018e7c6f59af3.webp)

## Or else: \`||\`

`||` (read "or else") works the other way around: the second command runs only if the first one failed. Use it for a warning or a plan B:

```powershell
Copy-Item edtied -Destination backup -Recurse -Force || Write-Output 'Backup failed: check the folder name'
```

```text
Copy-Item: Cannot find path 'C:\Users\Sam\terminal-practice\photo-book\edtied' because it does not exist.
Backup failed: check the folder name
```

Together, `&&` and `||` are PowerShell's **pipeline chain operators**. They go by `$?`, so they ask whether a command worked, not what it answered:

```powershell
Test-Path backup\photos || Write-Output 'No backup yet'
```

```text
False
```

`Test-Path` worked, so "or else" never happened. To act on an answer, you need `if`, which Module 6 teaches.

**Windows PowerShell 5.1** has `$?` and `$LASTEXITCODE`, but not `&&` or `||`: it stops with *The token '&&' is not a valid statement separator in this version.* There, run the second command on its own line after you've checked `$?`.

## Try it in the terminal

[Terminal Quest: The Clockwork Workshop, goal 7](https://www.ask-codey.com/games/terminal-quest/workshop/powershell/step): played right on the lesson page.

Ada's clock tower bell has to ring at noon, but only once the gearbox is turning. Run the gearbox, and only if it works, ring the bell.

## Check yourself

2 questions to try on the lesson page.

## So what

`$?` and `$LASTEXITCODE` tell you whether something worked; `&&` and `||` let the next step depend on it. That's how a careful person works, written into one line.

## Key terms

- [Exit Code](https://www.ask-codey.com/glossary/exit-code-operating-system)
- [Automatic Variable](https://www.ask-codey.com/glossary/automatic-variable)
- [Pipeline Chain Operator](https://www.ask-codey.com/glossary/pipeline-chain-operator)
- [Boolean](https://www.ask-codey.com/glossary/boolean)

## Cheat sheets

- [Did It Work? \`$?\`, \`$LASTEXITCODE\`, \`&&\` and \`||\`](https://www.ask-codey.com/cheat-sheets/powershell-did-it-work-cheat-sheet)

## Related

- [Keyboard Shortcuts at the Prompt](https://www.ask-codey.com/lessons/powershell-keyboard-shortcuts)
- [Is It There? Test-Path](https://www.ask-codey.com/lessons/powershell-test-path)
- [Copy and Move: Copy-Item and Move-Item](https://www.ask-codey.com/lessons/powershell-copy-and-move)
- [Exercise: Fewer Keystrokes](https://www.ask-codey.com/lessons/exercise-powershell-fewer-keystrokes)

Source: https://www.ask-codey.com/lessons/powershell-did-it-work
