95

I'm trying to take user input and before proceeding I would like get a message on screen and than a confirmation, whether user wants to proceed or not. I'm using the following code but its not working:

write-host "Are you Sure You Want To Proceed:"  -Confirm

12 Answers 12

187

-Confirm is a switch in most PowerShell cmdlets that forces the cmdlet to ask for user confirmation. What you're actually looking for is the Read-Host cmdlet:

$confirmation = Read-Host "Are you Sure You Want To Proceed:"
if ($confirmation -eq 'y') {
    # proceed
}

or the PromptForChoice() method of the host user interface:

$title    = 'something'
$question = 'Are you sure you want to proceed?'

$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No'))

$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($decision -eq 0) {
    Write-Host 'confirmed'
} else {
    Write-Host 'cancelled'
}

Edit:

As M-pixel pointed out in the comments the code could be simplified further, because the choices can be passed as a simple string array.

$title    = 'something'
$question = 'Are you sure you want to proceed?'
$choices  = '&Yes', '&No'

$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($decision -eq 0) {
    Write-Host 'confirmed'
} else {
    Write-Host 'cancelled'
}
Sign up to request clarification or add additional context in comments.

4 Comments

It works without the explicit types and object declarations: $decision = $Host.UI.PromptForChoice('something', 'Are you sure you want to proceed?', @('&Yes'; '&No'), 1)
FYI, in a rich environment (like PowerShell ISE), $message is the title of the pop-up window. So, you really need to keep that short, and put your whole message (including the question) into the $question variable. ($message should really just be renamed to $title).
Hmm I'm getting this on PS 4.0 running on Exchange Management Shell, might have to use the full explicit object declarations: Cannot convert argument "choices", with value: "System.Object[]", for "PromptForChoice" to type "System.Collections.ObjectModel.Collection`1[System.Management.Automation.Host.ChoiceDescription]"
@freddygrande If passing as an array, you need at least two choices, then the conversion should work. Otherwise just pass directly as a string like $Host.UI.PromptForChoice('t', 'q?', '&Yes', 0)
29

This is a simple loop that keeps prompting unless the user selects 'y' or 'n'

$confirmation = Read-Host "Ready? [y/n]"
while($confirmation -ne "y")
{
    if ($confirmation -eq 'n') {exit}
    $confirmation = Read-Host "Ready? [y/n]"
}

4 Comments

The break will exit the while loop properly instead of exit! It does depend on the context: break vs exit vs return @dallyack
Don't use read-host for confirmations, and don't use exit to break.
This was perfecto! I absolutley wanted to exit NOT break.
Use a doo...while loop and you don't need to repeat the Read-Host line: do { $yn = Read-Host "Ready? [y/n]"; if ($yn-eq 'n') {exit}; } while($yn -ne "y")
27

Read-Host is one example of a cmdlet that -Confirm does not have an effect on.-Confirm is one of PowerShell's Common Parameters specifically a Risk-Mitigation Parameter which is used when a cmdlet is about to make a change to the system that is outside of the Windows PowerShell environment. Many but not all cmdlets support the -Confirm risk mitigation parameter.

As an alternative the following would be an example of using the Read-Host cmdlet and a regular expression test to get confirmation from a user:

$reply = Read-Host -Prompt "Continue?[y/n]"
if ( $reply -eq 'y' ) { 
    # Highway to the danger zone 
}

The Remove-Variable cmdlet is one example that illustrates the usage of the -confirm switch.

Remove-Variable 'reply' -Confirm

Additional References: CommonParameters, Write-Host, Read-Host, Comparison Operators, Regular Expressions, Remove-Variable

1 Comment

No need to bring out regex. -eq is case insensitive. $reply -eq 'y' would suffice.
17

Here is the documentation from Microsoft on how to request confirmations in a cmdlet. The examples are in C#, but you can do everything shown in PowerShell as well.

First add the CmdletBinding attribute to your function and set SupportsShouldProcess to true. Then you can reference the ShouldProcess and ShouldContinue methods of the $PSCmdlet variable.

Here is an example:

function Start-Work {
    <#
    .SYNOPSIS Does some work
    .PARAMETER Force
        Perform the operation without prompting for confirmation
    #>
    [CmdletBinding(SupportsShouldProcess=$true)]
    param(
        # This switch allows the user to override the prompt for confirmation
        [switch]$Force
    )
    begin { }
    process {
        if ($PSCmdlet.ShouldProcess('Target')) {
            if (-not ($Force -or $PSCmdlet.ShouldContinue('Do you want to continue?', 'Caption'))) {
                return # user replied no
            }

            # Do work
        }

    }
    end { }
}

5 Comments

I think there's a missing closing bracket (}) exactly where the comment # Do work is.
Pretty sure it's just weird formatting in the markdown, did you try pasting the code into an IDE to see if there were any compiler errors?
No, I just saw that you don't have a closing bracket for your ShouldProcess condition, but maybe it is a weird formatting that's why I said I think
I fixed the formatting issue so the braces line up.
Almost there...
11

write-host does not have a -confirm parameter.

You can do it something like this instead:

    $caption = "Please Confirm"    
    $message = "Are you Sure You Want To Proceed:"
    [int]$defaultChoice = 0
    $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Do the job."
    $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Do not do the job."
    $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)
    $choiceRTN = $host.ui.PromptForChoice($caption,$message, $options,$defaultChoice)

if ( $choiceRTN -ne 1 )
{
   "Your Choice was Yes"
}
else
{
   "Your Choice was NO"
}

1 Comment

This is way better, I think, since there will be 3 otpions. The last one will be help and there you can add a bit more clear explanation what actually "yes" and "no" are doing.
11
Write-Warning "This is only a test warning." -WarningAction Inquire

from: https://serverfault.com/a/1015583/584478

Comments

10

For when you want a 1-liner

while( -not ( ($choice= (Read-Host "May I continue?")) -match "^(y|n)$")){ "Y or N ?"}

2 Comments

@BrainSlugs83 You took the trouble to comment on / downvote most of the answers using read-host? Will you also get the PowerShell docs updated too, to not say, The Read-Host cmdlet reads a line of input from the console. You can use it to prompt a user for input? -- learn.microsoft.com/en-us/powershell/module/…
Warning: you one-liner will exit if the entered string contain a "y" or "n" whatever its position ! Fix: while( -not ( ($choice= (Read-Host "May I continue?")) -match "^(y|n)$")){ "Y or N ?"}
2

Here's a solution I've used, similiar to Ansgar Wiechers' solution;

$title = "Lorem"
$message = "Ipsum"

$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "This means Yes"
$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "This means No"

$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

$result = $host.ui.PromptForChoice($title, $message, $Options, 0)

Switch ($result)
     {
          0 { "You just said Yes" }
          1 { "You just said No" }
     }

1 Comment

If they close the dialog, $result will not be 0 or 1.
2

A slightly prettier function based on Ansgar Wiechers's answer. Whether it's actually more useful is a matter of debate.

function Read-Choice(
   [Parameter(Mandatory)][string]$Message,
   [Parameter(Mandatory)][string[]]$Choices,
   [Parameter(Mandatory)][string]$DefaultChoice,
   [Parameter()][string]$Question='Are you sure you want to proceed?'
) {
    $defaultIndex = $Choices.IndexOf($DefaultChoice)
    if ($defaultIndex -lt 0) {
        throw "$DefaultChoice not found in choices"
    }

    $choiceObj = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]

    foreach($c in $Choices) {
        $choiceObj.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList $c))
    }

    $decision = $Host.UI.PromptForChoice($Message, $Question, $choiceObj, $defaultIndex)
    return $Choices[$decision]
}

Example usage:

PS> $r = Read-Choice 'DANGER!!!!!!' '&apple','&blah','&car' '&blah'

DANGER!!!!!!
Are you sure you want to proceed?
[A] apple  [B] blah  [C] car  [?] Help (default is "B"): c
PS> switch($r) { '&car' { Write-host 'caaaaars!!!!' } '&blah' { Write-Host "It's a blah day" } '&apple' { Write-Host "I'd like to eat some apples!" } }
caaaaars!!!!

Comments

1

This version asks if the user wants to perform an action before continuing with the rest of the script.

DO
{
    $confirmation = Read-Host "Do want Action before continue? [Y/N]"
    if ($confirmation -eq 'y') {
       write-Host "Doing the Action"
    }
} While (($confirmation -ne 'y') -and ($confirmation -ne 'n'))

Comments

0

I prefer a popup.

$shell = new-object -comobject "WScript.Shell"
$choice = $shell.popup("Insert question here",0,"Popup window title",4+32)

If $choice equals 6, the answer was Yes If $choice equals 7, the answer was No

1 Comment

This has the major disadvantage that it won't adapt to the host you're using. So if you're remoting into a server, for example, this will fail at best or freeze the script at worst.
0

I think this is what you are looking for.

To have a function or script behave as a cmdlet in this regard, you should use ConfirmImpact='High' in the CmdletBinding as well.

Then PowerShell will automatically prompt the user.

To improve on the answer somewhat above from Zack, use...

function Start-Work {
  [CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]
  param(
  )

  if (-not $PSCmdlet.ShouldProcess('')) {
     return
  }

  Write-Host 'Process did run'

}

Start-Work -Confirm:$false will still run the function without confirmation.

The prompting will depend on the preference variable $ConfirmPreference, that defaults to 'High'.
(See about_Preference_Variables)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.