Reverse Logic [switch] parameters?

This topic contains 2 replies, has 3 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 2 years, 1 month ago.

  • Author
    Posts
  • #20394
    Profile photo of Christopher Maahs
    Christopher Maahs
    Participant

    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"
    }
    }

    whyBother
    #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
    aBetterWay -Force

  • #20395
    Profile photo of Don Jones
    Don Jones
    Keymaster

    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.

  • #20396
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    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.

You must be logged in to reply to this topic.