Reverse Logic [switch] parameters?

I answer a great deal of “how do I do this” type questions regarding powershell scripting. And one thing that stands out more than anything else is when something “could” be figured out by the folks trying to write the scripts. They often send me scripts that look like they have the correct and logical syntax, but somewhere along the line a bad idea jumps into the mix. My latest “smack my head” moment comes from the Set-VM PowerCLI cmdlet. It contains a [switch] switch parameter that is defaulted to $true. Here is some quick code to demonstrate:

So Set-VM has a -Confirm switch. Switch parameters should be thought of being used to turn something “ON”, but in this case it is already on by default. Passing the -Confirm switch by itself simply does nothing. Unless the switch name itself indicates that it is turning some functionality “OFF” by flipping the switch “ON”, one tends to believe that a switch is enabling some sort of functionality. In this case it makes sense for the Set-VM cmdlet to default to doing confirmations on actions. So it doesn’t make sense to define -Confirm, since the process is already going to do that. Instead, removing the confirmation prompt should have been done with a more appropriately name switch parameter. Perhaps -NoConfirmation or how about the accepted -Force that we all know and love.

Was just wondering if you all have similar experiences in assisting with the powershell learning curve.

function whyBother([switch] $Confirm=$true) {
if ($Confirm.isPresent) {
Write-Output “We are going to confirm.”
} else {
Write-Output “We are NOT going to confirm”

#there is NO point in ever passing -Confirm, the results is the same as above.
whyBother -Confirm
#flip the bit to “remove” the -Confirm parameter, how often do we use the : when setting parameter values?
whyBother -Confirm:$false
#This is the traditional way we set non [switch] type parameters, so it makes sense that people would want to do it this way.
whyBother -Confirm $false

#A better switch:
function aBetterWay([switch] $Force) {
if ($Force.isPresent) {
Write-Output “We are going to FORCE the change, no confirmation”
} else {
Write-Output “We didn’t pass the -Force switch, so we will default to asking confirmation.”

aBetterWay -Force

So, a couple of fine points.

The cmdlet itself probably doesn’t “have” a -Confirm switch; that’s usually added by PowerShell when the cmdlet declares support for the ShouldProcess routines. It also adds -WhatIf.

PowerShell defaults -Confirm to $true when the cmdlet’s declared ImpactLevel is the same, or higher than, the built-in $ConfirmPreference variable (“Low,” “Medium,” “High”). So the switch is in deed enabling something, it’s just enabling it by default. You could also run with -Confirm:$false to override that and make the switch false.

Confirm is a special case. If you specify -Confirm (set to $true), the command will always give you confirmation prompts. If you specify -Confirm:$false , the command will never give you confirmation prompts. If you don’t use the -Confirm switch at all, then the behavior depends on the value of the command’s declared ConfirmImpact value and your $ConfirmPreference setting. The default $ConfirmPreference is High, and the command you’re describing must also have a ConfirmImpact of High.

If you were to set your $ConfirmPreference variable to ‘None’, it would have the same effect as using -Confirm:$false on all commands.