${...}
is a variable reference, and whatever ...
is is taken verbatim as a variable name.
- Enclosing a vairable name in
{...}
is typically not necessary, but is required in two cases: (a) if a variable name contains special characters and/or (b) in the context of an expandable string ("..."
), to disambiguate the variable name from subsequent characters - see this answer
In order to embed an expression or command as part of an argument, use $(...)
, the subexpression operator, and preferably enclose the entire argument in "..."
- that way, the entire argument is unambiguously passed as a single argument, whereas an unquoted token that starts with a $(...)
subexpression would be passed as (at least) two arguments (see this answer).
- If an expression or command by itself forms an argument,
(...)
, the grouping operator is sufficient and usually preferable - see this answer
Therefore:
[CmdletBinding()]
param(
[Parameter(Mandatory, HelpMessage="password?")]
[SecureString] $password
)
# Note the use of $(...) and the enclosure of the whole argument in "..."
do-something "password=$([Runtime.InteropServices.Marshal]::PtrToStringBSTR([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)))"
Also note:
On Windows it doesn't make a difference (and on Unix [securestring]
instances offer virtually no protection and should be avoided altogether), but it should be [Runtime.InteropServices.Marshal]::PtrToStringBSTR()
, not [Runtime.InteropServices.Marshal]::PtrToStringAuto()
As Santiago Squarzon points out, there is an easier way to convert a SecureString
instance to its plain-text equivalent (which should generally be avoided[1], however, and, more fundamentally, use of [securestring]
in new projects is discouraged[2]):
[pscredential]::new('unused', $password).GetNetworkCredential().Password
[1] A plain-text representation of a password stored in a .NET string lingers in memory for an unspecified time that you cannot control. More specifically, if it is part of a process command line, as in your case, it can be discovered that way. Of course, if the CLI you're targeting offers no way to authenticate other than with a plain-text password, you have no other choice.
[2] See this answer, which links to this .NET platform-compatibility recommendation.