Prof. Powershell
XML Marks the Spot Part 3: Nested Objects
In the final column discussing XML conversion in PowerShell, Jeffrey walks you through converting nested objects to XML.
- By Jeffery Hicks
- 09/16/2013
In the previous lessons we explored converting PowerShell data into a "traditional" XML document. In other words, an XML document that you could use outside of PowerShell. In the last lesson I created a few XML documents using ConvertTo-XML including nested objects. I'll use them for my demonstration.
If you look at cmdlet help you'll discover there is no ConvertFrom-XML cmdlet. Instead you'll get the contents of the XML file, which is just text after all, and tell PowerShell to treat it as an XML document.
PS C:\> [xml]$os = get-content C:\work\myos2.xml
PS C:\> $os
xml Objects
--- -------
version="1.0" Objects
The variable $os is now an XML document. I'm not back to where I was when I first converted the Win32_OperatingSystem class to an XML document. I could navigate the document as I showed you previously.
PS C:\> $os.objects
Object
------
Object
But there's actually much more than is presented on the screen as you can see in figure 1.
You can use any of these properties.
PS C:\> $os.objects.object.ChildNodes
When working with XML documents like this, there is an assumption that you know the data. While you can explore an unknown XML file, the more you know what sort of data is in your XML file, the easier (relatively speaking) it is to work with.
PS C:\> $os.objects.object.ChildNodes | where {$_.InnerText} | Select Name,InnerText
As figure 3 shows I'm displaying all properties that have a value.
Instead of filtering on #text, which is awkward because of the # symbol, I'm using the InnerText property which should give me the same value.
Or perhaps it would be easier to turn this back into a PowerShell object. Unfortunately, this is not a trivial task, especially if you have a nested hierarchy of objects.
$file = "C:\work\myos2.xml"
[xml]$xml = get-content -Path $file
$n = foreach ($obj in $xml.Objects.Object) {
$obj.Property | foreach -begin {
$h=@{}
} -process {
if ($_.property) {
#nested properties
$value = $_.property | Select Name,InnerText,Type
}
else {
$value = $_.InnerText
}
$h.add($_.name,$value)
} -end {
[pscustomobject]$h
}
} #foreach $obj
$n
This code enumerates the properties of each node and creates a hash table of each. In this version, everything is a string object, although the nested properties will indicate an object type. You can see my result in figure 4 for the operating system XML file.
If the XML file has a collection of objects, such as services, then $n will be a collection of converted service objects. All I need to do is modify the path of the XML file as I show in figure 5.
If all I'm doing is analyzing values, this might be all that I need. Of course, the easier way to recreate objects in PowerShell is to the cliXML cmdlets. But the concepts I've shown you here should work with any type of XML file, even those created outside of PowerShell. I'm not saying it will be easy but it can done.
Building such a tool is beyond the scope of what I can cover in this column. If you run into problems working with XML documents in PowerShell, I encourage you to use the forums at PowerShell.org. You might also keep an eye on my blog as I'll post any XML-related tools I create on that site.
About the Author
Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.