Chris Magnuson
Chris Magnuson

Reputation: 5949

Can I specify conditional default values for a parameter in PowerShell?

I thought if this was possible it might work using parameter sets so I tried the following:

Function New-TestMultipleDefaultValues {
    [CmdletBinding(DefaultParameterSetName="Default1")]
    param (
        [Parameter(Mandatory,ParameterSetName="Default1")]$SomeOtherThingThatIfSpecifiedShouldResultInTest1HavingValue1,
        [Parameter(ParameterSetName="Default1")]$Test1 = "Value1",
        [Parameter(ParameterSetName="Default2")]$Test1 = "Value2"
    )
    $PSBoundParameters
}

Executing this to create the function results in the error Duplicate parameter $test1 in parameter list. so it doesn't look like this way is an option.

The only thing I can think of at this point is to do something like this:

Function New-TestMultipleDefaultValues {
    param (
        $SomeOtherThingThatIfSpecifiedShouldResultInTest1HavingValue1,
        $Test1
    )
    if (-not $Test1 -and $SomeOtherThingThatIfSpecifiedShouldResultInTest1HavingValue1) {
        $Test1 = "Value1"
    } elseif (-not $Test1 -and -not $SomeOtherThingThatIfSpecifiedShouldResultInTest1HavingValue1) {
        $Test1 = "Value2"
    }

    $Test1
}

Which works but seems ugly:

PS C:\Users\user> New-TestMultipleDefaultValues -SomeOtherThingThatIfSpecifiedShouldResultInTest1HavingValue1 "thing"
Value1
PS C:\Users\user> New-TestMultipleDefaultValues
Value2
PS C:\Users\user> New-TestMultipleDefaultValues -Test1 "test"
test

Any better way to accomplish this?

Upvotes: 4

Views: 2392

Answers (2)

mklement0
mklement0

Reputation: 437100

The following should work:

Since there is then no longer a need for explicit parameter sets, I've omitted them; without specific properties, the [Parameter()] attributes aren't strictly needed anymore either.

Function New-TestMultipleDefaultValues {

  [CmdletBinding()]
  param (
    [Parameter()] $SomeOtherThing,
    [Parameter()] $Test1 = 
      ('Value2', 'Value1')[$PSBoundParameters.ContainsKey('SomeOtherThing')]
  )
    
  # * As expected, if -Test1 <value> is explicitly specified, 
  #   parameter variable $Test1 receives that value.
  # * If -Test1 is omitted, the expression assigns 'Value1` to $Test1
  #   if -SomeOtherThing was specified, and 'Value2' otherwise.
  $Test1 # Output the effective value of $Test1

}
  • It is possible to use expressions as parameter default values.

    • The above code is an expression and therefore can be used as-is.
    • To use a single command (a call to a PowerShell cmdlet, function, script or to an external program) as an expression, enclose it in (...), the grouping operator.
    • In all other cases you need $(...), the subexpression operator (or @(...), the array-subexpression operator) to convert the code to an expression; these cases are:
      • A Throw statement (and, hypothetically, exit and return statements, but you wouldn't use them in this context)
      • A compound construct such as foreach, while, ...
      • Multiple commands, expressions, or compound constructs, separated with ;
  • However, it is safe to always use $(...) (or @(...)) to enclose the code that calculates the default value, which you may opt to do for simplicity.

  • These expressions are evaluated after the explicitly specified parameters have been bound, which allows an expression to examine what parameters have been bound, via the automatic $PSBoundParameters variable:

    • ('Value2', 'Value1')[$PSBoundParameters.ContainsKey('SomeOtherThing')] is simply a more concise reformulation of
      if ($PSBoundParameters.ContainsKey('SomeOtherThing')) { 'Value1' } else { 'Value2' }
      that takes advantage of [bool] values mapping onto 0 ($false) and 1 ($true) when used as an array index (integer).

    • In PowerShell v7+ you could use a ternary conditional instead, which has the added advantage of short-circuiting the evaluation: $PSBoundParameters.ContainsKey('SomeOtherThing') ? 'Value1' : 'Value2'

Upvotes: 8

Max
Max

Reputation: 77

You may want to look at dynamic parameters. You declare a section called dynamicparams {} and inside you can create parameters on the fly.

Upvotes: 0

Related Questions