Manipulating XML files with PowerShell is something that we’re having to accomplish more and more internally. Microsoft App-V 5.0 and RES Workspace Manager utilise XML files extensively. Whilst we can manually tweak them, there’s nothing like automating things for consistency and speed!
I have seen a lot of “rip and replace” and “find and replace” script examples, but ensuring that the correct elements/nodes are added in the correct place can be troublesome. The only real option is to utilise the built-in .Net Framework XML objects. Hopefully this post will lay the basis for some more App-V 5.0 focused blogs in the future .
There are lots of forum posts out there that detail snippets of information, but a lot of it is trial and error. As a starting point you might want to read up here first. Reading XML files is one thing, but as the previous article mentions, inserting (multiple) elements can be quite convoluted. Note: I’m using the XmlDocument .Net object here but it is possible to utilise other .Net classes, e.g. XPath and/or XDocument.
Here is the example we’ll use in this post. Apologies; the XML formatting is stripped by the plugin:
<!-- employees.xml --> <employees> <employee id="101"> <name>Frankie Johnny</name> <age>36</age> </employee> <employee id="102"> <name>Elvis Presley</name> <age>79</age> </employee> <employee id="301"> <name>Ella Fitzgerald</name> <age>102</age> </employee> </employees>
Creating XML Elements
If we wish to add a new employee record to the above document, we need to create a new XML element (or node). Firstly we need to load the XML document:
$fileName = “employees.xml”; $xmlDoc = [System.Xml.XmlDocument](Get-Content $fileName);
Now we can create our new element/node, append it to the parent reference and save it:
$newXmlEmployeeElement = $xmlDoc.CreateElement("employee"); $newXmlEmployee = $xmlDoc.employees.AppendChild($newXmlEmployeeElement); $xmlDoc.Save($fileName);
To shorten this we can just use this (see here for more information on the CreateElement method):
$newXmlEmployee = $xmlDoc.employees.AppendChild($xmlDoc.CreateElement("employee")); $xmlDoc.Save($fileName);
If we examine the resulting XML file we’ll find the following (note the new empty element):
<!-- employees.xml --> <employees> <employee id="101"> <name>Frankie Johnny</name> <age>36</age> </employee> <employee id="102"> <name>Elvis Presley</name> <age>79</age> </employee> <employee id="301"> <name>Ella Fitzgerald</name> <age>102</age> </employee> <employee /> </employees>
Adding XML Attributes
To add the ID attribute tag in the XML document, we need to create a new XmlDocument Attribute and then attach it to our newly created element. We can create an XmlDocument attribute on our element with the following code:
$newXmlEmployee = $xmlDoc.employees.AppendChild($xmlDoc.CreateElement("employee")); $newXmlEmployee.SetAttribute(“id”,”111”); $xmlDoc.Save($fileName);
Now our resulting XML file looks like this:
<!-- employees.xml --> <employees> <employee id="101"> <name>Frankie Johnny</name> <age>36</age> </employee> <employee id="102"> <name>Elvis Presley</name> <age>79</age> </employee> <employee id="301"> <name>Ella Fitzgerald</name> <age>102</age> </employee> <employee id="111"> </employees>[/code]
Adding Nested XML Elements
Knowing how to add elements we can simply create our sub elements and attach them to our newly created parent reference:
$newXmlNameElement = $newXmlEmployee.AppendChild($xmlDoc.CreateElement("name")); $newXmlAgeElement = $newXmlEmployee.AppendChild($xmlDoc.CreateElement("age"));
The resulting XML file now looks like:
<!-- employees.xml --> <employees> <employee id="101"> <name>Frankie Johnny</name> <age>36</age> </employee> <employee id="102"> <name>Elvis Presley</name> <age>79</age> </employee> <employee id="301"> <name>Ella Fitzgerald</name> <age>102</age> </employee> <employee id="111"> <name /> <age /> </employee> </employees>
Adding XML Text Nodes
Unbeknownst to me, when you have text within an element tag, i.e. <name>Iain Brighton</name>, this is known as a text node (at least in XDocument speak). This is probably the bit that took longest to work out.
To add the text node we can use the following code:
$newXmlNameElement = $newXmlEmployee.AppendChild($xmlDoc.CreateElement("name")); $newXmlNameTextNode = $newXmlNameElement.AppendChild($xmlDoc.CreateTextNode("Iain Brighton")); $newXmlAgeElement = $newXmlEmployee.AppendChild($xmlDoc.CreateElement("age")); $newXmlAgeTextNode = $newXmlAgeElement.AppendChild($xmlDoc.CreateTextNode("37"));
Et voilà!
<!-- employees.xml --> <employees> <employee id="101"> <name>Frankie Johnny</name> <age>36</age> </employee> <employee id="102"> <name>Elvis Presley</name> <age>79</age> </employee> <employee id="301"> <name>Ella Fitzgerald</name> <age>102</age> </employee> <employee id="111"> <name>Iain Brighton</name> <age>37</age> </employee> </employees>
Full PowerShell Code Snippet
Here is the full code listing:
$fileName = “employees.xml”; $xmlDoc = [System.Xml.XmlDocument](Get-Content $fileName); $newXmlEmployee = $xmlDoc.employees.AppendChild($xmlDoc.CreateElement("employee")); $newXmlEmployee.SetAttribute("id","111"); $newXmlNameElement = $newXmlEmployee.AppendChild($xmlDoc.CreateElement("name")); $newXmlNameTextNode = $newXmlNameElement.AppendChild($xmlDoc.CreateTextNode("Iain Brighton")); $newXmlAgeElement = $newXmlEmployee.AppendChild($xmlDoc.CreateElement("age")); $newXmlAgeTextNode = $newXmlAgeElement.AppendChild($xmlDoc.CreateTextNode("37")); $xmlDoc.Save($fileName);