Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document the implications of passing an explicit value to a switch parameter #11797

Open
3 tasks done
surfingoldelephant opened this issue Feb 14, 2025 · 0 comments
Open
3 tasks done
Labels
area-about Area - About_ topics area-sdk-docs Area - SDK docs issue-doc-bug Issue - error in documentation

Comments

@surfingoldelephant
Copy link
Contributor

surfingoldelephant commented Feb 14, 2025

Prerequisites

  • Existing Issue: Search the existing issues for this repository. If there is an issue that fits your needs do not file a new one. Subscribe, react, or comment on that issue instead.
  • Descriptive Title: Write the title for this issue as a short synopsis. If possible, provide context. For example, "Typo in Get-Foo cmdlet" instead of "Typo."
  • Verify Version: If there is a mismatch between documentation and the behavior on your system, ensure that the version you are using is the same as the documentation. Check this box if they match or the issue you are reporting is not version specific.

Links

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_functions_advanced_parameters#switch-parameters
https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/types-of-cmdlet-parameters#switch-parameters

Summary

It's possible to pass an explicit boolean value to a switch parameter, either with hash table splatting or -Param:$bool syntax.

The implications of this (specifically, with an explicit $false value) are not currently documented, despite requiring consideration by cmdlet and function authors alike.

New-PSSession is an example of a command that does not take the implications into consideration, resulting in unexpected behavior for the user.

# The *presence* of the switch selects UseWindowsPowerShellParameterSet.
# Irrespective of the switch *value*, CreateRunspacesForUseWindowsPowerShellParameterSet() is called.
# Most PS users would not expect this to create a Windows PS session, but that's precisely what happens.
New-PSSession -UseWindowsPowerShell:$false

Details

  • Parameter sets are tied to the presence of the switch, not the value. Modifying command behavior based on the parameter set is problematic if a switch controls which parameter set is chosen.

    function Test { 
        param ([Parameter(ParameterSetName = 'SwitchParam')] [switch] $SwitchParam) 
        switch ($PSCmdlet.ParameterSetName) {
            SwitchParam { 'Switch behavior' }
            default     { 'Default behavior' }
        } 
    }
    
    Test                     # Default behavior
    Test -SwitchParam:$true  # Switch behavior
    Test -SwitchParam:$false # Switch behavior

    For real-world examples where this is problematic, see:

  • As of v7.6.0, there are at least 10 commands shipped with PowerShell that ignore an explicit $false switch value due to using the above practice. See Treat -Switch:$false the same as omitting a switch when selecting a parameter set PowerShell/PowerShell#25027 (comment) for details. These commands subvert reasonable user expectation when the switch is passed an explicit $false value.

    • Get-Random -Shuffle
    • Get-SecureRandom -Shuffle
    • Get-TimeZone -ListAvailable
    • New-PSSession -UseWindowsPowerShell
    • Register-PSResourceRepository -PSGallery
    • Split-Path -Qualifier/-NoQualifier/-Leaf/-IsAbsolute (not -Extension/-LeafBase)
    • Test-Connection -Repeat/-MtuSize/-Traceroute
    • Where-Object (all non-common switch parameters)
    • Get-Uptime -Since
    • New-Guid -Empty
  • Using InvocationInfo.BoundParameters/$PSBoundParameters without checking both the key and value is similarly problematic and should generally be avoided. E.g., ContainsKey() reflects the presence of the switch, irrespective of it being passed an explicit value.

    function Test { 
        param ([switch] $SwitchParam) 
        if ($PSBoundParameters.ContainsKey('SwitchParam')) {
            'Switch behavior'
        }
    }
    
    Test -SwitchParam:$false # Switch behavior
  • The natural alternative to using switch-controlled parameter sets is to instead use a single, enum/set-based parameter and branch off that instead (though of course this is not always a viable option). For example:

    # Two separate switches with three separate parameter sets
    # Breaks down with splatting and -Param:$bool syntax.
    function SwitchBased { 
        [CmdletBinding(DefaultParameterSetName = 'Timespan')]
        param (
            [Parameter(ParameterSetName = 'Since')]
            [switch] $Since,
    
            [Parameter(ParameterSetName = 'Pretty')]
            [switch] $Pretty
        ) 
    
        switch ($PSCmdlet.ParameterSetName) {
            Timespan { 'Timespan'; break }
            Since    { 'Since';    break }
            Pretty   { 'Pretty';   break }
        } 
    }
    
    # One set-based parameter.
    # Not susceptible to the issues above. 
    function SetBased { 
        [CmdletBinding()]
        param (
            [ValidateSet('Timespan', 'Since', 'Pretty')]
            [PSDefaultValue(Help = 'Control how output is formatted.')]
            [string] $Format = 'Timespan'
        ) 
    
        switch ($Format) {
            Timespan { 'Timespan'; break }
            Since    { 'Since';    break }
            Pretty   { 'Pretty';   break }
        } 
    }

    Note: The proposal in Treat -Switch:$false the same as omitting a switch when selecting a parameter set PowerShell/PowerShell#25027 seeks to address the outlined parameter set issue systematically.

@surfingoldelephant surfingoldelephant added issue-doc-bug Issue - error in documentation needs-triage Waiting - Needs triage labels Feb 14, 2025
@sdwheeler sdwheeler added area-sdk-docs Area - SDK docs area-about Area - About_ topics and removed needs-triage Waiting - Needs triage labels Feb 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-about Area - About_ topics area-sdk-docs Area - SDK docs issue-doc-bug Issue - error in documentation
Projects
None yet
Development

No branches or pull requests

2 participants