Author Posts

May 9, 2017 at 3:14 pm

I'm trying to write a script to replace a node on a single XML file. My XML example can be seen here:

I'm assuming I need to first figure out how to remove the existing node, then add the new one... But I'm stuck on the removal. This is what I currently have:

$path = "C:\Testing\File.xml"

[xml]$servicefactoryconfig = gc $path

$AuditOut = $servicefactoryconfig.SelectSingleNode("factory.map.add.Key[.='Audit']")
$AuditOut.parentnode.removeall()
$servicefactoryconfig.save($path)

When I run this, Notepad++ is telling me the file has been edited, but there is no difference in the file. I am also seeing this error:

You cannot call a method on a null-valued expression.
At line:14 char:1
+ $AuditOut.parentnode.removeall()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

Anyone have any suggestions? Is there an easier way to just replace this instead of removing, saving, and adding?

May 9, 2017 at 4:04 pm

You can try something like this:

#original XML content
[xml]$myXml = @"


  
    
      
    
  

"@

#Build an object with your values
$config = @()
$config += [pscustomobject]@{name="baseUrl";class="string";value="http://hostname/Website"}
$config += [pscustomobject]@{name="servicePath";class="string";value="Audit/AuditASMX.asmx"}
$config += [pscustomobject]@{name="timeout";class="int";value="120"}
$config += [pscustomobject]@{name="policy";class="string";value="AuditServicePolicy"}

#Select Node
$element = $myXML.factory.map.add
#Remove Node
$element.RemoveChild($element.FirstChild)

#$element.SelectSingleNode()
foreach ($item in $config) {
    #
    $child = $myXML.CreateElement("parameter")
    
    #Name
    $addName = $myXML.CreateAttribute("name")
    $addName.Value = $item.Name
    $child.Attributes.Append($addName)

    #Class
    $addClass = $myXML.CreateAttribute("Class")
    $addClass.Value = $item.Class
    $child.Attributes.Append($addClass)

    #Value
    $addValue = $myXML.CreateAttribute("Value")
    $addValue.Value = $item.Value
    $child.Attributes.Append($addValue)
    
    #Append to Add
    $element.AppendChild($child)
}

$myXML.Save(("{0}\myxml.xml" -f [environment]::GetFolderPath("Desktop")))

May 9, 2017 at 4:07 pm

I think I found the problem. Your XPath was not valid and yes the previous node needs to be removed.
What do you think about the following?

May 9, 2017 at 4:21 pm

Thanks Rob – a couple of questions. Admitting this is still fairly new to me, but I'm looking this over trying to figure out where the file path to my xml file should be going in here...

Also, I probably should have mentioned this, but there are many "add" nodes in this file, and this particular node can be in any location on the file. From the look of the code it's trying to remove the "first" add node. So it needs to be specific to the one that has the name "audit." So would I format that:

$element.RemoveChild($element.add | where-object key -eq "audit")

?

May 9, 2017 at 4:30 pm

You sir, are a rock star! Worked like a charm! THANK YOU!!!

May 9, 2017 at 5:28 pm

Daniel showed an example using xpath to specify a certain element, this is more dot notation. Yes, you can specifically reference a child using a where clause like such:

$element.RemoveChild(($element.parameter | Where{$_.value -like "*audit*"}))

May 9, 2017 at 10:03 pm

Daniel – upon further investigation, a number of my existing "add" nodes are missing the closing tag after I run the file. And they don't seem to be related in any way to what we're adding or removing. It's like the entire node is still there, it's just missing the /add at the end. Any idea what might cause that?

Edit: I just looked over the file. It appears it removed the closing tag on any add node that does not have a child node. If there is a child node, the closing tag was not removed.

May 10, 2017 at 4:24 pm

Upon further investigation, this appears to be working... I had started by making a backup of the file and changed the file type to *.original instead of *.xml. I then compared the changed file with the original... Apparently CompareIt doesn't like to display XML files properly. As soon as I changed the *.original to *.xml and compared 2 xml files, both files were identical.

Thanks again for the help!