ojdo
ojdo

Reputation: 8900

How to escape dollar and curly braces for replacement operators in Powershell

Say I have an XML-based template string in which I have to replace self-made template markers:

 $template = '<Foo Name="${BAZ}">'

I would like to replace the literal ${BAZ} with a value. I thought using the case-sensitive -creplace operator would be a good idea. As givens, I have both the bare parameter name (BAZ) without the additional adornment (${ }) and its value (42):

 $param = 'BAZ'
 $value = 42

So I first derive my replacement string using -f to mix the parameter name with its "markup", while carefully escaping the literal { and } within the format string:

 $needle = '${{{0}}}' -f $param 
 # ${BAZ}
 # at least when printed...

Now to the final act:

 $template -creplace $needle, $value
 # <Foo Name="${BAZ}">
 # so $needle does not seem to match the string '${BAZ}'

I seem to have missed (or overcompensated) for some escaping somewhere in between... can somebody pull me off the ice here? (I have tried many combinations of backspaces, backticks, single- and double-quoted strings. And just for context: in my real script, $template is a large multi-line string via $template = Get-Content "template-file.xml", which I hope is not the root source.)


Edit: I have found a working solution after some more hunting: by ditching -creplace in favour of .net's Replace() method, the above $needle matches the template:

 $template.Replace($needle, $value)
 # <Foo Name="42"/>

So I would be glad about any answer that sheds some light on why -creplace does not cooperate, what I could do to make it.

Upvotes: 1

Views: 840

Answers (2)

Manuel Batsching
Manuel Batsching

Reputation: 3596

-replace is an operator that replaces a regular expression.-creplace just makes this regular expression case sensitive. The problem you are running into is the regular expression itself, as certain characters have a special role in regex.

What you want to do, is to escape such characters:

 $template -replace [regex]::escape($needle), $value

The escaped pattern will look like this: \$\{BAZ}

Upvotes: 1

TobyU
TobyU

Reputation: 3918

In this case [regex]::escape() should do the trick.

 $template = '<Foo Name="${BAZ}">'
 $template -match [regex]::escape('${BAZ}')
 $Matches

Output:

Name                           Value 
----                           ----- 
0                              ${BAZ}

Upvotes: 2

Related Questions