As I have learned, when invoking PowerShell from cmd.exe
, with the -Command
option, escaping rules are essentially those used in Linux. So you use a backslash (\
), rather than the usual backtick (`
).
This is to say that you don't write:
C:\> powershell -c "echo `"That's a single quote: ' `""
but
C:\> powershell -c "echo \"That's a single quote: ' \""
to get:
That's a single quote: '
And this is the exact equivalent of what you would type in a Linux terminal:
~ >>> bash -c "echo \"That's a single quote: ' \""
If I am not wrong, this feature is named PSNativeCommandArgumentPassing. But comparisons work up to a certain point. In fact, under Linux you write:
~ >>> bash -c "echo \"That's a double quote: \\\" \""
to get:
That's a double quote: "
while the equivalent PowerShell line:
C:\> powershell -c "echo \"That's a double quote: \\\" \""
gives
The string is missing the terminator: ".
By trial and error, I realised that:
C:\> powershell -c "echo \"That's a double-quote: `"" \""
works as expected.
Can you explain to me what is the logic behind: `""
?
Also, what are the equivalent commands when calling PowerShell from powershell.exe
, rather than cmd.exe
?
tl;dr
On PowerShell's command line only, use \"
to pass a "
through to the code that -c
(-Command
) should execute.
Only in the resulting code does PowerShell's usual escaping of "
as `"
apply, so you may have to combine the two escaping techniques: `\"
.
`""
, had the same effect, but it doesn't work reliably.[1]\"
works robustly with respect to PowerShell's own parsing of its command line, but can situationally break calls on the cmd.exe
side - see the bottom section for workarounds.
When calling CLIs (external console applications) from PowerShell, not only do PowerShell's own, different quoting rules apply first (support for '...'
strings, embedded "
inside "..."
escaped as `"
), a long-standing bug up to PowerShell 7.2.x additionally requires escaping "
chars. with \
when embedded in external-program arguments (only); see this answer.
this feature is named
PSNativeCommandArgumentPassing
No; this feature - which became official in PowerShell 7.3 (see this answer) - does not come into play, because:
it generally isn't (and won't be) available in the legacy Windows PowerShell edition that you're invoking via its CLI, powershell.exe
(whereas the modern, cross-platform PowerShell (Core) edition's CLI is pwsh.exe
)
it only applies to calls from inside a PowerShell session.
it is designed to address a long-standing problem when calling external programs with embedded "
or empty-string string arguments from PowerShell - see this answer.
Therefore, the linked answer addresses your last question:
Also, what are the equivalent commands when calling PowerShell from
powershell.exe
, rather thancmd.exe
?
In short: unfortunately, up to at least PowerShell 7.2.x you'll have to additionally, manually escape "
chars. with "
embedded in external-program arguments (only).
Why the following works from cmd.exe
:
powershell -c "echo \"That's a single quote: ' \""
PowerShell only recognizes \
as an escape character on its command line, for consistency with other CLIs.
Inside a PowerShell session, only `
(backtick) serves as the escape character.
Caveat: While \"
to escape "
works consistently in both PowerShell editions on the PowerShell (command-line parsing) side, situationally it can break cmd.exe
's own parsing - see the bottom section.
When the PowerShell CLI is invoke via -c
(-Command
) with a piece of PowerShell source code to execute, that code (the argument(s) following -c
is parsed in two stages:
"
chars. are stripped, wheres escaped ones (\"
) are kept and unescaped.Therefore, what PowerShell ends up executing is verbatim:
echo "That's a single quote: ' "
From the above follows why this does not work:
:: SYNTAX ERROR
powershell -c "echo \"That's a double quote: \\\" \""
PowerShell ends up trying to execute verbatim
echo "That's a double quote: \" "
which is a syntax error, because inside a PowerShell session \
doesn't escape "
-only `"
or - inside "..."
, alternatively - ""
do.
From the above follows why this (mostly) works:
:: Works, but not robustly
powershell -nop -c "echo \"That's a double-quote: `"" \""
""
sometimes, but not always works as an alternative to \"
;[1] here it does - see also the bottom section.
As a result, PowerShell ends up executing the following verbatim, which works, because the escaped "
that was passed through is now `
-escaped, as it needs to be inside a PowerShell "..."
string:
echo "That's a double-quote: `" "
To avoid the brittle ""
escaping, it is better to formulate this command by combining the required `
-escaping with the command-line \
-escaping - i.e. `\"
- but see the bottom section for a fully robust solution:
powershell -nop -c "echo \"That's a double-quote: `\" \""
Avoiding parsing problems on the cmd.exe
side, a safe alternative to \"
:
While \"
to escape "
works consistently in both PowerShell editions on the PowerShell (command-line parsing) side, situationally it can break cmd.exe
's own parsing. By contrast, using \"
is safe when calling from no-shell environments such as Task Scheduler.
While there are workarounds, they are, unfortunately PowerShell edition-specific:
In Windows PowerShell (powershell.exe
)
"^""
(sic) instead of \"
In PowerShell (Core) (v6+, pwsh.exe
)
""
instead of \"
Important:
These workarounds require that the whole code to pass to -c
(-Command
) be passed as a single, "..."
-enclosed argument.
-c
(-Command
) also accepts multiple arguments - which may individually be double-quoted or not - in which case it simply concatenates these arguments, after having stripped unescaped "
, to form the code to execute. This technique situationally allows you to get away with \"
-escaping (e.g., powershell -c \"Between 2 & 3`\"\"
, but (a) it requires you to pay close attention to which parts of the command cmd.exe
will see as unquoted, (b) would require you to ^
-escape any cmd.exe
metacharacters such as &
in those parts, and (c) invariably performs whitespace normalization, i.e. folds runs of multiple spaces into a single one each.
The following calls, designed to print verbatim Between 2 & 3"
, demonstrate this:
:: BREAKS, because cmd.exe sees `&` as *outside a double-quoted string*
powershell -c " \" Between 2 & 3`\" \" "
:: PowerShell (Core) workaround
pwsh -c " "" Between 2 & 3`"" "" "
:: Windows PowerShell workaround
powershell -c " "^"" Between 2 & 3`"^"" "^"" "
[1] An example of where ""
inside "..."
doesn't work is powershell -c "echo \" Nat `""King`"" Cole \""
: instead of Nat "King" Cole
, it prints Nat "King Cole
, i.e. the second escaped "
is missing (it would work fine in pwsh.exe
, however, as discussed in the bottom section). It's ultimately not worth speculating how, precisely, embedded ""
sequences are parsed by powershell.exe -c
, given that it demonstrably isn't reliable and that reliable alternatives do exist (\"
or, from cmd.exe
, also "^""
).