Skip to content

Feature Request: Variable Parameter with switch-like capability #12104

Closed

Description

What I'm looking for is the ability to use a parameter to pass a variable, yet be able to act similar to a switch. Essentially...

No parameter:
PS>FunctionName

Or, parameter used like a switch where it will utilize a default value
PS>FunctionName -Parameter

Or, parameter used with a specified override to the default value
PS>FunctionName -Parameter 123

The idea is that I have a need for a function to accept multiple switch style inputs to say enable/disable, use/don't-use a particular feature. To that end a switch parameter works fine. However, many of the parameters are not only a true/false but also a variable, and I want to be able to provide the user a way to override the default value. A second parameter could be specified and required with dynamic parameters, to which the the input might look as follows...

PS>FunctionName -Parameter -ParameterOverride 123

But, this is clunky at best and considering the function I'm presently trying to work with has need for 8 parameters of this style it's down right ugly to use from the users perspective.

Activity

  1. vexx32 commented on Mar 11, 2020

    @vexx32
    Collaborator

    It's not exactly what you're after, but you could potentially utilise a [ValidateSet()] to make this easier to work with.

  2. chaydock commented on Mar 11, 2020

    @chaydock
    Author

    It's not exactly what you're after, but you could potentially utilise a [ValidateSet()] to make this easier to work with.

    How exactly would you employ a ValidateSet to solve this problem?

  3. vexx32 commented on Mar 11, 2020

    @vexx32
    Collaborator

    Hmm. Actually, that's only really a good solution if you have a specific set of acceptable values. If you have others... hmm. Yeah, okay, not sure. Depends on the exact requirements -- you can, for example, check $PSBoundParameters to verify if the value was actually passed deliberately or comes from some default parameter value you have set... and you can of course restrict input types.

    I was thinking something along these lines:

    [CmdletBinding()]
    param(
        # ...
    
        [Parameter()]
        [ValidateSet('Value1','Value2','Value3','Default')]
        $Parameter
        # ...
    )
    
    if ($Parameter -eq 'Default') { $Parameter -eq 'Value2' }
  4. chaydock commented on Mar 11, 2020

    @chaydock
    Author

    What I've tried so far with limited success was this...

    Function test {
    
    [CmdletBinding()]
        Param (
            [Parameter(Mandatory=$false)]
            [ValidateRange(1,25)]
            [Int]
            $OptionalNumber = 1
        )
    
        if($PSBoundParameters.keys -contains "OptionalNumber"){
            Write-Output "The optional number parameter is present"
            Write-Output "The Optional Number is: $OptionalNumber"
        }else{Write-Output "The optional number parameter was not specified"}
    }
    

    that works with running
    PS>test
    or running
    PS>test -OptionalNumber 4
    but fails when running
    PS>test -OptionalNumber
    I've tried (and failed) with all kinds of combinations of [ValidationScript()], [AllowNull()], [Nullable[int]] in an attempt to modify the parameter requirements, but every time it complains that there must be a value passed in when the "-OptionalNumber" parameter is present.

  5. vexx32 commented on Mar 11, 2020

    @vexx32
    Collaborator

    Yeah. The default value will be used whenever the parameter is not specified at all.

    Is there an important distinction here where you need the parameter to be specified for some reason, even though the default value will be used anyway?

  6. chaydock commented on Mar 11, 2020

    @chaydock
    Author

    for what it's worth, there was some discussion on this already on StackOverflow.com

    https://stackoverflow.com/questions/60459934/use-function-parameter-as-both-a-variable-and-switch

    https://stackoverflow.com/questions/58838941/powershell-special-switch-parameter

    Stack Overflow
    I have the powershell function below Function Test { Param ( [Parameter()] [string]$Text = "default text" )
    Write-Host "Text : $($Text)"
    

    }
    And I w...

    Stack Overflow
    I have the powershell function below Function Test { Param ( [Parameter()] [string]$Text = "default text" )
    Write-Host "Text : $($Text)"
    

    }
    And I w...

  7. chaydock commented on Mar 11, 2020

    @chaydock
    Author

    Yeah. The default value will be used whenever the parameter is not specified at all.

    Is there an important distinction here where you need the parameter to be specified for some reason, even though the default value will be used anyway?

    Basically, I want the presence (or lack thereof) of the parameter to be triggered like a switch parameter. If it's not there, just ignore the fact that it even has a default value set. However, if the parameter is present, then use whatever value the user specifies, and if no value is specified, use the default value.

    This isn't how I'm needing to use it (my case is a bit too much to explain easily), but imagine that you have a parameter that you call "$Log". You use that parameter to say that you want your function to enable a logging/transcript function. You have a default location already baked in... be it a specific or relative path.. but you want to give them the option to specify their own path.

    So this just runs the function without logging...
    PS>ExampleFunction
    This would run with logging to the default location...
    PS>ExampleFunction -Log
    And this would run with logging to a specific location...
    PS>ExampleFunction -Log C:\Temp\log.txt

    Again.. it is just an example of how it could be used. My use case is different but similar.

  8. mklement0 commented on Mar 11, 2020

    @mklement0
    Contributor

    Let me illustrate the proposal with a real-world example of such a parameter from the GNU sed Unix utility, whose -i option (for creating a backup of the input file) works as follows:

    • If -i isn't specified at all, no backup is created.

    • If only -i is specified, a backup file with default extension .bak is created.

    • If the user wishes to specify a different extension, they can pass an optional value to -i; e.g.,
      -i.org.

    For this to work syntactically in Powershell, the optional value, if specified, would have to be attached to the parameter name, with : as the separator (update: though there may be whitespace between the : and the argument):

    -MakeBackup:".org"

    This is how it already works for [switch] parameters, and this attachment is necessary to avoid ambiguity between optional parameter values and subsequent positional arguments.

  9. added
    WG-Enginecore PowerShell engine, interpreter, and runtime
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Mar 12, 2020
  10. bpayette commented on Mar 13, 2020

    @bpayette
    Contributor

    Actually there is no need for "attachment". This works fine:

    function foo { param( [switch] $zork) $zork}
    PS> foo
    
    IsPresent
    ---------
        False
    
    PS> foo -zork
    
    IsPresent
    ---------
         True
    
    PS> foo -zork:   $false
    
    IsPresent
    ---------
        False

    It's the ':' on the end of the switch that tells parser that the next argument binds to the switch parameter so syntactically the desired behavior could be implemented. However if this is generalized, how will the script distinguish between absent, present and present with a value? You'd have to encapsulate the value in a "magic" class containing the value along with the present flag. (This is more or less what which does.) This seems unnecessarily complicated.

  11. SeeminglyScience commented on Mar 13, 2020

    @SeeminglyScience
    Contributor

    Every time I've wished for this type of parameter, I realized I was trying to fit too much into a single command. The best way to handle this currently is one of these:

    1. Have a switch that just enables the behavior, this parameter would belong to AllParameterSets and also BehaviorNameSet. Have a separate optional parameter to specify the argument which only belongs to BehaviorNameSet

    2. Have a switch that enables the behavior, this parameter only belongs to BehaviorNameDefaultSet. Have a separate mandatory parameter to specify the argument which only belongs to BehaviorNameExplicitArgSet. Default parameter set would be AllParameterSets to make both optional

    Both of those solutions are heavy on parameter sets. If you find that you're running into trouble related to the number of sets you have, consider splitting the functionality into separate commands. While this would probably be a common request, I think that ultimately the lack of this syntax leads to better design (for a PowerShell command anyway, not disparaging monolith CLI executables).

    I also agree with Bruce Payette (@bpayette), usage of this type of parameter in a resilient way would be pretty verbose (if even possible).

  12. mklement0 commented on Mar 13, 2020

    @mklement0
    Contributor

    Good point about the whitespace, Bruce Payette (@bpayette): It's not the whitespace, it is the : that constitutes the attachment, and that : is all that's needed to unambiguously designate the argument as belonging to the parameter - as is already the case with and necessary for [switch] parameters, generalizing the logic of which is the gist of this proposal.

    However if this is generalized, how will the script distinguish between absent, present and present with a value?

    In order: -not $PSBoundParameters.ContainsKey('zork'), default value, bound value.

    No magic needed at all.

  13. mklement0 commented on Mar 13, 2020

    @mklement0
    Contributor

    Patrick Meinecke (@SeeminglyScience):

    Have a switch that just enables the behavior (...). Have a separate optional parameter

    Avoiding the ceremony and awkwardness of having to say -PleaseDo and
    -IfyouDoThenWith WithValue instead of just -PleaseDo:WithValue (with -PleaseDo with a default value typically being enough) is what this proposal is about.

    I get that this is amounts to a new concept (though not technically, given that [switch] already works this way), which is always challenging:

    • Users, if they're even aware of : as a parameter/argument separator at all, will have to understand that in the case of such optional-argument parameters they'll have to use it.

      • Then again, the relative obscurity of : may be a blessing in this case: start publicizing it in the context of this new feature, and recommend that it only be used for that.
    • We'll have to come up with a way of representing optional-argument parameters in the syntax diagrams (and, of course, implementation-wise in the parameter declaration, which could be as simple as [Parameter(ValueOptional)]).

    I personally think it's worth doing, but I get that it introduces additional complexity, and that it would require a focused effort to publicize and properly document the new feature.

  14. SeeminglyScience commented on Mar 16, 2020

    @SeeminglyScience
    Contributor

    Patrick Meinecke (@SeeminglyScience):

    Have a switch that just enables the behavior (...). Have a separate optional parameter

    Avoiding the ceremony and awkwardness of having to say -PleaseDo and
    -IfyouDoThenWith WithValue instead of just -PleaseDo:WithValue (with -PleaseDo with a default value typically being enough) is what this proposal is about.

    But how many scenarios are there where a better design wouldn't be Please-Do WithValue?

    Also personally I'd say -PleaseDo:WithValue is more awkward. I know that syntax already exists, but thankfully the use cases for it are pretty infrequent. Objectively less ceremony, but the awkwardness of either syntax is subjective.

  15. 3 remaining items

  16. mklement0 commented on Mar 16, 2020

    @mklement0
  17. SeeminglyScience commented on Mar 17, 2020

    @SeeminglyScience
  18. mklement0 commented on Mar 17, 2020

    @mklement0
  19. SeeminglyScience commented on Mar 17, 2020

    @SeeminglyScience
  20. mklement0 commented on Mar 17, 2020

    @mklement0
    Contributor

    Both excellent points, Patrick Meinecke (@SeeminglyScience).

    I'm increasingly making use of hiding outdated / resolved comments in order to keep threads short(er), and I often update the initial post with salient information discovered later and / or try to summarize a debate succinctly in a later comment.

    But the overall length is still a problem, and I wish there were some protocol for arriving at an agreed-upon final form of a proposal or concise summary of a debate- short of authoring an RFC, which often isn't appropriate (yet) and, it seems, is where ideas go to die - that doesn't require future readers to read the entire history.

    Having a shared, perhaps even documented understanding of how to use emoji would help too, though, at least based on the limited set of standard emoji offered by the site, I guess it's now down to the question whether to use 👎or 😕to signal one's final yay-or-nay stance (even though I bristled at it initially, I think the former is preferable).

  21. chaydock commented on Mar 22, 2020

    @chaydock
    Author
    function foo { param( [switch] $zork) $zork}

    I would love for this to work as you describe if only switch were to accept more than just $true/$false. If the switch parameter were to allow decoration as any variable type beyond Boolean, this would solve the problem I have at hand....

    PS > function foo { param( [switch] $zork) $zork}
    
    PS > foo
    
    IsPresent
    ---------
        False
    
    PS > foo -zork
    
    IsPresent
    ---------
         True
    
    PS > foo -zork: 4
    foo : Cannot process argument transformation on parameter 'zork'. Cannot convert the "4" value of type "System.Int32" to type "System.Management.Automation.SwitchParameter".
    At line:1 char:12
    + foo -zork: 4
    +            ~
        + CategoryInfo          : InvalidData: (:) [foo], ParameterBindingArgumentTransformationException
        + FullyQualifiedErrorId : ParameterArgumentTransformationError,foo
    

    The irony being that switch as an alternative to using endless if/else statements handles anything you can thing of to throw at it. But as a parameter can only handle $true/$false.

  22. mklement0 commented on Mar 22, 2020

    @mklement0
    Contributor

    Craig Haydock (@chaydock), note that the [switch] parameter type and the switch statement only happen to share the same name, but are otherwise unrelated.

    I think we've already established the desired behavior and hinted at possible implementations.

    Implementing this feature is definitely possible, but I don't think it's useful to further discuss implementation details until a decision is made on if this feature should be supported at all, which, of course, may be negative - or may never come.

  23. God-damnit-all commented on Dec 6, 2021

    @God-damnit-all
    Contributor

    I was disappointed to learn that this isn't currently possible, though I can understand why given PowerShell would have a hard time distinguishing between the argument of a positional parameter and an optional argument for a parameter like this one.

    However, there already is syntax for parameters like -Debug:$true, so I think the best solution would be to use this colon-based syntax for a new ternary-type parameter that can accept both booleans and another data type, so you could easily do something like -Foo:'bar' (with $true assumed if there's no argument).

  24. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  25. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  26. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  27. microsoft-github-policy-service commented on Nov 23, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

  28. RalfReddings commented on May 19, 2025

    @RalfReddings

    Please consider adressing this feature or issue. Its very much needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aResolution-No ActivityIssue has had no activity for 6 months or moreWG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions