1

One might need to replace each backslash in a string, say a file path, with double-backslash. Eg, wmic requires this (eg: https://stackoverflow.com/a/50878476/4582204).

So one might try this code

'foo\bar' -replace '\\', '\\\\'

however it produces the following with 4 backslashes:

foo\\\\bar

instead of the desired result with 2 backslashes:

foo\\bar

Why?

EDIT: was closed as a duplicate of How to handle backslash character in PowerShell -replace string operations?

Not really. The reason why -replace '\\', '\\' looks like it does nothing is because of 2 things: the first term IS a regex and escaped AND the second term is NOT a regex and is not escaped.

That page handles the first issue in the first term, but does not mention the second issue--that the second term is not escaped.

So that page does not in fact have a complete answer to this precise flavor of the question.

4
  • Btw, get-wmiobject can do anything wmic can do.
    – js2010
    Commented Oct 22, 2024 at 1:07
  • @js2010: Btw, Get-WmiObject has been obsolete since 2012, gjven that the WMI cmdlets were superseded by the CIM cmdlets, such as Get-CimInstance. See stackoverflow.com/a/54508009/45375
    – mklement0
    Commented Oct 22, 2024 at 1:15
  • @js2010 what if someone were writing a powershell script to demonstrate the use of wmic for use in contexts where powershell is not available (WindowPE, places in the registry, install unattended files, task scheduler commands, and many more (altho those last 2 you can call powershell from the cmd.exe context but it STARTS in cmd.exe)) lol :) Commented Oct 22, 2024 at 1:51
  • ok, btw you can have powershell enabled in winpe, task scheduler can run powershell directly
    – js2010
    Commented Oct 22, 2024 at 3:16

2 Answers 2

1

The two RHS operands of PowerShell's -replaceoperator require distinct syntax forms (both expressed as strings); that is, in
<input-string> -replace <regex>, <substitution>:

  • <regex> is a regex, in which \ is a metacharacter (among several others) and therefore requires escaping as \\ in order to be interpreted verbatim.

    • To escape a regex operand that may contain \ characters and/or other regex metacharacters (e.g. .) as a whole in a manner that ensures that it is interpreted verbatim, pass it to [regex]::Escape(...)
  • <substitution> is a substitution expression, in which \ is not a metacharacter and is therefore used as-is - no escaping needed.

    • Only $ is a metacharacter in substitution expressions (used to refer to what the regex captured, e.g. $1 to refer to the first capture group's value), requiring a verbatim $ to be escaped as $$.

    • To escape a substitution operand that may contain $ characters meant to be used verbatim, call .Replace('$', '$$') on it.

For a comprehensive overview of the -replace operator, see this answer.


It follows from the above that \\ is treated differently in the two RHS operands, and that the following, which looks like a no-op in fact replaces literal \ chars. in the input with literal \\ each:

# -> 'a\\b'
'a\b' -replace '\\', # regex: matches verbatim \ (escaping needed)
               '\\'  # substitution expression: uses \\ verbatim (no escaping needed)

To illustrate programmatic escaping of both operands to ensure their literal treatment:

# -> 'a\\b'
'a\b' -replace [regex]::Escape('\'),
               '\\'.Replace('$', '$$')

Note:

  • The .Replace() operation obviously has no effect here, but illustrates how a substitution operand must be escaped in general.

  • If both operands as a whole are to be treated literally, it is more efficient to use the literal replacements performed by System.String.Replace() instead, though note that only .NET / PowerShell (Core) 7 has overloads that allow for case-insensitive replacements (all of PowerShell's text-related operators are case-insensitive by default).
    The equivalent of the above is:

    # -> 'a\\b'
    'a\b'.Replace('\', '\\')
    # In PowerShell 7, you can pass 'CurrentCultureIgnoreCase' as the 3rd argument
    # for case-insensitive replacements.
    
0

The answer (a very comprehensive one) is here: https://stackoverflow.com/a/64771432/4582204 (and this question will likely be closed as a duplicate).

But I wanted to simply and quickly say that in

-replace regex, replacement

the regex is a regex, and needs the two backslashes \\ because the first has to escape the second, but the replacement is literal, no escaping needed, so \\\\ is not two escaped backslashes but literally 4 backslashes.

So the correct code is:

'foo\bar' -replace '\\', '\\'

And while at first glance this code appears to be doing nothing, it is doing something, because the first backslash is an escape and second term is not escaped.

1
  • 1
    Thanks for linking to that answer; obvious self-interest aside, I recommend up-voting answers you find helpful, whether given directly in response to your question or in response to other questions. Good answer, but replacement is not a literal: in it, $ is a metacharacter, whereas \ is not. Please see my answer.
    – mklement0
    Commented Oct 22, 2024 at 2:17

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.