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

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:

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:

. .\PlaylistTools.ps1
Get-Command Remove-Song -Syntax
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:

Get-Song -Mood Chill | Remove-Song -WhatIf
(Get-Song).Count
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:

Get-Song | Where-Object Title -eq 'Rainy Overpass' | Remove-Song
Get-Song -Mood Chill
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:

Get-Song -Mood Chill | Remove-Song -Confirm
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

Cheat sheets

Related