Search code examples
powershellparameterspowershell-5.0powershell-cmdlet

Param in CmdletBinding not mandatory and error/misspelled checking


Hey all I have a powershell script that I need to send some parameters to. However, sometimes I do not need to send any or maybe one out of the two.

[CmdletBinding()]
param (
    [Parameter(ParameterSetName='SkipAutoLoader')][switch]$SkipAutoLoader,
    [Parameter(ParameterSetName='AppPool')][switch]$AppPool
)

[more code here....]

if (-not $SkipAutoLoader) {
    $services += "Auto Loader Service"
}

[more code here....]

The above works just fine as long as I have either:

.\Start-AkkServides.ps1 -SkipAutoLoader

or

.\Start-AllServices -AppPool

If I have both together:

.\Start-AllServices -SkipAutoLoader -AppPool

It errors out.

C:\src\Start-AllServices.ps1 : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ .\Start-AllServices.ps1 -SkipAutoLoader -AppPool
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-AllServices.ps1], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Start-AllServices.ps1

I also want to be able to determine if the param has the valid -SkipAutoLoader and/or -AppPool but with something else tagged like -SkipAutoLoader43

I would like to say that -SkipAutoLoaderbob is an invalid param. But do not show an error if either param is not present.

Loads Fine: .\Start-AllServides.ps1 -SkipAutoLoader

Loads Fine: .\Start-AllServides.ps1 -AppPool

Does Not Load Fine/causes error: .\Start-AllServides.ps1 -SkipAutoLoader -AppPool

Does Not Load Fine/casues error: .\Start-AllServides.ps1

Does not say param is not valid: .\Start-AllServides.ps1 -SkipAutoLoaderbob

Does not say param is not valid: .\Start-AllServides.ps1 -AppPool7

Possible to do with powershell?


Solution

    • Your parameters are in separate parameter sets (only[1]), so by design they cannot be used together.

      • If your parameters can be freely combined, you don't need to define parameter sets at all.
    • Since your script is an advanced one, thanks to [CmdletBinding()] and/or [Parameter()] attributes, calling with non-declared parameter names is automatically prevented.

      • However, the lack of a default parameter-set designation in the [CmdletBinding()] attribute causes a more fundamental error if you only specify an unsupported parameter name (such as -SkipAutoLoaderbob): PowerShell then doesn't know which of the two defined parameter sets to select, because no declared parameter can be bound (before even considering whether the parameter name given is valid, perhaps surprisingly)

      • Use [CmdletBinding(DefaultParameterSetName='AppPool')], for instance, to designate the default parameter set.

    Assuming that your two parameters can be freely combined and neither is mandatory (which [switch] parameters shouldn't be anyway), your code can be simplified to:

    [CmdletBinding()]
    param (
      [switch] $SkipAutoLoader,
      [switch] $AppPool
    )
    
    # Output the name of the active parameter set.
    $PSCmdlet.ParameterSetName
    

    Note that non-mandatory parameters without explicit parameter-set membership (and other non-default parameter properties) do not require [Parameter()] attributes.

    When you invoke the script, you'll see that PowerShell implicitly defines a parameter set in the absence of explicitly declared ones, named __AllParameterSets.


    [1] Note that a parameter can belong to multiple explicitly specified parameter sets, via multiple [Parameter(ParameterSetName= '...')] attributes. Any parameter without an explicit parameter-set membership is implicitly part of all parameter sets.