GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Dollar Sign Gets 'Eaten' by -replace When More Than One Dollar Sign Adjacent In String · Issue #6842 · PowerShell/PowerShell

Dollar Sign Gets 'Eaten' by -replace When More Than One Dollar Sign Adjacent In String #6842

New issue
Copy link
New issue
Copy link
Closed
Closed
Dollar Sign Gets 'Eaten' by -replace When More Than One Dollar Sign Adjacent In String#6842
Copy link
Labels
Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aResolution-AnsweredThe question is answered.The question is answered.

Description

@blixthecat
blixthecat
opened on May 8, 2018
Issue body actions

If you try to do a -replace with a string that has two or more dollar signs next to it, one dollar sign gets removed. This happens even if the characters are escaped.

Steps to reproduce

Scenario 1: Two Dollar Signs in String Literal
image

Scenario 2: More Than Two Dollar Signs in String Literal
image

Scenario 3: One Dollar Sign in String Literal
image

Scenario 4: Two Dollar Signs in String Literal (escaped)
image

Expected behavior

Scenario 1: P@$$w0rd
Scenario 2: P@$$$w0rd
Scenario 3: P@$w0rd
Scenario 3: P@$$w0rd

Actual behavior

Scenario 1:
image

Scenario 2:
image

Scenario 3:
image

Scenario 4:
image

Environment data

$PSVersionTable
image

Activity

  1. mklement0 commented on May 8, 2018

    @mklement0
    Michael Klement (mklement0)
    on May 8, 2018
    Contributor
    More actions

    The -replace replacement operand is not a literal: $ has special meaning in it and is used to refer to aspects of the regex matching, such as $& to refer to the entire match and $1 to refer to what the 1st capture group matched.

    Therefore, $ characters you want to treat literally must be escaped by doubling them.
    (Note that this escaping mechanism is unrelated to PowerShell's `-based escaping).

    And that is what happened accidentally in your case: the $$ sequence was interpreted as an escaped $.

    Unescaped $ sequences that happen not to form a valid regex-match reference are also retained as literals, but it's better not to rely on that.

    You can read more about this here.

    The robust workaround is to use the following:

    $testString -replace '...', $password.Replace('$', $$')

    However, if your replacement operation doesn't actually need regex matching, only simple substring replacement, you can use [string]::Replace() for the entire operation, but note that it is case-sensitive by default:

    $testString.Replace('...', $password)
    Reacted by Rob Holt, blixthecat and Pyprohly
  2. Rob Holt (rjmholt)
    added
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on May 8, 2018
  3. blixthecat commented on May 8, 2018

    @blixthecat
    blixthecat
    on May 8, 2018
    Author
    More actions

    Thank you for explaining! I couldn't find a reference to that kind of escaping anywhere!

    Reacted by Michael Klement
  4. BrucePay commented on May 9, 2018

    @BrucePay
    Bruce Payette (BrucePay)
    on May 9, 2018
    Collaborator
    More actions

    We should probably have include a link to Substitutions in Regular Expressions in about_Comparison_Operators as well as mentioning that substitutions happen with -replace in the body of the document.

  5. MaximoTrinidad commented on May 9, 2018

    @MaximoTrinidad
    Maximo Trinidad (MaximoTrinidad)
    on May 9, 2018
    More actions

    Someone forgot to post that the symptom exist in PSCore6. Although I would have use the following .NET object replace method:

    PS C:\Program Files\PowerShell\6-preview> $password
    P@$$word
    PS C:\Program Files\PowerShell\6-preview> $password.Length
    8
    PS C:\Program Files\PowerShell\6-preview> $password.ToString()
    P@$$word
    PS C:\Program Files\PowerShell\6-preview> "$($password.ToString())"
    P@$$word
    PS C:\Program Files\PowerShell\6-preview> $testString.replace('%MGR_PWD',"$($password.ToString())");
    P@$$word
    

    I mostly use .NET object methods instead of using parameters. But, that's me!

  6. mklement0 commented on May 9, 2018

    @mklement0
    Michael Klement (mklement0)
    on May 9, 2018
    Contributor
    More actions

    Maximo Trinidad (@MaximoTrinidad):

    To be clear: the behavior is by design, and it is here to stay.
    However, the behavior is poorly documented, hence Bruce Payette (@BrucePay)'s suggestion.

    Using String.Replace(string oldvalue, string newvalue) may be the simplest solution in this case, but it is by no means a general alternative to -replace; not only do the behaviors differ, -replace offers many more features:

    • Regex support, which -replace invariably applies.

      • String.Replace() only supports literal substring replacement - both for matching and in the replacement string.

        • This prevents advanced matching behavior, such as anchoring matches or capturing parts of the input string and referencing these parts in the replacement-string operand.
        • On the flip side, you do not have to worry about escaping $ chars. in the replacement string, as you demonstrate.
      • You can indirectly get literal substring replacements with -replace too:

        • If the search operand is a string literal, \-escape all regex metacharacters that you want to be treated as literals.
          • If the search operand is a variable reference, call [regex]::Escape() on it.
        • If the replacement operand is a string literal, $-escape $ instances that you want to be treated as literals (i.e., double $ chars. meant to be literals).
          • If the search operand is a variable reference, call .Replace('$', '$$') on it (i.e., take advantage of simple substring replacement via String.Replace()) or, if you want to stick with -replace, use (... -replace '\$', '$$$$').
      • As an aside: thanks to work by @IISResetMe, -replace as of v6.1.0-preview.2 even supports passing a script block as the replacement operand; e.g.,
        '1 + 1 = 2' -replace '\d+', { [int] $_.Value * 2 } yields '2 + 2 = 4'

    • Case-insensitivity.

      • String.Replace(string oldValue, string newValue), is case-sensitive, but you can opt into case-sensitivity via overloads String.Replace(string oldValue, string newValue, bool ignoreCase, cultureinfo culture) or String.Replace(string oldValue, string newValue, System.StringComparison comparisonType)
      • Conversely, -creplace gives you case-sensitivity (more conveniently) in PowerShell.
    • Support for array-valued LHS operands.

    • Support for implicit to-string conversion of the LHS.

    P.S.: You can find an analogous juxtaposition of -split and String.Split() in this SO answer.

  7. mklement0 commented on May 10, 2018

    @mklement0
    Michael Klement (mklement0)
    on May 10, 2018
    Contributor
    More actions

    I've created a doc issue at MicrosoftDocs/PowerShell-Docs#2416

    blixthecat: Now that the issue is being tracked there, can I ask you to close this one?

  8. Bruce Payette (BrucePay)
    added
    Resolution-AnsweredThe question is answered.The question is answered.
    on May 14, 2018
  9. Ilya (iSazonov)
    closed this as completedon May 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aideally support can be provided via other mechanisms, but sometimes folks do open an issue to get aResolution-AnsweredThe question is answered.The question is answered.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.