To add an explanation to Theo's effective solution:
# Use of "..." around the entire argument is the key.
# (The extra space before and after the command is just for visual clarity.)
powershell.exe " echo 'a c' "
# Alternative with embedded double-quoting
powershell.exe " echo \"a c\" "
That is, enclosing the entire command in "..."
is necessary to avoid the whitespace normalization you saw.
When you pass a command (piece of PowerShell code) to the PowerShell CLI, via the -Command
(-c
) parameter (which is positionally implied in your case), PowerShell performs the following command-line parsing first, by splitting the command line into:
- white-space separated tokens
- with double-quoted tokens (
"..."
) getting recognized as single tokens even if they contain spaces, with the interior spaces getting preserved as-is; note that these (unescaped) "
are removed in the process).
- Note: By contrast,
'...'
-enclosed tokens are not recognized as single tokens on the command line (even though inside a PowerShell session they are), so that 'a b'
is split into verbatim 'a
and b'
.
The resulting tokens are then joined with a single space to form the single string that is then interpreted and executed as PowerShell code.
It is during the splitting by whitespace - which can be any number of spaces between tokens - that the information about how many spaces there were between tokens is lost.
Only inside "..."
-enclosed tokens is the whitespace preserved as-is, hence the use of "..."
around the entire command above.
If you need to use "
quoting as part of the PowerShell command (to use string interpolation), "
characters must be escaped as \"
, as shown in the second command at the top.
However, if you're calling from cmd.exe
/ a batch file, this may break due to how cmd.exe
parses command lines. In such edge cases, use the workarounds discussed in this answer.