What is the difference between the escape backtick "`" and backslash "\" in PowerShell? - powershell

I know that both are used in PowerShell but for different contexts.
On the internet there is a paucity of information on this topic and the only site that talks about it (without making me understand the concept) is:
https://www.rlmueller.net/PowerShellEscape.htm
I am a beginner with PowerShell, I am recently approaching it.
A use case of the \ escape came up in the answer to this other topic of mine:
PowerShell removes multiple consecutive whitespaces when I pass arguments to a nested Start-Process command
Is there anyone who can explain to me in detail the difference between the escape backtick ` and backslash \ in PowerShell, with examples and use cases?
At least one source is welcome, but it is not mandatory.

vonPryz's helpful answer covers the PowerShell-internal angle well; let me attempt a systematic summary that includes the PowerShell CLI angle, as well as passing arguments with embedded " to external programs:
Inside a PowerShell session, the only escape character is ` (the so-called backtick), in the following contexts:
Inside an expandable string ("...", double quoted), but not inside a verbatim string ('...', single-quoted); for the supported escape sequences, see the conceptual about_Special_Characters help topic:
# " must be escaped; escape sequence `n expands to a newline.
"3`" of`nrain"
In unquoted command arguments:
# > must be escaped to write verbatim 'a>b',
# since outside a quoted string an unescaped > is a redirection.
Write-Output a`>b
For line-continuations:
# Spread the Get-Date call across two lines.
# Important: ` must be the *very last char* on the line.
Get-Date `
-Year 2525
Note: Various subsystems, whether PowerShell-specific or not, may have their own escaping rules, such as \ in regular expressions and ` in wildcard expressions. Since arguments to those subsystems are delivered via PowerShell strings, it's best to use verbatim string literals, so as to avoid confusion between PowerShell's own string interpolation and what the target subsystem ends up seeing; e.g. 'A $50 fine.' -match '\$50' (\ is needed to treat regex metacharacter $ literally).
When PowerShell is called from the outside, via its CLI, different rules apply, possibly in addition:
In order to adhere to widely used convention for CLIs (command-line interfaces, programs that accept arguments via a command line) on Windows:
In calls to powershell.exe, the Windows PowerShell CLI, " characters must be escaped with a backslash - i.e. as \" - in order to be preserved during parsing of the original command line.
pwsh.exe, the CLI of the cross-platform, install-on-demand PowerShell (Core) 7+ edition, now commendably alternatively accepts ""[1] in lieu of \", which makes calls from cmd.exe more robust. To get the same robustness in Windows PowerShell - from cmd.exe only - use "^"" (sic).
Note that - unlike \" - these escape sequences only work inside an (unescaped) "..." string (e.g., pwsh.exe -c " ""you & I"" " or powershell.exe -c " "^""you & I"^"" "
By contrast, unescaped " have syntactic function on the command line and tell PowerShell where the boundaries between arguments are; these " instances are removed during command-line parsing.
This ensures that outside callers that merely want to invoke a PowerShell script file (.ps1) with arguments, using the -File parameter, can use the conventional syntax and needn't special-case calls to PowerShell's CLI.
However, if you pass a string containing PowerShell code to the CLI, using the -Command parameter, what PowerShell ends up interpreting obviously must be syntactically valid PowerShell code.
Caveat: If you specify neither -Command nor -File:
powershell.exe defaults to -Command
pwsh.exe now defaults to -File
For the differences between -File and -Command calls and when to use which, see this answer.
If you use -Command, there are two, sequential parsing stages:
The command-line parsing stage, where syntactic (unescaped) " are removed, and escaped \" (or "") turn into literal ".
The result of this stage is then parsed as PowerShell code, as it would be from inside a PowerShell session.
Therefore, you may situationally have to combine \ and `-escaping; e.g. (call from cmd.exe):
C:>powershell.exe -Command " \"3`\" of snow as of $(Get-Date)\" "
3" of snow as of 11/04/2021 14:13:41
Note the use of `\" in order to make PowerShell see `", i.e. a properly escaped " inside a "..." string, after command-line parsing.
Alternatively, depending on the specifics of the command(s) you pass to -Command, using embedded '...' quoting may be an option, which simplifies matters, because ' chars. don't require escaping:
C:>powershell.exe -Command " '3\" of snow as of today.' "
3" of snow as of today.
Given that '...' strings in PowerShell are verbatim strings, use of '...' is only an option if you don't require string interpolation (such as the $(Get-Date) subexpression in the prior example).
Escaping " when calling external programs from PowerShell:
As a shell, it is PowerShell's job to pass the arguments that were passed based on its syntax rules to a target executable, so that the verbatim values that result from PowerShell's parsing are passed in a way that makes the target executable see them as such. In other words: PowerShell should perform any required escaping automatically, behind the scenes. (Unlike cmd.exe, PowerShell cannot just pass its own argument syntax through as-is, because external CLIs cannot be expected to understand '...' strings (single-quoting) or `-escaping).
To use a simply example: Passing '3" of snow' should be passed as "3\" of snow" behind the scenes, based on the most widely used escaping convention.
Sadly, up to PowerShell 7.2.x, this is not the case, and embedded " characters in arguments for external programs must additionally, manually be \-escaped in order to be passed through properly.
This has been fixed in PowerShell 7.3, with selective exceptions on Windows - see the new $PSNativeCommandArgumentPassing preference variable
# Broken behavior up to PS v7.2.x
PS> cmd /c echo '{ "foo": "bar" }'
"{ "foo": "bar" }" # !! Embedded " aren't escaped.
PS> choice.exe /d Y /t 0 /m '{ "foo": "bar" }'
{ foo: bar } [Y,N]?Y # !! When parsed by an executable,
# !! embedded " are effectively LOST.
# Manual escaping required.
PS> choice.exe /d Y /t 0 /m '{ \"foo\": \"bar\" }'
{ "foo": "bar" } [Y,N]?Y # OK
This bug has existed since v1, and has never been fixed so as to avoid breaking existing workarounds.
[1] Inside PowerShell, in "..." strings only, you may also use "" to escape an embedded ", as an alternative to `"

The backtick ` is used as the escape character in Powershell. That is, escaping quotes, tabs and whatnot. Unlike in many other environments, Powershell's newline is `n, not \n. This has the benefit of simplifying paths, since those use backslash in Windows.
As for a practical example, in many programming languages one needs to escape the backslashes in paths. If you have an application located at
c:\program files\newApplication\myApp.exe
Its path must be written as
c:\\program files\\newApplication\\myApp.exe
The double-backslash notation means that there is actaully a backslash, not a metacharacter such as tab or newline. Note that the path contains \newApplication. Now, \n usually means a newline, but it clearly isn't the case. The file does not reside in
c:\program files\
ewApplication\myApp.exe
after all, doesn't it?
The escaping is not needed in Powershell, as the backslash doesn't have special meaning by itself. When Powershell sees c:\program files\newApplication\myApp.exe, it doesn't assign any special meaning to the forementioned \n part, it is just a string literal.
The backslash \ is used as the escape character in regular expressions and to signify metacharacters. That is, to match a literal * in regex, it must be escaped, lest it means the Kleene star (zero or more matches).

Related

How to escape a string to pass it to another command?

I have an array of arguments $p = "a", "b c", "d`"e" to be passed to command.
I can do this like so:
& my_command $p
Now, I need to call that same command inside some external wrapper (binary), which works like this using fixed parameters:
& my_wrapper /Command=my_command "/CommandParameters=a 'b c' 'd`"e'"
But how can I pass the /CommandParameters from the array $p?
One approach that works for some inputs is to pre-process the array like so:
$p = $p | Foreach {"\`"$_\`""}
& my_wrapper /Command=my_command "/CommandParameters=$p"
but this seems pretty fragile. Values in $p do contain spaces and quotes.
In Bash, I could use printf %q to properly escape the parameters.
The following encloses all strings in the array in embedded "..." and additionally escapes preexisting embedded " chars. as \", which is what external programs typically expect:
Note: In Windows PowerShell and in PowerShell (Core) up to at least v7.1, an additional round of \-escaping is - unfortunately - needed when passing arguments with embedded " to external programs:
$p = "a", "b c", "d`"e"
$pEscaped = $p.ForEach({ '\"{0}\"' -f ($_ -replace '"', '\\\"') })
& my_wrapper /Command=my_command "/CommandParameters=$pEscaped"
Note: While $pEscaped is a collection (array) of strings, using it inside an expandable string ("...") automatically creates a space-separated single-line representation; e.g. "$('foo', 'bar')" yields verbatim foo bar
This longstanding problem - the unexpected need for manual \-escaping of embedded " chars. when passing arguments to external programs - is summarized in this answer.
Preview versions of v7.2 now come with experimental feature PSNativeCommandArgumentPassing, which is an attempted fix, but, unfortunately, it looks like it will lack important accommodations for high-profile CLIs on Windows - see this summary from GitHub issue #15143. However, the fix is effective for executables that expect " to be escaped as \", so the solution simplifies to (using string concatenation (+) inside an expression ((...)) to construct the argument in-line):
# Note: Requires experimental feature PSNativeCommandArgumentPassing
# to be turned on, available in preview versions of v7.2
& my_wrapper /Command=my_command ('/CommandParameters=' + $p.ForEach({ '"{0}"' -f ($_ -replace '"', '\"') }))
Note:
Assuming this experimental feature becomes an official one (which is in general never guaranteed), the corrected behavior will most likely be opt-in, via a preference variable: $PSNativeCommandArgumentPassing = 'Standard' ('Legacy' selects the old behavior).
If you don't mind installing a third-party module (authored by me), the Native module (Install-Module Native) comes with a backward- and forward-compatible helper function, ie, which too obviates the need for the extra escaping, while also containing the important accommodations for high-profile CLIs on Windows missing from the experimental feature:
# Note: Assumes `Install-Module Native` was called.
# Just use `ie` instead of `&`
ie my_wrapper /Command=my_command ('/CommandParameters=' + $p.ForEach({ '"{0}"' -f ($_ -replace '"', '\"') }))
As for what you tried:
[Enclosing the value in embedded "] seems pretty fragile
If you additionally escape any preexisting " as \" (\\\", if the argument-passing bug must be compensated for), as shown above, it works robustly.
Ultimately, the following command line must be executed, which PowerShell constructs behind the scenes:
my_wrapper /Command=my_command "/CommandParameters=\"a\" \"b c\" \"d\\\"e\""
When my_wrapper parses its command line, it ends up seeing the following verbatim string as the last argument:
/CommandParameters="a" "b c" "d\"e"
In Bash, I could use printf %q to properly escape the parameters.
Unfortunately, PowerShell has no equivalent feature, but it's not hard to provide it ad hoc:
Meta-quoting strings in Powershell:
Note:
By meta-quoting I mean the functionality that Bash's printf %q provides: It formats a given string value to become usable as a string literal in source code. For instance (this example illustrates the general principle, not printf %q's actual behavior), verbatim string value a b is transformed to verbatim string value "a b", and the latter can be used as an argument when constructing a command line stored in a string.
The required approach depends on whether the meta-quoted string is to be used in the string representation of a PowerShell command (such as a cmdlet call) or that of a call to an external program, given their different escaping needs. Additionally, while most external programs on Windows (also) understand \" to be an escaped ", some - notably batch files and msiexec.exe - only understand "".
The commands below use the following sample input input string, which contains both a ' and a " (constructed via a verbatim here-string for quoting convenience):
$str = #'
6'1" tall
'#
The solutions below use the -f operator to synthesize the result strings, not just for conceptual clarity, but also to work around string interpolation bugs that can cause subexpressions embedded in expandable strings to yield incorrect results (e.g., "a$('""')b" and "a$('`"')b" both yield verbatim a"b - one " / the ` is missing); an alternative is to use simple string concatenation with +.
Unfortunately, it looks like these bugs will not be fixed, so as to preserve backward-compatibility; see GitHub issue #3039
The verbatim content of the resulting strings is shown in source-code comments, enclosed in «...»; e.g. «"6'1\""» (this representation is just for illustration; PowerShell does not support such delimiters).
Meta-quoting for external programs:
Note:
On Windows, console applications typically only recognize double quotes as string delimiters in their command lines, so that's what the solutions below focus on. To create a single-quoted representation that is understood by POSIX-compatible shells such as bash, use the following:
"'{0}'" -f ($str -replace "'", "'\''"), which yields verbatim '6'\''1" tall' (sic).
In edge cases on Windows, you may have to bypass PowerShell's command-line parsing altogether, so as to fully control the command line that is used for actual process creation behind the scenes, either via --%, the stop-parsing symbol, which has severe limitations or by delegating the invocation to cmd.exe, by passing an entire command line to /c - again, see this answer.
For external programs that require \"-escaping (typical):
# With the experimental, pre-v7.2 PSNativeCommandArgumentPassing
# feature turned on, you can directly pass the result
# as an external-program argument.
# Ditto with the `ie` helper function.
'"{0}"' -f ($str -replace '"', '\"') # -> «"6'1\" tall"»
# With additional \-escaping to compensate for PowerShell's
# argument-passing bug, required up to at least v7.1
'\"{0}\"' -f ($str -replace '"', '\\\"') # -> «\"6'1\\\" tall\"»
For external programs that require ""-escaping (e.g., batch files, msiexec - Windows-only):
# CAVEAT: With the experimental, pre-v7.2 PSNativeCommandArgumentPassing
# feature turned on, passing the result as an external-program argument
# will NOT work as intended, because \" rather than "" is invariably used.
# By contrast, the `ie` helper function automatically
# switches to "" for batch files, msiexec.exe and msdeploy.exe
# and WSH scripts.
'"{0}"' -f ($str -replace '"', '""') # -> «"6'1"" tall"»
# With additional escaping to compensate for PowerShell's
# argument-passing bug, required up to at least v7.1
'""{0}""' -f ($str -replace '"', '""""') # -> «""6'1"""" tall""»
Meta-quoting for PowerShell commands:
Note:
Fortunately, no extra escaping is ever needed in this case; the argument-passing bug discussed above only affects calls to external programs.
Creating a double-quoted representation ("..."):
'"{0}"' -f ($str -replace '"', '`"') # -> «"6'1`" tall"»
Creating a single-quoted representation ('...'):
"'{0}'" -f ($str -replace "'", "''") # -> «'6''1" tall'»

Is there a way to escape quotes in ripgrep for MS Windows (Powershell or CMD)?

I want to find a string "Hello (Hello starts with double quote) in text files using ripgrep.
Normally, in Bash or ZSH, this would work by escaping with backslash or surrounding with single quote:
rg \"Hello
rg '"Hello'
However, in MS Windows (Powershell and CMD), I've tried these but none of these worked:
rg \"Hello
rg '"Hello'
rg `"Hello
rg '`"Hello'
Is there any way to escape single or double quotes using ripgrep in MS Windows?
Verbatim string "Hello must ultimately be passed as \"Hello to rg ("\"Hello" would work too). That is, the verbatim " char. must be \-escaped:
From cmd.exe:
rg \^"Hello
^, cmd.exe's escape character, ensures that the " is treated verbatim and is removed by cmd.exe before calling rg.
Note that ^ isn't strictly necessary here, but it prevents the " from being considered the start of a double-quoted argument, which could make a difference if there were additional arguments.
From PowerShell:
rg \`"Hello
`, PowerShell's escape character, ensures that the " is treated verbatim and is removed by PowerShell before calling rg.
Arguably, the explicit \-escaping shouldn't be necessary, because it is the duty of a shell to properly pass arguments to target executables after the user has satisfied the shell's own escaping requirements (escaping the verbatim " with ^ in cmd.exe, and with ` in PowerShell).
In the context of PowerShell, this problematic behavior is summarized in this answer.
Note that in PowerShell this extra escaping is only needed if you call external programs; it isn't needed PowerShell-internally - such as when you call Select-String, as shown in js2010's answer.
You can use rg -F \"Hello
-F, --fixed-strings
Treat the pattern as a literal string instead of a regular expression. When this flag is used, special regular expression meta characters such as .(){}*+ do not
need to be escaped.
This flag can be disabled with --no-fixed-strings.
If you're in powershell you might as well do:
get-childitem file | select-string '"hello'
file:1:"hello

pwsh -Command is removing quotation marks

In pwsh call the following:
Write-Host '{"drop_attr": "name"}'
Result ok:
{"drop_attr": "name"}
Now do the same via pwsh:
pwsh -Command Write-Host '{"drop_attr": "name"}'
Result is missing quotation marks and square brackets?
drop_attr: name
Update:
PowerShell 7.3.0 mostly fixed the problem, with selective exceptions on Windows, and it seems that in some version after 7.3.1 the fix will require opt-in - see this answer for details.
For cross-version, cross-edition code, the Native module discussed at the bottom may still be of interest.
Unfortunately, PowerShell's handling of passing arguments with embedded " chars. to external programs - which includes PowerShell's own CLI (pwsh) - is fundamentally broken (and always has been), up to at least PowerShell 7.2.x:
You need to manually \-escape " instances embedded in your arguments in order for them to be correctly passed through to external programs (which happens to be PowerShell in this case as well):
# Note: The embedded '' sequences are the normal and expected
# way to escape ' chars. inside a PowerShell '...' string.
# What is *unexpected* is the need to escape " as \"
# even though " can normally be used *as-is* inside a '...' string.
pwsh -Command ' ''{\"drop_attr\": \"name\"}'' '
Note that I'm assuming your intent is to pass a JSON string, hence the inner '' ... '' quoting (escaped single quotes), which ensures that pwsh ultimately sees a single-quoted string ('...'). (No need for an explicit output command; PowerShell implicitly prints command and expression output).
Another way to demonstrate this on Windows is via the standard choice.exe utility, repurposed to simply print its /m (message) argument (followed by verbatim [Y,N]?Y):
# This *should* preserve the ", but doesn't as of v7.2
PS> choice /d Y /t 0 /m '{"drop_attr": "name"}'
{drop_attr: name} [Y,N]?Y # !! " were REMOVED
# Only the extra \-escaping preserves the "
PS> choice /d Y /t 0 /m '{\"drop_attr\": \"name\"}'
{"drop_attr": "name"} [Y,N]?Y # OK
Note that from inside PowerShell, you can avoid the need for \-escaping, if you call pwsh with a script block ({ ... }) - but that only works when calling PowerShell itself, not other external programs:
# NOTE: Works from PowerShell only.
pwsh -Command { '{"drop_attr": "name"}' }
Background info on PowerShell's broken handling of arguments with embedded " in external-program calls, as of PowerShell 7.2.1:
This GitHub docs issue contains background information.
GitHub issue #1995 discusses the problem and the details of the broken behavior as well as manual workarounds are summarized in this comment; the state of the discussion as of PowerShell [Core] 7 seems to be:
A fix is being considered as an experimental feature, which may become an official feature, in v7.3 at the earliest. Whether it will become a regular feature - i.e whether the default behavior will be fixed or whether the fix will require opt-in or even if the feature will become official at all - remains to be seen.
Fixing the default behavior would substantially break backward compatibility; as of this writing, this has never been allowed, but a discussion as to whether to allow breaking changes in the future and how to manage them has begun: see GitHub issue #13129.
See GitHub PR #14692 for the relevant experimental feature, which, however, as of this writing is missing vital accommodations for batch files and msiexec-style executables on Windows - see GitHub issue #15143.
In the meantime, you can use the PSv3+ ie helper function from the Native module (in PSv5+, install with Install-Module Native from the PowerShell Gallery), which internally compensates for all broken behavior and allows passing arguments as expected; e.g.,
ie pwsh -Command ' ''{"drop_attr": "name"}'' ' would then work properly.
Another way. Are you in Windows or Unix?
pwsh -c "[pscustomobject]#{drop_attr='name'} | convertto-json -compress"
{"drop_attr":"name"}
Another way is to use "encoded commands".
> $cmd1 = "Write-Host '{ ""description"": ""Test program"" }'"
> pwsh -encoded ([Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd1)))
{ "description": "Test program" }

How to escape the contents of a dynamic variable in PowerShell?

Let's say I have the variable $password = Get-Passwd ACME\bob where I get the password of a given user. The password contains all sorts of special characters including $, that is used by PowerShell.
I need to dynamically use the password in the following command:
cmdkey.exe /add:$hostname /user:"$user" /pass:"`"$password`""
I need to escape the " character on both sides so the command is parsed as pass:"123qwe" and not pass:123qwe. The issue is that it breaks when the password includes a $ character. How can I pass the password to this command without breaking it?
Running Executables in PowerShell
For most executables, it's not necessary to manually quote the parameters in PowerShell. Just write the command using any variables, and the PowerShell parser will automatically quote the arguments for the program's command line. This usually "just works."
cmdkey.exe /add:hostname /user:username /pass:$pass
You can inspect the actual command line that PowerShell passes to an executable by using a small program I wrote called showargs.exe, available at the following page:
https://www.itprotoday.com/management-mobility/running-executables-powershell
Example:
showargs cmdkey.exe /add:hostname /user:username /pass:$pass
The showargs.exe program simply echoes its command line to standard output so you can see the literal command line that PowerShell actually passes to the executable.
An embedded $ character shouldn't be a problem. If that character is in a PowerShell string variable, PowerShell will pass it along as a part of the command line string. Example:
$pass = 'my$pass'
cmdkey.exe /add:hostname /user:username /password:$pass
No matter how you pass the command line to the program, it's important to note that the interpretation of that command line is up to that individual program. (For example, if an executable's parser doesn't support certain characters, no amount of quoting or parsing will allow you to work around the limitation.)
Cmdkey.exe Uses a Non-Standard Parser
In my prefunctory testing of of cmdkey.exe, it seems it does not have a way of "escaping" the " character on its command line. Since this seems to be the case, you will not be able to use cmdkey.exe to store a credential that contains an embedded " character.
Embedding a Space in a Cmdkey.exe Command Line Argument
Because cmdkey.exe uses a non-standard command-line parser, you can't use a variable on its command line that contains embedded spaces. For example:
PS C:\> $pass = "my pass"
PS C:\> showargs cmdkey.exe /add:hostname /user:username /password:$pass
cmdkey.exe /add:hostname /user:username "/password:my pass"
The "/password:my pass" evidently confuses the cmdkey.exe parser, so we have to work around this behavior by bypassing PowerShell's default parsing behavior. The simplest way to do this is by escaping the quotes around the argument containing the space:
PS C:\> showargs.exe cmdkey.exe /add:hostname /user:username /password:`"$pass`"
cmdkey.exe /add:hostname /user:username /password:"my pass"
In any case, you can use showargs.exe to diagnose the trouble and work out a solution appropriate to the executable you need to run.
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).

Escaping the and (&) sign in Powershell

I need to use \r\n inside of ffmpeg --header parameter. This works in Unix, but not in Windows command prompt. So I was wondering to use powershell
powershell c:\ffmpeg -headers 'User-Agent: user-agent'"`r`n"'Cookies: my-cookie' ...
I understand I have to use 'string' when special characters are used and
"`r`n"
as my \r\n delimiter.
I have also tested that I can mix them together, like 'this '"is "'text' to get this is text
However if my string (cookie or user-agent) contains & character, it fails.
Example: powershell c:\ffmpeg -headers 'Cookies: param=a=1&b=2; session=123'
How can I "escape" & character in one-liner?
These examples (some parts are masked) are accepted by CMD, but they are not working
powershell -c "c:\ffplay -user_agent ""Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0"" -headers ""Cookie: nlqptid=h=676886edeea5bae904b0cf53daec8038.1519940538670&hdnea=exp=1519940598~acl=/*~hmac=C0E019502B060D23AB02BB157FCFFC72404500770A2CE5B00789A84AAEFBD77F&nltid=xxxxxxxxxx&nltdt=0&uid=744826&csid=xxxxxxxxxx; hdntl=exp=1520026938~acl=%2f*~hmac=952689e6de57a2a201ddc1d4c0794962fdc886ea48cf41494a42e787ef923bf9`r`n"" -i ""https://xxxxxxxxxx.net/nlds_vod/xxxxxxxxxx/vod/2018/02/28/cd264e10-dd54-3de2-df90-4c1cac104dcb/v1/stream/cd264e10-dd54-3de2-df90-4c1cac104dcb_1_4500_pc.mp4.m3u8"""
or
powershell -c "c:\ffplay -headers ""User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0`r`nCookie: nlqptid=h=676886edeea5bae904b0cf53daec8038.1519940538670&hdnea=exp=1519940598~acl=/*~hmac=C0E019502B060D23AB02BB157FCFFC72404500770A2CE5B00789A84AAEFBD77F&nltid=xxxxxxxxxx&nltdt=0&uid=744826&csid=xxxxxxxxxx; hdntl=exp=1520026938~acl=%2f*~hmac=952689e6de57a2a201ddc1d4c0794962fdc886ea48cf41494a42e787ef923bf9`r`n"" -i ""https://xxxxxxxxxx.net/nlds_vod/xxxxxxxxxx/vod/2018/02/28/cd264e10-dd54-3de2-df90-4c1cac104dcb/v1/stream/cd264e10-dd54-3de2-df90-4c1cac104dcb_1_4500_pc.mp4.m3u8"""
ffplay says
An input file must be specified
But the input file is specified after -i parameter.
What is wrong with this command?
Note that the implementation is a part of the existing batch script, therefore it is required to use a syntax working inside of batch file.
When calling from cmd.exe, things get tricky; here's a simplified example:
powershell -c "ffmpeg.exe -h "^""User-Agent: usra`r`nCookies: parm=a=1&b=2; session=1"^"""
In short: From cmd.exe / batch files, to pass what PowerShell's CLI should see as a double-quoted argument inside an overall "..." string passed to -Command (-c)[1] (which is powershell.exe's default parameter):
\"...\" is normally the preferred form of escaping, because it works in both PowerShell editions and also aligns with how most CLIs expect " to be escaped; however, it doesn't work in all cases when calling from cmd.exe, such as the case at hand.
By contrast, \"...\" is always safe to use from no-shell contexts, such as Task Scheduler and the Windows Run dialog (WinKey-R).
To also handle all edge cases of calling the PowerShell CLI from cmd.exe / batch files - namely when the string to be quoted contains cmd.exe metacharacters such as &, such as in your case - use the following in lieu of \"...\":
When calling Windows PowerShell (powershell.exe): use "^""..."^"" (sic), as shown above.
Caveat: This doesn't work for capturing the output in a variable via a for /f loop: If whitespace normalization (runs of two or more spaces becoming a single space each) isn't a concern (it rarely is) use \""...\"" (sic) inside a for /f loop. In the rare event that it is a concern, use " ^^^"\"...\"" (sic) - see the bottom section of this answer.
When calling PowerShell (Core) v6+ (pwsh.exe): use ""...""
As a general requirement, literal % chars. must be escaped as %% to prevent them from being interpreted as part of a cmd.exe variable reference in batch files. From the command prompt, things are unfortunately more complicated.
The command line for PowerShell is best passed as a single, "..."-enclosed string, via parameter -c (short for -Command, which in Windows PowerShell is the default, but that has changed in PowerShell (Core) v6+, which now defaults to -File).
Since the PowerShell CLI strips unescaped " characters during command-line parsing, before interpreting the result as PowerShell code, any " instances to be retained as part of the command to ultimately execute must be escaped (note that PowerShell-internally `" is used to escape a "; alternatively, in the context of "..." strings only, "" may be used).
"^""..."^"" (Windows PowerShell) and ""..."" (PowerShell (Core) v6+) inside an overall "..." -c argument ensure that cmd.exe itself interprets ... as being inside a double-quoted string, which is what makes these escaping forms robust.
If \"...\" were used inside "..." from cmd.exe (which only recognizes "" as an escaped "), it would in effect see ... as being outside a double-quoted string, which would cause values that contain cmd.exe metacharacters such as & and | to break the command. Compare the following invocations from cmd.exe:
# OK - prints verbatim: The king of "Rock & Roll"
C:\>powershell.exe -c " 'The king of "^""Rock & Roll"^""' "
C:\>pwsh.exe -c " 'The king of ""Rock & Roll""' "
# !! BROKEN - cmd.exe interprets "&" as a metachar.
C:\>powershell.exe -c " 'The king of \"Rock & Roll\"' "
C:\>pwsh.exe -c " 'The king of \"Rock & Roll\"' "
Note: You could fix the use of \" by ^-escaping such cmd.exe characters (e.g., ^&), but that requires you to analyze the string carefully and determine which specific parts cmd.exe sees as unquoted. If you make a mistake, the ^ will be retained as a literal part of the string. The advantage of the "^"" / "" approach is that you needn't worry about such pitfalls.
As an aside: 'this '"is "'text' does not create a single string the way it does in Bash; in PowerShell:
As a stand-alone expression, it causes a syntax error (try executing it by itself); you'd have to use ('this ' + "is " + 'text') or use a single quoted string ('this is text').
As an argument passed to a command (program), it is interpreted as 3 distinct arguments - see this answer for an explanation of this - surprising - behavior.
[1] Using overall "..." quoting around what then becomes a single -Command argument is conceptually preferable, but not strictly necessary. If overall "..." quoting is not used, \"-escaping of " characters that are to be treated as part of the command is the only supported form - see this answer.