Updating and Writing XML Files with PowerShell

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 Open-mouthed smile.

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);