Conditional PowerShell parameters

16,747

Solution 1

As Christian indicated, this can be accomplished via ParameterSetNames. Take a look at this example:

function Get-MySPWeb {
    [CmdletBinding(DefaultParameterSetName="set1")]
    param (
        [parameter(ParameterSetName="set1")] $RelativeUrl,
        [parameter(ParameterSetName="set2")] $WebUrl,
        [parameter(ParameterSetName="set2", Mandatory=$true)] $DisplayName
    )
    Write-Host ("Parameter set in action: " + $PSCmdlet.ParameterSetName)
    Write-Host ("RelativeUrl: " + $RelativeUrl)
    Write-Host ("WebUrl: " + $WebUrl)
    Write-Host ("DisplayName: " + $DisplayName)
}

If you run it with -RelativeUrl Foo it will bind to "set1". If you call this function without any parameters it will also bind to "set1".

(Note - when no parameters are provided in PowerShell v3 (with Windows 8 consumer preview) it will bind to "set1", however it will error binding in PowerShell v2 unless you add [CmdletBinding(DefaultParameterSetName="set1")] to the parameter block. Thanks @x0n for the DefaultParameterSetName tip!)

If you try to run it with a parameter value from both sets you will get an error.

If you run it with -WebUrl Bar it will prompt you for a parameter value for DisplayName, because it's a mandatory parameter.

Solution 2

There is a much more powerful option, called dynamic parameters, which allows to dynamically add parameters depending on the value of other parameters or any other condition.

You must structure your script in a different way, declaring the regular parameters as usual, and including a DynamicParam block to create dynamic parameters, a Begin block to initialize variables using the dynamic parameters , and a Process block with the code run by the script, which can use regular parameters, and variables initialized in Begin. It looks like this:

param( 
  # Regular parameters here
)

DynamicParam {
  # Create a parameter dictionary
  $runtimeParams = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

  # Populate it with parameters, with optional attributes
  # For example a parameter with mandatory and pattern validation
  $attribs = New-Object  System.Collections.ObjectModel.Collection[System.Attribute]

  $mandatoryAttrib = New-Object System.Management.Automation.ParameterAttribute
  $mandatoryAttrib.Mandatory = $true
  $attribs.Add($mandatory)

  $patternAttrib = New-Object System.Management.Automation.ValidatePatternAttribute('your pattern here')
  $attribs.Add($patternAttrib)

  # Create the parameter itself with desired name and type and attribs
  $param = New-Object System.Management.Automation.RuntimeDefinedParameter('ParameterName', String, $attribs)

  # Add it to the dictionary
  $runtimeParams.Add('ParameterName', $param)

  # Return the dictionary
  $ruintimeParams
}

Begin {
  # If desired, move dynamic parameter values to variables
  $ParameterName = $PSBoundParameters['ParameterName']
}

Process {
  # Implement the script itself, which can use both regular an dynamic parameters
}

Of course, the interesting part is that you can add conditions on the DynamicParam section and the Begin section to create different parameters depending on anything, for example other parameter values. The dynamic parameters can have any name, type (string, int, bool, object...) an attributes (mandatory, position, validate set...), and they are created before the execution of the script so that you get parameter tab completion (IntelliSense) in any environment which supports it, like the PowerShell console, the PowerShell ISE or the Visual Studio Code editor.

A typical example would be to create a different set of dynamic parameters depending on the value of a regular parameter, by using a simple if in the DynamicParam section.

Google "PowerShell dynamic parameters" for extra information, like showing help for dynamic parameters. For example:

Solution 3

You need to use parameters set naming.

You can assign an exclusive parameter to a different parameter set name.

Share:
16,747

Related videos on Youtube

jumbo
Author by

jumbo

Developing C# solutions. Playing with Powershell all the time. Former Sharepoint 2010 developer. Because of Sharepoint administration tasks I became a Powershell programmer and lover. Also written lot of Silverlight code for browsers and for Windows Phone 7/8. I was big Windows Phone 7/8/10 enthusiast. RIP Currently focused on .NET and C# backend solutions.

Updated on September 14, 2022

Comments

  • jumbo
    jumbo over 1 year

    Is there a way to have some of the parameters mandatory based on some condition (for example, if one of the parameters is absent or false) in a PowerShell function?

    My idea is to be able to call a function in two ways. A concrete example is a function that gets a list from SharePoint - I should be able to call it with relative URL of the list (one and only parameter) OR with a web URL and a list display name (two parameters, both mandatory, but only if list relative URL is not used).

  • jumbo
    jumbo almost 12 years
    Can you give me a little example how can I accomplish what I wrote?
  • CB.
    CB. almost 12 years
    Read here blogs.technet.com/b/heyscriptingguy/archive/2011/06/30/… I'm too busy now to write an example but link give a really good explanation.
  • BartekB
    BartekB almost 12 years
    Code in comments looks bad... but: param ( [Parameter(ParameterSetName = 'rel', Mandatory = $true)][string]$RelativeUrl, [Parameter(ParameterSetName = 'web', Mandatory = $true)][string]$WebUrl, [Parameter(ParameterSetName = 'web', Mandatory = $true)][string]$DisplayName ) Now you have to parameter sets, one for each scenario. Parameter can go to multiple sets or all sets (if no parameterSetName is specified). More in help about_Functions_Advanced_Parameters
  • jumbo
    jumbo almost 12 years
    This is exactly I needed! Thank you! Only one thing: when I run this with no params, I get an error (but I wanted it this way). One follow-up question: when using parametersets it is intended to use switch with the $PSCmdlet.ParameterSetName variable, right?
  • Andy Arismendi
    Andy Arismendi almost 12 years
    Right, $PSCmdlet.ParameterSetName is there so you can take the appropriate action based on the parameter set evaluated by the parameter binding process. BTW it's interesting you got an error, it seems this is a difference in behavior between PSv2 and PSv3.
  • x0n
    x0n almost 12 years
    The trick to making it work like v3 is to use a default parameter set directive. I've edited your answer to show this.
  • Gareth Oakley
    Gareth Oakley over 11 years
    If you're building your Cmdlet as a .NET assembly then DefaultParameterSetName must go in the [Cmdlet()] attribute - it won't work if you add a seperate [CmdletBinding()] attribute
  • jumbo
    jumbo almost 6 years
    Thanks for this answer. Even though the original answer was really what I needed, this is definitely very interesting way of solving the problem and I can see its power in some complicated cases. Also, I would say this option is much neglected and therefore not very well known. Thanks again for sharing.
  • Peter Mortensen
    Peter Mortensen almost 5 years
    The link is (effectively) broken. It redirects to a non-specific page, https://docs.microsoft.com/en-us/powershell/developer/window‌​s-powershell.