1

I am trying to understand what the relationship between the $? and $lastexitcode variables versus the -Confirm flag in Powershell cmdlets.

Say for example you run a command with -confirm it will prompt you accordingly for action:

PS C:\temp> rm .\foo.txt -confirm
Confirm

Are you sure you want to perform this action?

Performing the operation "Remove Directory" on target "C:\temp\foo.txt".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
(default is "Y"):n

PS C:\temp> $?

True

I understand that technically the command ran successfully, but if the user chose no then the command did not run.

My question is how to I obtain the user's answer to the -Confirm flag?

chwarr
  • 6,777
  • 1
  • 30
  • 57
DJ Brett van
  • 11
  • 1
  • 5
  • The question title asked how to use -Confirm while the actual question is how to get the user's input from -Confirm. For folks skimming along like me just looking for how to use confirm, consider using the ```[cmdletbinding(SupportsShouldProcess)]``` along with an if block ```if ($PSCmdlet.ShouldProcess("The Item" , "The Change")) {``` around relevant logic. This is a slick, built-in way to add confirm provided you don't need to get the user's answer. For a reference see https://sqldbawithabeard.com/2018/01/25/how-to-write-a-powershell-function-to-use-confirm-verbose-and-whatif/ – Negatar Jan 09 '20 at 22:52

2 Answers2

2

$?, $LastExitCode, and -Confirm are completely unrelated to each other.

$? is an automatic variable with a boolean value indicating whether or not the last (PowerShell) operation was executed successfully.

$LastExitCode is an automatic variable with the exit code of the external command that was last executed (an integer value).

-Confirm is a common parameter controlling whether or not a cmdlet prompts the user for confirmation of its action.

To my knowledge PowerShell does not store the answer given to a -Confirm prompt anywhere, so if you need that response for something else you'll have to prompt the user yourself, e.g. like this:

function Read-Confirmation {
  Param(
    [Parameter(Mandatory=$false)]
    [string]$Prompt,
    [Parameter(Mandatory=$false)]
    [string]$Message
  )

  $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'))

  -not [bool]$Host.UI.PromptForChoice($Message, $Prompt, $choices, 1)
}

$doRemove = if ($PSBoundParameters['Confirm'].IsPresent) {
  Read-Confirmation -Prompt 'Really delete'
} else {
  $true
}

if ($doRemove) {
  Remove-Item .\foo.txt -Force
}
Community
  • 1
  • 1
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
0

AFAIK, it is not possible to capture the user's response to the confirmation prompt; it is not a part of PowerShell's command history, and while you might be able to get the information from the buffer somehow that would only be supported in the default PowerShell host as other hosts will use different buffers. In this case it is probably best to either do a separate confirmation within your script using an if statement.

$userAnswer = Read-Host "Are you sure you wish to proceed?"
if($userAnswer -eq "yes"){
    rm .\foo.txt
}    

Then just use the $userAnswer variable to know what your user responded with. Alternatively you could determine their answer by checking to see if the operation was completed. This would be my preferred method as this way you are SURE that the file has been deleted rather than assuming so because the cmdlet successfully executed and the user confirmed (the reliability is probably not any different here considering that remove-item is incredibly well tested but it could make a difference if you are using a third-party library of some kind) that would look something like the below.

rm .\foo.txt -Confirm

if(Test-Path .\foo.txt){
    $success = $false
} else {
    $success = $true
}

and if you really need to know whether it failed to delete due to an error or the user saying no you could do something like

rm .\foo.txt -Confirm


if(Test-Path .\foo.txt){
    $success = $false
} else {
    $success = $true
}

if(!($success) -and (!($?))){
    $status = "Previous command failed"
} elseif (!($success) -and $?){
    $status = "User cancelled operation"
} 

Hope that helps.

chwarr
  • 6,777
  • 1
  • 30
  • 57
Mike Garuccio
  • 2,588
  • 1
  • 11
  • 20