Author Posts

September 8, 2018 at 11:47 am

Hi,

I'm making a function and I'm having trouble with some parametersets..

This is my function.


function Test-ParameterSet

{

[CmdletBinding(

DefaultParameterSetName = "all"

)]

Param

(

[Parameter(Mandatory = $false,

Position = 0)]

[ValidateNotNullorEmpty()]

[String]$apiKey,

[ValidateSet("Prod", "Dev")]

[Parameter(Mandatory = $false)]

$environment = "Dev",

[Parameter(Mandatory = $false)]

[int]$maxItems,

[Parameter(Mandatory = $false,

ParameterSetName = "all")]

[switch]$all,

[Parameter(Mandatory = $false,

ParameterSetName = "byCustomerId")]

[Parameter(ParameterSetName = "byId")]

[Parameter(ParameterSetName = "byName")]

[string]$customerId,

[Parameter(Mandatory = $false,

ParameterSetName = "byId")]

[Parameter(ParameterSetName = "byCustomerId")]

[string]$id,

[Parameter(Mandatory = $false,

ParameterSetName = "byName")]

[Parameter(ParameterSetName = "byCustomerId")]

[string]$name

)

 

 

Write-Output $PSCmdlet.ParameterSetName

 

}

Basically how I want it to work is;

Test-ParameterSet -All (Gets everything, CustomerId, Name and Id is not available)

Test-ParameterSet -Customerid XXX (Gets everything by this particular customer, customerId and Name is available but not mandatory)

Test-ParameterSet -CustomerId XXX -id XXX (Gets object from this particular customer with id specified. Name is not available)

Test-ParameterSet -CustomerId XXX -name XXX (Gets object from this particular customer with name specified. id is not available)

According to Get-Help this is how it looks


NAME

Test-ParameterSet

 

SYNTAX

Test-ParameterSet [[-apiKey] ] [-environment {Prod | Dev}] [-maxItems ] [-all]  []

 

Test-ParameterSet [[-apiKey] ] [-environment {Prod | Dev}] [-maxItems ] [-customerId ] [-entityName

]  []

 

Test-ParameterSet [[-apiKey] ] [-environment {Prod | Dev}] [-maxItems ] [-customerId ] [-entityId

]  []

 

Test-ParameterSet [[-apiKey] ] [-environment {Prod | Dev}] [-maxItems ] [-customerId ] [-entityId

] [-entityName ]  []

 

 

ALIASES

None

 

 

REMARKS

None

I am unable to find a way to exclude id if name is used and exclude name if id is used. According to help I should be able to use :

PS C:\Windows\system32> Test-ParameterSet -customerId 1212

But I am recieving an error:

Test-ParameterSet : Parameter set cannot be resolved using the specified named parameters.

At line:1 char:1

+ Test-ParameterSet -customerId 1212

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo          : InvalidArgument: (:) [Test-ParameterSet], ParameterBindingException

+ FullyQualifiedErrorId : AmbiguousParameterSet,Test-ParameterSet

 

What am I doing wrong?

September 8, 2018 at 12:32 pm

If not properly used, Parameter sets will give a lot of trouble. Its a kind of(not exactly) overloading.

From what I understood ,

function Test-ParameterSet
{
    [CmdletBinding(DefaultParameterSetName = "all")]
    Param(

        [Parameter(Mandatory = $false,Position = 0)]
        [ValidateNotNullorEmpty()]
        [String]$apiKey,

        [ValidateSet("Prod", "Dev")]
        [Parameter(Mandatory = $false)]
        $environment = "Dev",

        [Parameter(Mandatory = $false)]
        [int]$maxItems,


        [switch]$all,


        [string]$customerId,

        [Parameter(Mandatory = $True,ParameterSetName = "byId")]        
        [string]$id,

        [Parameter(Mandatory = $True,ParameterSetName = "byName")]
        [string]$name

    )

    Write-Output $PSCmdlet.ParameterSetName
}


PS C:\Windows\Temp> Test-ParameterSet -customerId s
all

PS C:\Windows\Temp> Test-ParameterSet -name d
byName

PS C:\Windows\Temp> Test-ParameterSet -id 2
byId

PS C:\Windows\Temp> Get-Help Test-ParameterSet

NAME
    Test-ParameterSet
    
SYNTAX
    Test-ParameterSet [[-apiKey] ] [-environment {Prod | Dev}] [-maxItems ] [-all] [-customerId ]  []
    
    Test-ParameterSet [[-apiKey] ] -id  [-environment {Prod | Dev}] [-maxItems ] [-all] [-customerId ]  []
    
    Test-ParameterSet [[-apiKey] ] -name  [-environment {Prod | Dev}] [-maxItems ] [-all] [-customerId ]  []
    

ALIASES
    None
    

REMARKS
    None

September 8, 2018 at 12:45 pm

Hi,

Thanks for you reply.

Yes, it's almost correct and i've also gotten that far before, however I don't want customerid to be available when the switch "all" is used, which it is now in your example.

Best regards

September 8, 2018 at 12:57 pm

Add byCustomerID to $CustomerID,$Id and $Name.

        [Parameter(Mandatory = $true,ParameterSetName = "bycustomerId")]
        [string]$customerId,

        [Parameter(Mandatory = $false,ParameterSetName = "bycustomerId")]
        [Parameter(Mandatory = $True,ParameterSetName = "byId")]        
        [string]$id,

        [Parameter(Mandatory = $false,ParameterSetName = "bycustomerId")]
        [Parameter(Mandatory = $True,ParameterSetName = "byName")]
        [string]$name

September 8, 2018 at 1:02 pm

OK, so parameter sets can be confusing. I've found the most effective way is to lay out exactly which sets of parameters can be used together and go from there. You're halfway there already:

Test-ParameterSet -All (Gets everything, CustomerId, Name and Id is not available)

Test-ParameterSet -Customerid XXX (Gets everything by this particular customer, customerId and Name is available but not mandatory)

Test-ParameterSet -CustomerId XXX -id XXX (Gets object from this particular customer with id specified. Name is not available)

Test-ParameterSet -CustomerId XXX -name XXX (Gets object from this particular customer with name specified. id is not available)

So, you want the following parameters to be able to be used together, if I understand correctly:

  1. -All (Set 1)
  2. -CustomerID (Set 2)
  3. -CustomerID, -ID (Set 3)
  4. -CustomerID, -Name (Set 4)

Your definition for set 2 is going to conflict with 3 and 4. Essentially, once you specify one of the others, you're in a separate parameter set entirely. They shouldn't be available in Set 2; if they are, you'll have duplicate parameter sets.

In each parameter set, it looks like all of the above need to be Mandatory, in order for PS to determine which set needs to be used. Too many optional parameters means the set to use is very unclear.

I'd name each parameter set according to their function, or their defining parameters.

  1. Set 1 -> "All"
  2. Set 2 -> "ByCustomerID"
  3. Set 3 -> "ByID"
  4. Set 4 -> "ByName"

Any additional parameters that can be used regardless of the set should not declare a parameter set. If you have optional parameters that can also be used to supplement a specific set, make sure they're in the set but not Mandatory. Here's a stripped-down idea of how I'd structure these parameter sets in terms of parameter attributes:

[Parameter(Mandatory, ParameterSetName = "All")]
[switch]
$All,

[Parameter(Mandatory, ParameterSetName = "ByCustomerID")]
[Parameter(Mandatory, ParameterSetName = "ByID")]
[Parameter(Mandatory, ParameterSetName = "ByName")]
[string]
$CustomerID,

[Parameter(Mandatory, ParameterSetName = "ByID")]
[string]
$ID,

[Parameter(Mandatory, ParameterSetName = "ByName")]
[string]
$Name

Note that any parameters which are valid in more than one set need the multiple attributes, and although that looks like a lot of mandatory params, "mandatory" becomes less strict when parameter sets are in play. That's because although they're all mandatory, only specific ones can be used at the same time.

Also worth noting is that it's not possible for all three (CustomerID, ID, Name) params to be used at once. If you wanted that, you'd need to add a 5th parameter set encompassing them all, again with them all as mandatory.

Essentially, each parameter set must have a unique set of parameters, and enough mandatory parameters that the distinction between the sets is very clear.

September 8, 2018 at 1:30 pm

Joel! You are a genius. It worked just like I wanted it to work.

You know, I think I got stuck on the idea where I thought the parameters Name and Id had to be part of the same parameterset once the customerId  got used (As non-mandatory parameters). In reality it just had to be in different parametersets.

Big thanks to kvprasoon as well!