Adding custom confirmation to commands

We recently had a customer question where they were concerned that some commands might be typed accidentally and end up causing significant disruption. In general, commands that fit that classification include a confirmation message to warn you, but sometimes you just don’t agree with what the cmdlet author thought was a high-impact action. While Restart-Computer might be a day-to-day operation for some servers, it might be certain doom for others.

So let’s pretend you want to make Stop-Process prompt you whenever you run it.

In PowerShell V3, the solution is amazing with PSDefaultParameterValues. In this case, it will opt in to the ‘WhatIf’ behaviour by default, which you can override if you want:

4 [C:\]
>> $PSDefaultParameterValues["Stop-Process:WhatIf"] = $true

5 [C:\]
>> Stop-Process -name notepad
What if: Performing the operation "Stop-Process" on target "notepad (5936)".

6 [C:\]
>> Stop-Process -name notepad -WhatIf:$false

(Notepad stops)                                                                                                                                                         

In PowerShell V2, the solution is still pretty handy. You can use PowerShell’s proxy function APIs insert your own logic into a cmdlet. In this case, we can have it confirm:

19 [C:\]
>> Set-HighImpactCommand Stop-Process

20 [C:\]
>> Stop-Process -Name Notepad

Invoke Stop-Process?
Stop-Process has high impact. Invoke?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): N
Invocation of Stop-Process was discontinued.
At line:25 char:106
+ ... -Process?')) { throw 'Invocation of Stop-Process was discontinued.' }
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Invocation of S...s discontinued.:String) [], RuntimeException
    + FullyQualifiedErrorId : Invocation of Stop-Process was discontinued.
 

21 [C:\]
>> Stop-Process -Name Notepad

Invoke Stop-Process?
Stop-Process has high impact. Invoke?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): Y

22 [C:\]                                                                                                                                                        

And the function that does the magic?

001

002

003

004

005

006

007

008

009

010

011

function Set-HighImpactCommand

{

    param($CommandName)

   

    $MetaData = New-Object System.Management.Automation.CommandMetaData (Get-Command $CommandName -CommandType Cmdlet)

    $functionContent = ([System.Management.Automation.ProxyCommand]::Create($MetaData))

    $updatedFunction = $functionContent -replace "begin`r`n{",

        "begin`r`n{`r`n if(-not `$PSCmdlet.ShouldContinue('$CommandName has high impact. Invoke?', 'Invoke ${CommandName}?')) { throw 'Invocation of $CommandName was discontinued.' }`r`n"

    Set-Item function:\GLOBAL:$CommandName $updatedFunction

}

4 Responses to “Adding custom confirmation to commands”

  1. June Blender writes:

    Is there a way to make PSDefaultParameterValues contingent on the value of another parameter? For about topics, I use ShowWindow, but it shows only the first paragraph of cmdlet parameter descriptions, so for cmdlets, I want Online.

    e.g.
    if (Get-Help -Name -like “about*”) {[email protected]{Get-Help:ShowWindows=$true} else ([email protected]{Get-Help:Online = $true}

    Thanks!

  2. Kirk Munro writes:

    The biggest downside to the v2 approach is that ShouldContinue does not allow you to indicate that you don’t want a default option. It automatically defaults to “Y” as the default, so you could end up invoking the high-impact action by simply hitting enter twice. There is a workaround for this, which is to use $host.UI.PromptForChoice, however you end up rewriting a lot of what you get for free in ShouldContinue in order to force an explicit decision to run the command. That would be a better approach for v2 users though, because otherwise the high-impact actions are just an accidental enter key away.

  3. Dew Drop – March 30, 2015 (#1983) | Morning Dew writes:

    […] Adding custom confirmation to commands (Lee Holmes) […]

  4. @evilSnobu writes:

    This is very handy in the context of Get-AD* cmdlets, which don’t get the actual useful stuff by default.

    $PSDefaultParameterValues[‘Get-ADComputer:Properties’] = ‘Description’

    PS> get-adcomputer PC

    Description : Some box out there, lost in the corporate shenanigans
    DistinguishedName : CN=PC,OU=Computers,DC=myDC,DC=local
    [..]

Leave a Reply