Last Update: Sep 04, 2024 | Published: Jan 12, 2017
In a previous article, I guided you through using the Export-Clixml and Import-Clixml cmdlets to serialize and deserialize data from a PowerShell expression. However, as I demonstrated in earlier articles in this series, you could also use ConvertTo-XML. This cmdlet will generate XML that is more compatible with non-PowerShell applications. But what if you also wanted to bring the data back to life in PowerShell? There is no ConvertFrom-XML cmdlet, at least as of today, so it will take a little extra work.
Here is an XML file I created in a previous article from a Get-Service command.
I converted the result to XML and saved it to a file. To bring this back, I need to convert it back into an XML document, which is actually quite easy.
[xml]$in = Get-Content C:workwu2.xml
The [xml] tells PowerShell, “treat the content as an XML document.” Which it now becomes.
This should look familiar. It is pretty easy to “walk” the object tree.
The object properties are also easily discovered.
The tricky part is enumerating all of the XML nodes and writing them as objects to the pipeline.
$data = $in.Objects.Object | foreach { #initialize an empty hash table $hash = @{} #enumerate each property and add it to the hashtable foreach ($prop in $_.property) { $hash.Add($prop.name,$prop.'#text') } #Write the hashtable to the pipeline as a custom object [pscustomobject]$hash }
The results seem ok at first.
But look at this with Get-Member.
By default, everything will be treated as a string or a generic object. This can pose challenges should you want to filter or sort. The clixml cmdlets automatically know how to preserve type. To do that here requires a little extra work.
Fortunately, when I converted the Get-Service command, the result saved property type, which you can see in the screenshot above. This means I can modify my code and add each entry to the hashtable as the necessary type.
$data2 = $in.Objects.Object | foreach { #initialize an empty hash table $hash = @{} #enumerate each property and add it to the hashtable foreach ($prop in $_.property) { $hash.Add($prop.name,$prop.'#text' -as $prop.Type) } #Write the hashtable to the pipeline as a custom object [pscustomobject]$hash }
Unfortunately, this may not always be 100 percent successful.
But almost everything else is now properly typed.
But the overall display shows all properties by default. It doesn’t look like a service object. That’s because the type name is PSCustomObject and what we really want is this:
Your PowerShell expression should have generated the same type of object for all items. You can’t convert each custom object to this type, but you can insert a new type name.
$theType = $in.Objects.Object[0].Type $data3 = $in.Objects.Object | foreach { #initialize an empty hash table $hash = @{} #enumerate each property and add it to the hashtable foreach ($prop in $_.property) { $hash.Add($prop.name,$prop.'#text' -as $prop.Type) } #Turn the hashtable into custom object $obj = [pscustomobject]$hash #insert a new typename $obj.psobject.typenames.insert(0,$theType) #write the object to the pipeline $obj }
Now look at the results:
Or you can take a more generic approach where you don’t care what the node names are called but you know there is a Type attribute.
[xml]$in = Get-Content C:workwu3.xml #skip XML declaration node $nodes = $in.ChildNodes | Select -Skip 1 foreach ($node in $nodes.ChildNodes) { $hash = @{} #enumerate each property and add it to the hashtable #this assumes you don't know or care what the node #might be called foreach ($item in $node.($node.firstchild.LocalName)) { Try { $hash.Add($item.name,$item.'#text' -as $item.Type) } Catch { #ignore conversion errors } } #Turn the hashtable into custom object $obj = [pscustomobject]$hash #insert a new typename $obj.psobject.typenames.insert(0,$node.type) #write the object to the pipeline $obj }
This example uses properties of the XML document itself to enumerate itself.
The main takeaway from all of this is that you need to know in advance what your XML file looks like so that you can write a script or function to properly import it into PowerShell. If your XML file doesn’t include type information, and it matters to you, then you’ll have to take other steps to convert those items to the proper type.
If you have anything more complex, then bringing it into PowerShell will take even more effort. But I’ll try to guide you through that process next time.