skip to Main Content

I need to replace

location ~* "^/(888888-localhost/client)(.*)$" {
            proxy_pass https://localhost:32583;

by

location ~* "^/(888888-localhost/client)(.*)$" {
            proxy_pass https://localhost:$proxy;

I’m trying to achieve this with the following code with no success

Get-ChildItem 'C:nginxconfnginx.conf' | ForEach {
     (Get-Content $_) | ForEach  {$_ -Replace "location ~* ""^/(888888-localhost\/client)(.*)$"" {
            proxy_pass https://localhost:.+;", "location ~* ""^/(888888-localhost/client)(.*)$" {
                proxy_pass https://localhost:$proxy;""} | Set-Content $_
}

How can i do this using Powershell?

2

Answers


    • Since you want to match across lines, you cannot use the line-by-line processing that Get-Content does by default. Use the -Raw switch to read the entire file at once, into a single, multi-line string.

    • Since both your search string and the replacement string passed to the regex-based -replace operator contain metacharacters, you must escape them.

      • Note: If all you need is literal (verbatim) substring matching, including not needing to assert where the substring must match (start of the string, word boundary, …), using [string]::Replace() is the simpler option, however:

        • In Windows PowerShell [string]::Replace() is invariably, case-sensitive, in PowerShell (Core) 7+ it is by default, unlike PowerShell’s operators – see this answer for guidance on when to use -replace vs. [string]::Replace()
      • The search string must be escaped with [regex]::Escape(), so that the .NET regex engine, which the -replace operator invariably uses, treats it as a literal.

      • The substitution string must have any embedded $ characters escaped as $$, so that $ isn’t mistaken for the start of a capture-group reference.

      • For a comprehensive overview of how -replace works, see this answer.

    # Escape the search string.
    $reSearch = [regex]::Escape(@'
    location ~* "^/(888888-localhost/client)(.*)$" {
                proxy_pass https://localhost:32583;
    @')
    
    # Escape the substitution string.
    $substitution = @"
    location ~* "^/(888888-localhost/client)(.*)$" {
                proxy_pass https://localhost:$proxy;
    "@.Replace('$', '$$')
    
    # ...
      ($_ | Get-Content -Raw) -replace $reSearch, $substitution |
        Set-Content -LiteralPath $_.FullName
    # ...
    

    Note the use of both verbatim and expandable here-strings to facilitate declaring the strings.

    As for a potential simplification of your -replace operation:

    • Abraham Zinala points out that ultimately you’re looking to only replace the port number in the matched substring, so you could use a positive look-behind assertion ((?<=...)), as shown in this simplified example:

      $proxy = 8080
      'a https://localhost:80; z' -replace '(?<=https://localhost:)d+', $proxy
      
      • Output is: a https://localhost:8080; z

    Caveat re newlines:

    • The above assumes that your script file uses the same newline format (Windows-format CRLF vs. Unix-format LF) as the input file.

    • If you’re not sure, and you want to match either format, replace the n escape sequence in $reSearch with r?n ($reSearch = $reSearch.Replace('n', 'r?n') and possibly replace the literal newline in $substitution with `r`n or `n, as needed.

    Login or Signup to reply.
  1. One solution would be to use a positive lookbehind to ensure the pattern is matched:

    @"
    location ~* "^/(888888-localhost/client)(.*)$" {
                proxy_pass https://localhost:32583;
    "@  -replace "(?<=/localhost:)d+",'$port'
    
    # In your use-case
    (Get-Content -Path ($Path = 'C:nginxconfnginx.conf')) -replace "(?<=/localhost:)d+",'$port' | 
        Set-Content -Path $Path
    

    Removing the single quotes around $port, or replacing them with double quotes will allow the use of $port as an actual variable.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search