Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a switch parameter as a variable / via splatting in PowerShell?

If you have multiple parameters which require a value when calling a command or a script, I know you can pass it like this:

$parameters = @{
    name = "John"
    last_name = "Doe"
}

But if the command or script actually just expect -T to indicate something like a flag, but the parameter itself doesn't require a value. How can I set that in a variable?

$optionalT = ""
if ($itNeedsTheT) $optionalT = "-T"

command $optionalT

If I do it like that it complains with the following message:

Unknown argument 'T' on command line.
like image 805
Mason Avatar asked Oct 22 '19 15:10

Mason


People also ask

How do you use splatting in PowerShell?

Here is the basic syntax for using splatting. You use the regular PowerShell command ( <CommandName> ) followed by the variable name indicating the splatted values ( @<SplattedValues> ). Not all parameters need to be included in the splat. You can pass other parameters ( <parameters> ) before or after the splat.

How do you pass parameters to a function in PowerShell?

Passing arguments in PowerShell is the same as in any other shell: you just type the command name, and then each argument, separated by spaces. If you need to specify the parameter name, you prefix it with a dash like -Name and then after a space (or a colon), the value.

How do I create a switch parameter in PowerShell?

To create a switch parameter in a function, specify the switch type in the parameter definition. Switch parameters are easy to use and are preferred over Boolean parameters, which have a less natural syntax for PowerShell. For example, to use a switch parameter, the user types the parameter in the command.


2 Answers

When splatting, create the hashtable with non-conditional parameters (the values can be variable), but add the optional parameters after the hashtable is created:

$parameters = @{
  Name = "John"
  LastName = "Doe"
  Age = $age
  Enabled = $true
}

if( $favoriteThing ){
  $parameters.FavoriteThing = $favoriteThing
}

command @parameters

If dealing with a switch in splatting, you can treat it as a boolean parameter like shown above, just give it a value of $true or $false depending on whether you want the switch to be enabled on the command or not. You can see a non-splat example of this to set a -Confirm flag to $false:

Install-Package some_package -Confirm:$false
like image 23
Bender the Greatest Avatar answered Sep 19 '22 19:09

Bender the Greatest


tl;dr

# Pass the $itNeedsT Boolean - which indicates whether the -T switch should
# be passed - as the switch's *value*.
command -T:$itNeedsTheT  

If $itNeedsTheT is $false, the above is the same as omitting -T - usually (read on for details).

Note the need to use : to separate the switch name from the value.


As boxdog points out in a comment, in a hashtable used with splatting (@parameters), you use a Boolean value to represent a switch parameter (a flag-like parameter of type [switch]) .

# Dynamically determine if -Recurse should be turned on.
$recurseIfTrue = $true

# Define the hashtable for splatting...
$parameters = @{
  Path = '.'
  Recurse = $recurseIfTrue  # turn the -Recurse switch on or off
}

# ... and pass it to the target command.
# *Loosely speaking*, the following command is the same as either:
#   Get-ChildItem -Path '.' -Recurse  # if $recuseIfTrue was $true
# or:
#   Get-ChildItem -Path '.'           # if $recuseIfTrue was $false
Get-ChildItem @parameters

That is, loosely speaking:

  • use $true to pass the switch
  • use $false to not pass the switch.

This allows you to keep a single hashtable definition that unconditionally includes the switch parameter, but whose value can determine programmaticaly.

Caveat:

Strictly speaking, hashtable entry Recurse = $true translates to parameter -Recurse:$true and Recurse = $false doesn't translate into omitting the parameter, it translates to passing -Recurse:$false.

In most cases, omitting a switch -Foo and passing it with value $false - i.e. -Foo:$false - are equivalent.

However, commands can detect the difference and sometimes act differently:

A notable example is the -Confirm common (switch) parameter: omitting -Confirm means that the $ConfirmPreference preference variable is respected, whereas -Confirm:$false means that the preference variable should be overridden (and confirmation should not be requested).

If you want to make this distinction yourself in a PowerShell script or function, you can call $PSBoundParameters.ContainsKey('Foo') in addition to checking the $Foo (-Foo) switch parameter variable's value.

If you're dealing with such a command and you want to programmatically enforce omission of a switch parameter, you'll have no choice but to conditionally add an entry for this switch, in a separate step:

# Dynamically determine if -Recurse should be turned on.
$recurseIfTrue = $true

# A 'Recurse' key now can NOT be included unconditionally,
# if you want to *omit* -Recurse in case $recurseIfTrue is $false
$parameters = @{
  Path = '.'
}

# Add a 'Recurse' entry only if the switch should be passed.
if ($recurseIfTrue) {
  $parameters.Recurse = $true
}

Get-ChildItem @parameters

Finally, note that as an alternative to specifying a switch value programmatically via splatting, you can pass a dynamic value to a switch directly:

# Dynamically determine if -Recurse should be turned on.
$recurseIfTrue = $true

Get-ChildItem -Path . -Recurse:$recurseIfTrue

Note the need to use : to separate the switch name from its value.

This is necessary, because using the customary whitespace to separate the parameter name from its value would cause PowerShell to interpret the Boolean as the next argument, given that switch parameters normally do not take values.

Although rarely used, this :-based syntax works with all parameter types.

like image 159
mklement0 Avatar answered Sep 19 '22 19:09

mklement0