1

I've got the following PowerShell script (I'm using Powershell v5.1), which I took and adapted mostly from this previous post: Replace multiline text in a file using Powershell without using Regex:

$oldCode =  @"
        <httpProtocol>
            <customHeaders>
                <clear />
            </customHeaders>
            <redirectHeaders>
                <clear />
            </redirectHeaders>
        </httpProtocol>
"@

$newCode = @"
        <httpProtocol>
            <customHeaders>
                <add name="X-Frame-Options" VALUE="SAMEORIGIN"></add>
            </customHeaders>
            <redirectHeaders>
                <clear />
            </redirectHeaders>
        </httpProtocol>
"@

$Path = "c:\Windows\System32\inetsrv\config\applicationHost.config"
$Content = (Get-Content $Path -Raw).replace($oldCode,$newCode)

Set-Content -Path $Path -Value $Content -Verbose

This doesn't replace the $oldCode, however. I've used Write-Output to check the $Content variable and it isn't replacing the string, so I'm assuming it's a problem matching the string or with the replace command itself, rather than a problem with the Set-Content command.

Any ideas on how to get this working?

Chris Davis
  • 11
  • 2
  • 5
  • `Get-Content`, when used on a text file, returns the content as an array of strings, where each entry in the array is one line of the file. However, a heredoc (which is what you're using for `$oldcode` and `$newcode`) is a simple string, not a string array, so the `.replace()` is failing. – Jeff Zeitlin Oct 24 '17 at 11:39
  • From the previous post I linked, I thought the `-Raw` parameter was equivalent to `Out-String`. If I add a `$Content.GetType()` it tells me it's a string rather than an array (Removing the `-Raw`) reverts it to a System.Array object. – Chris Davis Oct 24 '17 at 12:43
  • I missed the `-Raw`. The linked post is using the `-replace` operator, rather than the `.replace()` method. The two actually work differently; one of them does use regexp (but I don't recall which one). Try replacing `.replace($oldcode,$newcode)` with `-replace $oldcode,$newcode`. – Jeff Zeitlin Oct 24 '17 at 12:55
  • 1
    `-replace` uses regular expressions, `.Replace()` does not. With that said, you may want to use a proper [XML](https://stackoverflow.com/a/45869062/1630171) [parser](https://stackoverflow.com/a/26606882/1630171) rather than string replacements. – Ansgar Wiechers Oct 24 '17 at 13:32
  • You're right, I wasn't even aware of the XML parsing in PowerShell. I can already see there's some Append and Replace dot notation for it. I'll take a look. Thanks. – Chris Davis Oct 24 '17 at 14:26

1 Answers1

0

So in the end, I used the below. This isn't the only option you could also use the API to construct your elements.

$xmlPath = "c:\windows\system32\inetsrv\config\applicationHost.config"

[xml]$xml = Get-Content -Path $xmlPath

[xml]$xFrameXml = @"
            <customHeaders>
                <add name="X-Frame-Options" value="SAMEORIGIN" />
            </customHeaders>
"@

foreach($node in $xml.SelectNodes('/configuration/system.webServer/httpProtocol/customHeaders')){
    $node.ParentNode.AppendChild($xml.ImportNode($xFrameXml.customHeaders, $true));
    $node.ParentNode.RemoveChild($node);

}
$xml.Save($xmlPath);

You may also just be able to use a .ReplaceChild but I haven't found the correct syntax for that, so if anybody does it would potentially be cleaner.

Thanks to Ansgar for pointing me in the right direction.

Chris Davis
  • 11
  • 2
  • 5
  • That @"One line/Two lines"@ solution is called a here-string, and it is a fine way of doing things, but bear in mind that it does not work with PowerShell 2. If you are looking to write fully compatible code, this method is not compatible alas. – seagull Jul 20 '20 at 12:23