The two RHS operands of PowerShell's -replace
operator 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.
Get-WmiObject
has been obsolete since 2012, gjven that the WMI cmdlets were superseded by the CIM cmdlets, such asGet-CimInstance
. See stackoverflow.com/a/54508009/45375wmic
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 thecmd.exe
context but it STARTS incmd.exe
)) lol :)