PowerShell V2: ParameterSets

PowerShell V2: ParameterSets

  • Comments 6

One of the great benefits of PowerShell V2 Advanced Functions is the ease in which you can support parametersets.  ParameterSets are, well, different SETS of valid parameters.  For instance you can say:
Get-Process -id 0

Get-Process -Name *ss

Those are 2 different parametersets for the Get-Process cmdlet.  Here is an example of how you would code parametersets using advanced functions:

function test-param
{
param(
[Parameter(ParameterSetName="p1",Position=0)]
[DateTime]
$d,

[Parameter(ParameterSetName="p2", Position=0)]
[int]
$i
)
    switch ($PsCmdlet.ParameterSetName)
    {
    "p1"  { Write-Host $d; break}
    "p2"  { Write-Host $i; break}
    }
}

Now the question becomes - which Parameterset is used?  Let's experiment.  Clearly you can specify which parameter you want and the right thing will happen:

PS> test-param -d (get-Date)
12/23/2008 3:25:25 PM
PS> test-param -i 42
42

But what happens when it is ambiguous?  Where this is where the magic of PowerShell kicks in.  PowerShell uses the types of the input to determine which one you want.  If you specified a DateTime you probably want the p1 parameterset and if you specified a INT you probably want the p2 parameterset.

PS> test-param (get-Date)
12/23/2008 3:37:01 PM
PS> test-param 42
42

This almost always does exactly what you want but if it doesn't, you can always say what you want and you'll get it (it is just a mechanism to relieve you of work!).

PS> test-param -d 42
1/1/0001 12:00:00 AM

(That is the DATETIME corresponding to 42 TICKs of the clock!  Was that really what you wanted? :-) )

So now comes the interesting part.  What if the parametersets are ambiguous.  Let's redo the script and make both parameters be STRINGs and then convert to DATETIME and INT in the script and see what happens.

function test-param
{
param(
[Parameter(ParameterSetName="p1",Position=0)]
[String]
$d,

[Parameter(ParameterSetName="p2", Position=0)]
[String]
$i
)
    switch ($PsCmdlet.ParameterSetName)
    {
    "p1"  { Write-Host ([DateTime]$d); break}
    "p2"  { Write-Host ([INT]$i); break}
    }
}

PS> test-param -i "42"
42

PS> test-param "42"
test-param : Parameter set cannot be resolved using the specified named par
ameters.
At line:1 char:11
+ test-param <<<<  "42"
    + CategoryInfo          : InvalidArgument: (:) [test-param], Parameter
   BindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,test-param

If you don't specify which one you want, it is ambiguous.  But let's say that as the script author, you know that 9 out of 10 times people are going to want the p2 parameterset.  Do you really want to make people type in the parametername every time just to get around this ambiguity?  Wouldn't it be great if the PowerShell team thought about such a circumstance and give you a mechanism to specify which parameterset to pick if things were ambiguous?

OH WAIT - they did!

function test-param
{
[CmdletBinding(DefaultParametersetName="p2")]
param(
[Parameter(ParameterSetName="p1",Position=0)]
[String]
$d,

[Parameter(ParameterSetName="p2", Position=0)]
[String]$i
)
    switch ($PsCmdlet.ParameterSetName)
    {
    "p1"  { Write-Host ([DateTime]$d); break}
    "p2"  { Write-Host ([INT]$i); break}
    }
}

PS> test-param 42
42

Party on!

Jeffrey Snover [MSFT]
Windows Management Partner Architect
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Leave a Comment
  • Please add 8 and 4 and type the answer here:
  • Post
  • This is *very* cool.  I'll make heavy use of this feature.

  • Other languages use overloading for  this type of feature. What made you decide to "pack" all into one function? Will overloading be available as an alternative to keep code more readable?

  • @alexander

    I didn't follow that.  Can you post an example of what you would like to work?

    Jeffrey Snover [MSFT]

    Windows Management Partner Architect

    Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell

    Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

  • Sure!

    I'll email it to you, you can decide if you want to blog it.

    Alex

  • Please remember that each parameter set must have at least one parameter that is unique...it does not belong to any other parameter set. This unique parameter should be mandatory, unless you are writing an advanced function (or cmdlet) that can be called without specifying any parameters.

  • Great article.  In my blog post I describe another technique that can be used to avoid having "switch ($PsCmdlet.ParameterSetName)" all over in your code when you need to perform actions based on which parameters are provided: blog.danskingdom.com/always-explicitly-set-your-parameter-set-variables-for-powershell-v2-0-compatibility

    Also, @Alexander Riedel, I believe cmdlet names need to be unique, so overloading is not an option (Jeffery, please correct me if I'm wrong).

Page 1 of 1 (6 items)