1

I have a file that looks something like this:

<Parameter Name="WebImage" Value="web:${BuildNumber}" />
<Parameter Name="ApiImage" Value="api:${BuildNumber}" />

I'd like to replace any occurrence of ${xxx} in the file with the environment variable xxx. This file could refer to any number of environment variables; they are not known ahead of time.

I'm trying something like:

(Get-Content .\Cloud.xml) -replace "\$\{(\w+)\}", "$([Environment]::GetEnvironmentVariable('$1'))"

However, I just get:

<Parameter Name="WebImage" Value="web:" />
<Parameter Name="ApiImage" Value="api:" />

The GetEnvironmentVariable call works, since I can do:

(Get-Content .\Cloud.xml) -replace "\$\{(\w+)\}", "$([Environment]::GetEnvironmentVariable('BuildNumber'))"

And that works. The $1 call works since I can do:

(Get-Content .\Cloud.xml) -replace "\$\{(\w+)\}", '$1'

And I'll get:

<Parameter Name="WebImage" Value="web:BuildNumber" />
<Parameter Name="ApiImage" Value="api:BuildNumber" />

However, I can't seem to combine the two. I think it's something to do with the order of how functions are resolved.

Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
  • PowerShell expands `[Environment]::GetEnvironmentVariable()` long before the regular expression engine gets to see the replacement string and could fill in `$1`. – Ansgar Wiechers Oct 05 '18 at 21:25
  • @AnsgarWiechers Yea that's kinda what I figured. I need some way to build an expression by hand and then resolve it. Kinda like an `eval()` – Mike Christensen Oct 05 '18 at 21:32
  • Please take a look at my answer to the duplicate question linked at the top of your question. – Ansgar Wiechers Oct 05 '18 at 21:34
  • @AnsgarWiechers Yup, basically that evaluates any expression in the entire file. I'd have to change how I represent tokens, but it would work. Thanks! – Mike Christensen Oct 05 '18 at 21:39
  • You could also parse the XML and apply the string expansion only to a particular node or attribute value (basically a combination of the first and last code snippet from my answer). – Ansgar Wiechers Oct 05 '18 at 21:41
  • Another option might be a replacement using a [callback function](https://stackoverflow.com/a/31211494/1630171). – Ansgar Wiechers Oct 05 '18 at 21:46

1 Answers1

1

Try to use $Matches auto variable.

(Get-Content .\Cloud.xml) | 
    ForEach-Object { 
        if ($_ -match "\$\{((\w+))\}")
        {
            $_ -replace "\$\{(\w+)\}",$([Environment]::GetEnvironmentVariable($Matches[1]))
        }
        else
        {
            $_
        }
    }
Kirill Pashkov
  • 3,118
  • 1
  • 15
  • 20
  • This is a solid answer because it lets me express my own token format and would work with any file (not just XML). I have a feeling it could be made simpler though.. – Mike Christensen Oct 05 '18 at 21:42
  • @MikeChristensen, I have placed an extra `()` for match condition to make groups and now it comes a little shorter and simpler too. – Kirill Pashkov Oct 05 '18 at 21:47