Closed bergmeister closed 4 years ago
@bergmeister , this cmdlet is implemented with both ShouldContinue and ShouldProcess, -Confirm:$false can only override ShouldProcess, you have to specify -Force to override ShouldContinue. Please let us know if any comment, thanks.
@erich-wang why are you using ShouldContinue? In the vast majority of use cases ShouldProcess is more than sufficient. If you need to prompt by default, typically setting ConfirmImpact = "High"
is the recommended route.
ShouldContinue
and -Force
are generally a bad pattern to follow, not least because the prompts generated by ShouldContinue
are indistinguishable from ShouldProcess
.
From @markcowl:
-Confirm is an automatic parameter completely handled by PowerShell. It impacts the display of ShouldProcess prompts without intervention from the cmdlet.
-Force is a parameter that is defined by convention for any cmdlet that also implements ShouldContinue prompts, and avoids the Should continue prompts.
It is entirely expected that settings to the -Confirm parameter have no impact whatsoever on the ShouldContinue.
This may be confusing to people who are not initimately familiar with PowerShell confirmation, but we need to respect the actual confirmation conventions of PowerShell.
You can find more about confirmation here:
or you can see a really detailed discussion of this in this gist, when we made cmdlet confirmation compliant with PowerShell recommendations across the board. This specific case is mentioned there: https://gist.github.com/markcowl/338e16fe5c8bbf195aff9f8af0db585d
@vexx32, we'll close this issue as by design because of it is recommended implementation by PowerShell team. Please let us know if any concern, or you could raise one discussion with powershell team at https://github.com/PowerShell/PowerShell/issues, thanks.
@erich-wang Guidance in the listed article is from 2016. I've not seen a cmdlet introduced since well before that point that implements a -Force
parameter.
Unlike -Confirm
and -WhatIf
, -Force
is not an automatic parameter that is bundled with ShouldProcess
. It's a kludge, at best, in my opinion. ShouldContinue()
is not a necessary method, and -- again, in my opinion -- is best left as an implementation detail for ShouldProcess()
's own prompting use, as I understand it.
However, there are the occasional case where it may be considered "necessary" to always prompt. In my own opinion, that's kind of exactly what ConfirmImpact
exists for -- set it to High
and it will always prompt unless a user has deliberately altered their $ConfirmPreference
variable to bypass it.
The PowerShell team may have their own guidance (/cc @SteveL-MSFT for additional perspective).
I'm rather surprised that such a method is being used, and even more surprised that it is supposedly recommended to essentially re-implement what is already being done with ShouldProcess()
. The example from the article is:
protected override void ProcessRecord()
{
if (ShouldProcess("ShouldProcess target"))
{
if (Force || ShouldContinue("", ""))
{
// Add code that performs the operation.
}
}
}
This is lacking information. @sdwheeler and @SteveL-MSFT: I think we should update that article. It only refers to use of ShouldContinue
; use of ShouldProcess()
on its own is generally sufficient for all but the most harmful operation.
@erich-wang from a more pragmatic standpoint, I don't think it helps your users to expect them to be intimately familiar with the mechanisms with which PowerShell handles prompting. If you're providing a -Confirm
parameter by implementing ShouldProcess()
, your cmdlet should be respecting the value of said parameter unless the operation being performed should always be prompted for regardless of user preferences.
In general, such prompts are reserved only for unduly / unexpectedly harmful operations. The common example is trying to delete a non-empty directory with Remove-Item
and not supplying -Recurse
; in this case, the invocation could be a mistake, the user may have wanted to target a file instead, and deleting an entire directory could be hazardous.
Is this similarly hazardous / unexpected behaviour? As I understand the purpose of the cmdlet, I don't think the mandatory / unavoidable prompt is necessary here.
Yes, I agree with @vexx32 that although this used to be a recommendation from the PowerShell team, the practical experience from various cmdlets (the most famous one being install-module) showed that the original recommendation has some downsides that only showed up over time as functionality of cmdlets grew and I think most people would agree that it's now more of an anti-pattern that should not be used any more in modern PowerShell. The main problem with the approach is not only that one cannot use the confirm parameter (which would be the intuitive UX) but moreover that the Force parameter grows slowly to a dangerous beast, where users confirm the action without knowing which warning messages are being ignored as the force parameter ignores all of them. This contradicts modern security where one should only turn off the warnings one by one for a better understanding and reduced vulnerability surface because there could be cases where force is used but important warnings are ignored that might not be desired to be ignored, therefore the user does not have much of a choice. Whilst it is nice to have a single switch to say 'just do it, I take responsibility', one also needs to be given the opportunity to only opt into ignoring some warnings, which brings us back to the usage of shouldprocess/shouldcontinue where the non-interactive scenario needs to work as well, therefore the best solution seems to be here to not use ShouldContinue but rather ShouldProcess. Since you cannot remove the force parameter without a breaking change, I suggest an additional parameter for some cmdlets where there is more than one ShouldProcess command to allow the user to override a selected set of warnings only, the best might be to make this parameter take a hashtable
I think @erich-wang has it right - shouldprocess
and shouldcontinue
have distinct uses. ShouldProcess is used for normally state changing operations, but ShouldContinue is set by the developer on operations which are especially sensitive (or destructive). I think our guidance is still valid and the discussion here seems to me suggests that in this case shouldcontinue
should not be used. However, I'm not sure I agree. It seems that remove-azresourcegroup
is a pretty destructive operation with which there is some benefit to the "belt-and-braces (suspenders)" approach. It's about providing extra confirmation on especially destructive operations.
Thanks @bergmeister for taking the time to open this issue and all for the follow-up discussion. As indicated by @erich-wang this behavior has a by design aspect.
Below you describes how the implementation is done based on the current conventions commonly adopted by PowerShell that we are following for consistency and usability:
-Confirm is an automatic parameter completely handled by PowerShell that impacts the display of ShouldProcess prompts without intervention from the cmdlet.
-Force is a parameter that is defined by convention for any cmdlet that also implements ShouldContinue prompts, and avoids the ShouldContinue prompts.
Even if this article from @markcowl is a bit old, it has relevant additional details about the implementations of the confirmation prompts with Azure PowerShell: https://gist.github.com/markcowl/338e16fe5c8bbf195aff9f8af0db585d
If you want to make suggestions for changes on this implementation, the following repo is where the community can review and comment: https://github.com/PowerShell/PowerShell-RFC
Thanks, Damien - Azure PowerShell PM
10471 Description
When passing in
-Confirm:$false
it should override confirmation prompts so that one does not need to the use the-Force
parameter which is very overloaded and dangerous. However, it still prompts and I have to use the-Force
parameterSteps to reproduce
Example in CloudShell:
Environment data
CloudShell
Module versions