# \`-WhatIf\` in Your Own Tools

SupportsShouldProcess in \[CmdletBinding()\] gives a function -WhatIf and -Confirm, and wrapping each change in if ($PSCmdlet.ShouldProcess(target, action)) makes it print a What if: line instead of changing anything, or ask before each change, exactly like Remove-Item.

Freelancer · PowerShell · Updated November 10, 2026

## After this lesson you can

- Add -WhatIf and -Confirm to a function with SupportsShouldProcess, and wrap each change in $PSCmdlet.ShouldProcess()
- Choose which commands need SupportsShouldProcess, and give ShouldProcess a target and action that say what would change

## Key takeaways

- [CmdletBinding(SupportsShouldProcess)] gives your function -WhatIf and -Confirm, the same switches Remove-Item has.
- Wrap each change in if ($PSCmdlet.ShouldProcess(target, action)) { }. It returns True to go ahead, False under -WhatIf, and asks first under -Confirm.
- The target and action you give it become the What if: line, so name the thing and say what would happen to it.
- A tool that removes or replaces something needs it. A Get- tool only reads, so it never does.

In *Deleting Safely: `Remove-Item`, `-WhatIf` and `-Confirm`* you learned to rehearse every delete. Now you're writing a delete of your own: `Remove-Song` takes songs out of the playlist file. The first person to use it, maybe you, will run it with `-WhatIf` to see what it would do. If the tool doesn't know `-WhatIf`, one of two things happens. An advanced function stops with "A parameter cannot be found that matches parameter name 'WhatIf'". A plain function is worse: it ignores the switch, as it ignored `-Genre` in *Advanced Functions: `[CmdletBinding()]`*, and removes the songs for real. Any tool that changes things, from an IT team's account cleanup to your playlist, should rehearse the way PowerShell's own commands do.

Start fresh with the practice-folder lines from *Functions: Naming a Job*, then load `PlaylistTools.ps1`.

## SupportsShouldProcess: the switches

Add this function to `PlaylistTools.ps1`. It takes songs from the pipeline, as Limit-Playlist does in *Taking Pipeline Input*:

```powershell
function Remove-Song {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        $Song,
        [string]$Path = 'road-trip.csv'
    )
    begin {
        $titles = @()
    }
    process {
        if ($PSCmdlet.ShouldProcess($Song.Title, 'Remove song')) {
            $titles += $Song.Title
        }
    }
    end {
        if ($titles) {
            $keep = Get-Song -Path $Path | Where-Object Title -notin $titles
            $keep | Export-Csv -Path $Path -Confirm:$false
        }
    }
}
```

`SupportsShouldProcess` inside `[CmdletBinding()]` says "this tool changes things, so it supports rehearsing". Load the file and look at the syntax:

```powershell
. .\PlaylistTools.ps1
Get-Command Remove-Song -Syntax
```

```text
Remove-Song [-Song] <Object> [[-Path] <string>] [-WhatIf] [-Confirm] [<CommonParameters>]
```

`-WhatIf` and `-Confirm` are there, and you didn't write either of them.

## ShouldProcess: ask before each change

The switches alone change nothing: your function has to ask before it acts. `$PSCmdlet` is the running function itself, and **`$PSCmdlet.ShouldProcess()`** (read "should process") is the question "should I go ahead with this one?". It answers True or False:

- run normally, it says True, and the change happens;
- with `-WhatIf`, it prints a `What if:` line and says False, so the change is skipped;
- with `-Confirm`, it asks the person, and says what they answered.

It takes two things: the **target**, what will change (here the song's title), and the **action**, what will happen to it. Rehearse removing every Chill song:

```powershell
Get-Song -Mood Chill | Remove-Song -WhatIf
(Get-Song).Count
```

```text
What if: Performing the operation "Remove song" on target "Rainy Overpass".
What if: Performing the operation "Remove song" on target "Cruise Control".
What if: Performing the operation "Remove song" on target "Last Exit Home".
7
```

Three lines, one for each song, and all seven songs are still there. Your target and action are the words in quotes, so choose words that make the line clear to someone else. Each song is checked in `process`, and the file is written once, in `end`, after the last song has arrived and Get-Song has finished reading it. Now remove one song for real:

```powershell
Get-Song | Where-Object Title -eq 'Rainy Overpass' | Remove-Song
Get-Song -Mood Chill
```

```text
Title          Artist         Minutes Mood
-----          ------         ------- ----
Cruise Control The Night Owls 5       Chill
Last Exit Home Juniper Kite   4       Chill
```

## -Confirm: one at a time

`-Confirm` asks about each song before anything happens:

```powershell
Get-Song -Mood Chill | Remove-Song -Confirm
```

```text
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove song" on target "Cruise Control".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): n

Confirm
Are you sure you want to perform this action?
Performing the operation "Remove song" on target "Last Exit Home".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): n
```

Two answers of `n`, and nothing is removed. Here's why Export-Csv has `-Confirm:$false`: `-WhatIf` and `-Confirm` reach the commands inside your function too, so without it, Export-Csv would ask a third time, about overwriting `road-trip.csv`. You've already answered for each song, so the file is written without asking again.

## Which tools need it?

Any tool that removes, replaces or changes something: `Remove-`, `Set-`, `Clear-`, `Rename-`. `Add-` and `New-` tools can have it too, and PowerShell's own `New-Item` does. A `Get-` tool only reads, so it never needs it: rehearsing a read would be the read itself. Everything here works the same in Windows PowerShell 5.1 and on a Mac or Linux.

**Try it.** Rehearse removing every song by Juniper Kite. Then put back the playlist with the practice-folder lines, and remove them for real.

## Check yourself

2 questions to try on the lesson page.

## So what

A tool that removes things should rehearse like `Remove-Item`. Two lines, `SupportsShouldProcess` and `ShouldProcess`, mean nobody has to trust your delete blindly, including you.

## Key terms

- [-WhatIf and -Confirm](https://www.ask-codey.com/glossary/whatif-and-confirm)
- [SupportsShouldProcess](https://www.ask-codey.com/glossary/supportsshouldprocess)
- [ShouldProcess](https://www.ask-codey.com/glossary/shouldprocess)
- [Advanced Function](https://www.ask-codey.com/glossary/advanced-function)

## Cheat sheets

- [\`-WhatIf\` in Your Own Tools](https://www.ask-codey.com/cheat-sheets/powershell-supports-should-process-cheat-sheet)

## Related

- [Deleting Safely: Remove-Item, -WhatIf and -Confirm](https://www.ask-codey.com/lessons/powershell-deleting-safely)
- [Taking Pipeline Input](https://www.ask-codey.com/lessons/powershell-pipeline-input)
- [Help for Your Tool](https://www.ask-codey.com/lessons/powershell-comment-based-help)
- [Advanced Functions: \`\[CmdletBinding()\]\`](https://www.ask-codey.com/lessons/powershell-advanced-functions)

Source: https://www.ask-codey.com/lessons/powershell-supports-should-process
