1

I have a switch statement inside a function like so:

function SomeFunc {
    [CmdletBinding()]
    Param(
        [Parameter(Position = 0)]
        [switch]$History
    )
    Process {
    switch ($PSBoundParameters.keys) {
        'History' {$PSBoundParameters.keys}
        Default {write-host "No Parameters used"} 
        }
    }
}

If I invoke SomeFunc -History "History" gets printed, as expected. but for the life of me, I cannot get the default condition to trigger, I am expecting "No Parameters used" to print when I invoke only "SomeFunc"

Any help on this would be really wellcome.

  • 3
    `AutomationNull.Value` does not get enumerated – Santiago Squarzon Jan 03 '23 at 02:31
  • 2
    True, @SantiagoSquarzon, but here it is actually an _empty collection_ that is the problem, and I think it's worth discussing the non-obvious enumeration behavior of `switch` in general, so I took the liberty of reopening this question. – mklement0 Jan 03 '23 at 15:58
  • 1
    @mklement0 good clarification, I do believe this exact question has been asked before tho – Santiago Squarzon Jan 03 '23 at 17:06
  • 2
    @SantiagoSquarzon, I didn't look too hard, but if you can find a bona fide duplicate, we can close this question again; I just searched my own notes again and found [this post](https://stackoverflow.com/q/59402280/45375), which may qualify as a duplicate, though it's focused mostly on AutomationNull and mentions the empty-collection case only in passing. – mklement0 Jan 03 '23 at 17:15

1 Answers1

3

tl;dr

  • Because $PSBoundParameters.Keys is an empty collection when no arguments are passed, the switch statement's body is never entered.

  • Use $PSBoundParameters.Count -eq 0 to detect if no parameters were passed.


It isn't obvious, but the switch statement enumerates its input, just like the pipeline does.

That is, if you provide an enumerable object to switch, the enumerated elements are processed, one by one. Typical examples of enumerables are arrays or collections, though not hashtables. See the bottom section of this answer for details on what PowerShell considers enumerable.

It follows that if there is nothing to enumerate, no processing takes place at all - not even the default branch is entered.

In short: Any empty enumerable causes the switch statement's body to be skipped, notably with:

Two simple examples in which a switch statement's body is skipped:

# An empty array has nothing to enumerate -> body is not entered.
switch (@()) { 
  default { 'Never get here!' }
}

# Ditto for a command that produces no output.
switch ((Get-ChildItem -Filter *NoSuchFiles*)) { 
  default { 'Never get here!' }
}
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    What a pitfall! Thank goodness you decided to elaborate on it, you just know some of us folks would be scratching our heads on this again later. Thanks allot! – hellen_dorandt89 Jan 03 '23 at 17:44