0

I have an config file similar to below:

<?xml version="1.0" encoding="utf-8"?>
<configuration>  
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.1.3" newVersion="4.1.1.3" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
      </dependentAssembly>      
    </assemblyBinding>
  </runtime>
  <appSettings>
    <add key="key1" value="Value1" />
    <add key="key2" value="Value12" />
    <add key="key3" value="Value3" />   
  </appSettings>
</configuration>

Now through PowerShell I'm trying to replace some values, say for example Value1. For that I have written the below script :

$original_file = "C:\test.xml"
(Get-Content $original_file) | Foreach-Object {
     $_ -replace 'Value1', 'Newvalue'
    } | Set-Content $original_file

So what it does it replace all Value1 strings with Newvalue string. The problem I'm facing here is it changing all the values whereever Value1 is found, like this.

  <appSettings>
    <add key="key1" value="Newvalue" />
    <add key="key2" value="Newvalue2" /> --- this is not supposed to happen
    <add key="key3" value="Value3" />  
</appSettings>

And also in reality, I actual values are very long strings.

So is there any way I can find the key and change its respective value? Like find Key1 and change its value to NewValue.

halfer
  • 19,824
  • 17
  • 99
  • 186
CrazyCoder
  • 2,194
  • 10
  • 44
  • 91
  • if your XML is loaded into `$InStuff`, then this will address the array that has the `add` items in it ... `$InStuff.configuration.appSettings.add.Where({$_.Key -eq 'key1'})` ... and get the array item that has the XmlElement with a `key1` in it. – Lee_Dailey Nov 20 '18 at 05:19

1 Answers1

3

Don't use regex against structured markup - use XPath!

# Load the xml document
$filename = 'C:\test.xml'
$xmlDoc = New-Object xml
$xmlDoc.Load($filename)

# Select all applicable nodes
$nodes = $xmlDoc.SelectNodes('//appSettings/add[@key="key1"]')

# In each node, replace the value `Value1` with `NewValue`
foreach($node in $nodes){
  $node.value = $node.value.Replace('Value1','NewValue')
}

# Save the document
$xmlDoc.Save($filename)

The XPath expression //appSettings/add[@key="key1"] will select any add node which has an attribute named key with the value key1 and whose parent is an appSettings node.

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • thanks for replying. This has solved my issue. One issue what I'm facing here is I'm changing the values continuously for every 3 hrs. So If I change the value first time Value1 to NewValue , Second time this doesn't work because there is no Value1 anymore. So is there any way I can directly replace the value for key1 without mentioning 'Value1' anywhere like in this $node.value.Replace('Value1','NewValue') ? – CrazyCoder Nov 20 '18 at 10:37
  • I understand that this requirement was not there in the original question , if you can help me that would be helpful. – CrazyCoder Nov 20 '18 at 10:38
  • @CrazyCoder just set `$node.value` to whatever it needs to be instead: `$node.Value = "NewValue"` – Mathias R. Jessen Nov 20 '18 at 10:57