Search code examples
powershellparameter-passingswitch-parameter

Powershell behaviour of [Switch]-Parameter


I'm trying to understand the behaviour of -switch parameters, especially when passing them to other functions.

My underlying question is: How do I have to pass the variable of a switch parameter to another function with a switch parameter so the variable keeps its value. At the moment, it looks like I'm always passing "true" to the underlying functions, just for the fact that the parameter is passed.

To illustrate my problem, i wrote this test script:

function testswitch{
    param(
        [switch]$foo
    )    
    if ($foo -eq $true) {
        "testswitch yes"
    } else {
        "testswitch no"
    }
}

function testbool{
    param(
        [bool]$foo
    )
    if ($foo -eq $true) {
        "testbool yes"
    } else {
        "testbool no"
    }
}

function test{
    param(
        [switch]$foo
    )
    "received value:"
    if ($foo -eq $true) {
        "test yes"
    } else {
        "test no"
    }

    "passed calls:"
    testswitch -foo $foo
    testbool -foo $foo
    "negated calls:"
    testswitch -foo (!$foo)
    testbool -foo (!$foo)
}
cls
test
"-----"
test -foo
"-----"
test -foo:$false

which returns this output:

received value:
test no
passed calls:
testswitch yes
testbool no
negated calls:
testswitch yes
testbool yes
-----
received value:
test yes
passed calls:
testswitch yes
testbool yes
negated calls:
testswitch yes
testbool no
-----
received value:
test no
passed calls:
testswitch yes
testbool no
negated calls:
testswitch yes
testbool yes

As you can see "testswitch" is always returning "yes" - which is not what i want it to be. Unfortunately, It's pretty hard to find decent information about the switch parameter on google, as there is also the conditional statement which gets a lot of the hits based on the keywords i can come up with.

edit: sorry @mklement0 but i woud've never guessed that your suggested solution would have the answer i needed, just based on the title the issues seem to different.


Solution

  • Parameter binding against a [switch] is tricky because the mere presence of the -SwitchName parameter (with no explicit argument value after) is enough - PowerShell see testswitch -foo $foo and goes "user specified -foo present, and then they gave me some, unrelated, positional argument $foo".

    To override this behavior, you can either tightly bind the argument to a switch parameter with a colon:

    testswitch -foo:$foo
    

    ... or you can splat the argument and PowerShell will correctly figure out how to pass the arguments:

    testswitch @PSBoundParameters
    

    Both of these approaches are "safe", eg. binding explicit arguments tightly with : works for any parameter type at won't change any behavior (other than the switch arguments being now bound correctly)