binki
binki

Reputation: 8308

How do I pass a string as a non-string to a command in powershell?

I am attempting to conditionally add parameters to a command I am invoking in powershell. However, when I try, my parameter gets passed as a string. I can’t figure out how to pass it as an identifier instead.

This is my attempt so far:

$readParams = $(if ("2".Equals("2")) {"-AsSecureString"})
read-host 'Prompt' $readParams

The output I get is:

Prompt -AsSecureString:

I want to be able to set $readParams differently depending on conditions. If the condition is true get this behavior:

read-host 'Prompt' -AsSecureString

and if the condition is false get this behavior:

read-host 'Prompt'

I only want to write read-host once in my program.

How do I specify the argument dynamically without passing it as a string which causes it to become part of the prompt instead of passed as an identifier-style parameter?

Upvotes: 2

Views: 463

Answers (3)

mklement0
mklement0

Reputation: 437062

If you want to prepare multiple parameters in advance, use the splatting technique described in Mike Shepard's helpful answer, which uses a hashtable whose keys are named for the target cmdlet's parameters and also works with switch parameters (as an alternative to conditionally omitting an entry named for the switch parameter, include it unconditionally and assign $True to emulate passing the switch, and $False to emulate omitting it[1]).


To expand on Jacob Colvin's helpful answer:

For a switch parameter such as -AsSecureString (an optional flag-like parameter without argument), the challenge is that a switch's value is normally implied by its presence ($True) vs. its absence ($False)[2].

However, there is a syntax that allows passing the value explicitly, namely by appending :<expr> directly to the switch name, where <expr> is an expression whose value is converted to a Boolean; to illustrate with the automatic $True and $False variables:

  • -AsSecureString:$True ... same as just -AsSecureString
  • -AsSecureString:$False ... usually the same as not passing -AsSecureString[1]

Therefore, you can solve your problem as follows, using an expression (enclosed in (...)) directly, with no need for aux. variable $readParams:

 Read-Host 'Prompt' -AsSecureString:('2' -eq '2')

* Obviously, the expression value shouldn't be invariant in real-life use.

  • '2' -eq '2' is PowerShell's equivalent of "2".Equals("2"), though note that PowerShell's -eq is case-insensitive by default, so, strictly speaking, -ceq would be the closer analog.

[1] On occasion, -SomeSwitch:$False has different semantics from omitting the switch altogether, notably when overriding preference variables ad hoc. For instance, if $VerbosePreference = 'Continue' is in effect to make all cmdlets produce verbose output by default, you can use -Verbose:$False on individual commands to suppress it.

[2] Strictly speaking, a parameter variable inside a cmdlet/advanced function that represents a switch parameter is of type [switch](System.Management.Automation.SwitchParameter); however, instances of this type effectively behave like Booleans.
Somewhat confusingly, and against what the documentation says, the type's .IsPresent property reflects the effective Boolean value of the switch (on or off, loosely speaking), and not whether the switch was explicitly passed by the user.

Upvotes: 2

Mike Shepard
Mike Shepard

Reputation: 18146

The feature you're looking for is called splatting. It allows you to present a hashtable to a command and have it interpreted as parameters.

$readParams=@{}
if("2".Equals("2")) {
  $readParams["AsSecureString"]=$true
}
read-host 'Prompt' @readParams

Upvotes: 5

Jacob Colvin
Jacob Colvin

Reputation: 2835

You could set the switch to true or false depending on the condition:

$readParams = $(if ("2".Equals("2")) {$true} else {$false})
read-host 'Prompt' -AsSecureString:$readParams

Upvotes: 1

Related Questions