Chase Florell
Chase Florell

Reputation: 47437

powershell single switch parameter only

Providing I have a three switch parameters

param(
    [parameter(Mandatory=$false] [switch] $i,
    [parameter(Mandatory=$false] [switch] $ir,
    [parameter(Mandatory=$false] [switch] $iur
)

and only ONE of them is allowed, what is the best way to do this? If I use what's above, all three switches can be added as a parameter on a single call (undesirable).

> invoke-aspnetregiis -i -ir -iur # bad

I originally used a ValidateSet on a [string]

[parameter(Mandatory=$false, ValidateSet('-i', '-ir', '-iur'))] [string] $arg

but then the call looks funny

invoke-aspnetregiis '-i' # notice the single quotes.

I prefer it too read

invoke-aspnetregiis -i # to mimic the native call

The best I've come up with so far is to use ParameterSetNames

[parameter(Mandatory=$false, ParameterSetName='i')] [switch] $i,
[parameter(Mandatory=$false, ParameterSetName='ir')] [switch] $ir,
[parameter(Mandatory=$false, ParameterSetName='iur')] [switch] $iur,

switch($PsCmdlet.ParameterSetName){
    'i'   {$argument = '-i'}
    'ir'  {$argument = '-ir'}
    'iur' {$argument = '-iur'}
    default {$argument = '-i'}
}

essentially making the actual switch irrelevant.

Is there a better way to accomplish this in Powershell?

Upvotes: 0

Views: 4821

Answers (3)

Fede Marko
Fede Marko

Reputation: 11

the best can be use the validate scrip

[Parameter(Mandatory=$false)][ValidateScript({-not ($descendente -or $aleatorio )})][Switch]$ascendente, 
[Parameter(Mandatory=$false)][ValidateScript({-not ($ascendente -or $aleatorio  )})][Switch]$descendente, 
[Parameter(Mandatory=$false)][ValidateScript({-not ($ascendente -or $descendente)})][Switch]$aleatorio

so powershell will throw the error

Upvotes: 1

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200523

Parameter sets is what you'd normally use for something like this. If you name the parameter sets after the parameters you can even simplify passing the parameter to the actual command you're calling:

[CmdletBinding(DefaultParameterSetName='-i')]
Param(
  [Parameter(ParameterSetName='-i',Mandatory=$false)][Switch]$i,
  [Parameter(ParameterSetName='-ir',Mandatory=$false)][Switch]$ir,
  [Parameter(ParameterSetName='-iur',Mandatory=$false)][Switch]$iur
)

& yourcommand $PSCmdlet.ParameterSetName

There are, of course, other options as well, like building your own logic for ensuring that just one out of the three parameters is provided:

Param(
  [Parameter(Mandatory=$false)][Switch]$i,
  [Parameter(Mandatory=$false)][Switch]$ir,
  [Parameter(Mandatory=$false)][Switch]$iur
)

if (1 -ne $i.IsPresent + $ir.IsPresent + $iur.IsPresent) {
  'Usage: script.ps1 {-i|-ir|iur}'
  exit 1
}

However, as @mikez pointed out in the comments, the command/script help will not automatically show that the parameters cannot be used in conjunction with each other:

PS C:\> .\test_paramset.ps1 -?
test_paramset.ps1 [-a] [<CommonParameters>]
test_paramset.ps1 [-b] [<CommonParameters>]
test_paramset.ps1 [-c] [<CommonParameters>]

PS C:\> .\test_no_paramset.ps1 -?
test_no_paramset.ps1 [-a] [-b] [-c] [<CommonParameters>]

thus making the alternative approach a little less user-friendly.

Upvotes: 2

Etan Reisner
Etan Reisner

Reputation: 81052

Nothing about the ParameterSetName usage makes the switches irrelevant. They are how the user picked the mode in the first place.

You don't have to use the same name for the ParameterSetName as the switch name.

You don't have to use $argument and can just use the switch name if you cant.

You can just use the switch name and ignore ParameterSetName (since powershell has ensured you only get one switch among the sets already).

You could also manually validate the arguments given if you wanted to.

I don't know of any other way (but I'm not a powershell expert either).

Upvotes: 0

Related Questions