Help with ParameterSets

Welcome Forums General PowerShell Q&A Help with ParameterSets

This topic contains 5 replies, has 3 voices, and was last updated by

 
Participant
3 months, 1 week ago.

  • Author
    Posts
  • #111257

    Participant
    Points: 54
    Rank: Member

    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?

  • #111260

    Participant
    Points: 878
    Helping Hand
    Rank: Major Contributor

    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
    
    
    • #111262

      Participant
      Points: 54
      Rank: Member

      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

  • #111266

    Participant
    Points: 878
    Helping Hand
    Rank: Major Contributor

    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
    
  • #111269

    Participant
    Points: 290
    Helping Hand
    Rank: Contributor

    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.

    • #111272

      Participant
      Points: 54
      Rank: Member

      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!

       

The topic ‘Help with ParameterSets’ is closed to new replies.