tl;dr
Your command should work - except if $password
contains "
chars.
- Embedded
$
chars., by contrast, should not be a problem.
Your /pass:"`"$password`""
technique - i.e., explicit, embedded double-quoting - also handles values with embedded spaces correctly, unlike the /pass:$password
technique (also) suggested in Bill Stewart's helpful answer.
- You can simplify the command by omitting the outer
"..."
quoting, as also suggested in Bill's answer:
/pass:`"$password`"
- Caveat: If PowerShell's argument-passing worked correctly, these techniques shouldn't work and if it ever gets fixed, such techniques will stop working - see this answer for background.
As for supporting "
chars. in values: even \
-escaping them doesn't always work, namely when spaces are also involved - see details below.
The issue is that it breaks when the password includes a $ character.
Your command passes any $
characters embedded in the value of $password
through to the target program as-is.
Therefore, if there is a problem, the implication is that your target program - cmdkey.exe
- interprets $
characters, but note that the docs make no mention of that.
If it indeed does, however, you would have to escape $
characters as required by the target program in order to pass them literally.
Caveat: There is a fundamental limitation, however:
Commands typically break if the argument value contains spaces AND embedded "
chars, whether the latter are properly escaped for the target program or not.
Normally, you'd escape value-internal "
as \"
so as not to break the enclosing double-quoting of the value:
# !! Only works if:
# !! * $password contains NO "
# !! * $password contains " but NOT ALSO SPACES
# !! * $password contains PAIRS of " and what is between each
# !! pair does not contain spaces
cmdkey.exe /add:$hostname /user:"$user" /pass:`"$($password -replace '"', '\"')`"
Note:
- Escaping embedded
"
as \"
is a not a standard per se, but it is recognized by most external programs; the only notable exceptions are batch files - see this answer for details.
- Arguably, PowerShell should handle this escaping automatically - see this GitHub issue for details.
If Windows PowerShell thinks it cannot pass the resulting token as-is as a single argument to the target program, it blindly applies double-quoting around the entire token[1], which, in combination with the escaped "
, can result in invalid syntax:
E.g., if $password
literally contains a " b
and is manually escaped as a \" b
by the command above, PowerShell ends up passing the following behind the scenes:
... "/pass:"a \" b""
That is, the resulting literal token that PowerShell saw - /pass:"a \" b"
- was blindly enclosed in double quotes, as a whole, even though most target programs would parse /pass:"a \" b"
correctly as-is.
As a result, the explicitly provided double-quoting is invalidated (as it would then require another level of escaping) - and short of using --%
, the stop-parsing symbol, which then limits you to literals (or %...%
-style environment-variable references), there is no way around that.
If the target program recognizes an argument if it is double-quoted as a whole (e.g.,
"/pass:a b"
instead of /pass:"a b"
), you can omit the explicit double-quoting around the argument value.
Do note, however, that some target programs - including cmdkey.exe
and notably msiexec
- do not recognize the argument if it is double-quoted as a whole.
... /pass:$($password -replace '"', '\"')
With $password
literally containing a " b
, PowerShell then passes behind the scenes:
... "/pass:a \" b"
This is syntactically valid - for target programs that recognize \"
as an escaped "
, which is the norm - but, as stated, the fact that the entire argument is enclosed in `"...", and not just the value may not be supported by the target program.
[1] Windows PowerShell ignores any \
-escaping in the resulting token and considers all embedded "
to have syntactic function: From that perspective, if the token is not composed of any mix of directly concatenated unquoted and double-quoted strings, enclosing double-quoting is blindly applied - which may break the command.
This behavior is not only obscure, it prevents robust, predictable parameter passing.
PowerShell Core now recognizes \"
as as escaped; however, quotes that aren't pre-escaped as \"
still result in broken quoting; e.g., 'a "b c" d'
is passed as "a "b c" d"
, which target programs parse as 2 arguments, a b
and c d
(after quote removal).