# If This, Then That: \`if\`, \`elseif\` and \`else\`

if runs a block of commands only when its test is True, elseif adds another test, else catches everything left, -and, -or and -not join tests together, and exit stops a script early, so a backup copies only when something changed and explains itself when it can't.

Apprentice · PowerShell · Updated November 10, 2026

## After this lesson you can

- Write an if statement with elseif and else that runs the right block for a test
- Combine tests with -and, -or and -not, and stop a script early with exit

## Key takeaways

- if (test) { … } runs the commands in the braces only when the test is True. else { … } runs when it's False.
- elseif adds another test. PowerShell tries the tests in order and runs only the first block whose test is True.
- -and needs both tests True, -or needs one of them, and -not turns True into False: if (-not (Test-Path $Path)).
- exit stops a script there; exit 1 also tells $LASTEXITCODE and && that it didn't work.
- In a test, = sets a variable and > writes a file. Compare with -eq and -gt.

The backup script from *Parameters: param()* does the same thing every time it runs. Point it at a folder where nothing changed and it reports "Files copied: 0" as if that were news; add `-Preview` and it claims files were copied when none were; misspell the folder and it carries on anyway. Real applications decide. An installer checks for enough disk space before it starts, and a backup checks before it copies. Scripts that IT teams and developers run every day are full of these checks: if the disk is nearly full, send a warning; if the file is missing, say so and stop.

This lesson changes `Backup-Folder.ps1` in the `smart-backup` folder from *Parameters: param()*.

## if and else: two roads

You decide this way all day: if it's raining, take the umbrella; else, take the sunglasses. PowerShell writes it the same way:

```powershell
if ($changed.Count -eq 0) {
    "Nothing changed in $Path, so nothing was copied."
}
else {
    $changed | Copy-Item -Destination $Destination
    "Files copied: $($changed.Count)."
}
```

Read it aloud: "if the number of changed files equals zero, say so; else, copy them." The test goes in parentheses, and it's a comparison from *Filtering: Where-Object and Comparisons*: its answer is True or False, a **Boolean**. The commands in the first braces run only when it's True, the ones after `else` only when it's False. Together, that's an **if statement**.

In `Backup-Folder.ps1`, put `@( )` around the `Get-ChildItem` line, so `$changed` is a list even when nothing changed (*Lists and Lookups: Arrays and Hashtables*), and replace the last two lines with the if statement above:

```powershell
.\Backup-Folder.ps1
.\Backup-Folder.ps1 -Path club
```

```text
Files copied: 2.
Nothing changed in club, so nothing was copied.
```

## elseif: more roads

`elseif` (read "else if") adds another test, tried only when the tests before it were False. Put this between the first block and `else`:

```powershell
elseif ($Preview) {
    $changed | Copy-Item -Destination $Destination -WhatIf
    "Preview only. Files that would be copied: $($changed.Count)."
}
```

A switch is a Boolean on its own: `$Preview` is True when `-Preview` was written.

```powershell
.\Backup-Folder.ps1 -Preview
.\Backup-Folder.ps1 -Path club -Preview
```

```text
What if: Performing the operation "Copy File" on target "Item: C:\Users\Sam\terminal-practice\smart-backup\homework\empty-draft.txt Destination: C:\Users\Sam\terminal-practice\smart-backup\backup\empty-draft.txt".
What if: Performing the operation "Copy File" on target "Item: C:\Users\Sam\terminal-practice\smart-backup\homework\essay.txt Destination: C:\Users\Sam\terminal-practice\smart-backup\backup\essay.txt".
Preview only. Files that would be copied: 2.
Nothing changed in club, so nothing was copied.
```

PowerShell tries the tests from the top and runs only the first block whose test is True, then skips the rest. For the club, "nothing changed" came first, so the preview never ran: order your tests from the most important down.

![Backup-Folder.ps1's if statement as three doors tried from the top down: the first opens when $changed.Count -eq 0 and says nothing changed, the second opens when $Preview is on and only previews, and else, the last, copies the files; only the first door that opens is used](https://fsdtrainingmedia.blob.core.windows.net/public/images/2026/11/b33b7bf478ed4159829eb6c90f34ad2c.webp)

## -and, -or and -not

`-and` (read "and") is True only when both tests are; `-or` ("or") when at least one is; `-not` ("not") turns True into False and back. `!` is a short way of writing `-not`.

```powershell
$days = 7
$days -gt 0 -and $days -lt 31
$days -lt 1 -or $days -gt 30
-not ($days -gt 0)
```

```text
True
False
False
```

Here's the whole script with three more checks. Two go right after `param()`, and `Where-Object` now skips empty files, so an empty draft never replaces a good copy:

```powershell
# Backup-Folder.ps1: copies a folder's recent changes into a backup folder.
param(
    [string]$Path = 'homework',
    [string]$Destination = 'backup',
    [int]$Days = 1,
    [switch]$Preview
)
if (-not (Test-Path $Path)) {
    "There's no folder called $Path."
    exit 1
}
if ($Days -lt 1 -or $Days -gt 365) {
    'Days must be from 1 to 365.'
    exit 1
}
$since = (Get-Date).AddDays(-$Days)
$changed = @(Get-ChildItem -Path $Path -File |
    Where-Object { $_.LastWriteTime -gt $since -and $_.Length -gt 0 })
if ($changed.Count -eq 0) {
    "Nothing changed in $Path, so nothing was copied."
}
elseif ($Preview) {
    $changed | Copy-Item -Destination $Destination -WhatIf
    "Preview only. Files that would be copied: $($changed.Count)."
}
else {
    $changed | Copy-Item -Destination $Destination
    "Files copied: $($changed.Count)."
}
```

`-not (Test-Path $Path)` reads "the folder is not there" (*Is It There? Test-Path*). `exit` (read "exit") stops the script on that line, and the 1 after it is its exit code, "it didn't work", which `$LASTEXITCODE` and `&&` understand (*Did It Work? $?, $LASTEXITCODE, && and ||*):

```powershell
.\Backup-Folder.ps1
.\Backup-Folder.ps1 -Path homwork
$LASTEXITCODE
.\Backup-Folder.ps1 -Days 0
.\Backup-Folder.ps1 -Days 7 && Write-Output 'Backup done'
.\Backup-Folder.ps1 -Path homwork && Write-Output 'Backup done'
```

```text
Files copied: 1.
There's no folder called homwork.
1
Days must be from 1 to 365.
Files copied: 2.
Backup done
There's no folder called homwork.
```

The empty draft stays out now, the typo stops with a plain message, and `&&` goes on to *Backup done* only after a backup that worked.

## Two slips to watch for

In a test, `=` sets a variable; it doesn't compare. This test is "True" because 30 isn't zero, and `$days` is changed for good:

```powershell
$days = 7
if ($days = 30) { 'A whole month' }
$days
```

```text
A whole month
30
```

And `>` means "into a file", so `if ($days > 10)` prints nothing and leaves a file named `10` in the folder (`Remove-Item 10` takes it away). Compare with `-eq` and `-gt`. All of this works the same in Windows PowerShell 5.1, and on a Mac or Linux.

**Try it.** Add a check that stops with *The backup folder can't be the folder you're backing up.* when `-Destination` is the same as `-Path`. Then run `.\Backup-Folder.ps1 -Destination homework`.

## Check yourself

2 questions to try on the lesson page.

## So what

With `if`, `elseif`, `else` and a few joined tests, a script stops doing the same thing every time and starts doing the right thing: copying only what changed, rehearsing when asked, and explaining itself when it can't go on.

## Key terms

- [if Statement](https://www.ask-codey.com/glossary/if-statement-powershell)
- [Logical Operators](https://www.ask-codey.com/glossary/logical-operators-powershell)
- [Comparison Operators](https://www.ask-codey.com/glossary/comparison-operators-powershell)
- [Boolean](https://www.ask-codey.com/glossary/boolean)
- [Exit Code](https://www.ask-codey.com/glossary/exit-code-operating-system)

## Cheat sheets

- [If This, Then That: \`if\`, \`elseif\` and \`else\`](https://www.ask-codey.com/cheat-sheets/powershell-if-statements-cheat-sheet)

## Related

- [Parameters: \`param()\`](https://www.ask-codey.com/lessons/powershell-param)
- [Filtering: Where-Object and Comparisons](https://www.ask-codey.com/lessons/powershell-where-object)
- [Is It There? Test-Path](https://www.ask-codey.com/lessons/powershell-test-path)
- [Did It Work? \`$?\`, \`$LASTEXITCODE\`, \`&&\` and \`||\`](https://www.ask-codey.com/lessons/powershell-did-it-work)
- [Many Choices: \`switch\`](https://www.ask-codey.com/lessons/powershell-switch)

Source: https://www.ask-codey.com/lessons/powershell-if-statements
