Simple XML output of a data object

I am doing some data collection using PowerShell and the output needs to be a simple XML document string.

The built in cmdlets do a great job when persisting data, but they produce some fairly complicated XML that provides more detail on object types than I can use.

Here is a single function to take a PSObject based data object and turn it into XML. I have also included a test function to show an example of building the data object.

 
Function Convert-CustomObjectToXml {
<#
.SYNOPSIS
 
Outputs a human readable simple text XML representation of a simple PS object.
 
.PARAMETER object
 
The input object to inspect and dump.
 
.PARAMETER depth
 
The number of levels deep to dump. Defaults to 1.
 
.PARAMETER rootEl
 
The name of the root element in the document. Defaults to "root"
 
.PARAMETER indentString
 
The string used to indent each level of XML. Defaults to two spaces.
Set to "" to remove indentation.
 
.DESCRIPTION
 
Outputs a human readable simple text XML representation of a simple PS object.
 
A PSObject with member types of NoteProperty will be dumped to XML.  Only
nested PSObjects up to the depth specified will be searched. All other
note properties will be ouput using their strings values.
 
The output consists of node with property names and text nodes containing the
proprty value.
 
#>
	param (
		[PSCustomObject]$object,
		[Int32]$depth = 1,
		[String]$rootEl = "root",
		[String]$indentString = "  ",
		[Int32]$indent = 1,
		[switch]$isRoot = $true
	)
 
	# Output the root element opening tag
	if ($isRoot) {
		"<{0}>" -f $rootEl
	}
 
	# Iterate through all of the note properties in the object.
	foreach ($prop in (Get-Member -InputObject $object -MemberType NoteProperty)) {
		$child = $object.($prop.Name)
 
		# Check if the property is an object and we want to dig into it
		if ($child.GetType().Name -eq "PSCustomObject" -and $depth -gt 1) {
			"{0}<{1}>" -f ($indentString * $indent), $prop.Name
				Convert-CustomObjectToXml $child -isRoot:$false -indent ($indent + 1) -depth ($depth - 1) -indentString $indentString
			"{0}</{1}>" -f ($indentString * $indent), $prop.Name
		}
		else {
			# output the element or elements in the case of an array
			foreach ($element in $child) {
				"{0}<{1}>{2}</{1}>" -f ($indentString * $indent), $prop.Name, $element
			}
		}
	}
 
	# Output the root element closing tag
	if ($isRoot) {
		"</{0}>" -f $rootEl
	}
}
 
Function Test-Convert-CustomObjectToXml {
 
	# Create an example object and then try to dump it to the screen.
	$a = New-Object PSObject
	$a | Add-Member -MemberType NoteProperty -Name "CPU" -Value 4
	$a | Add-Member -MemberType NoteProperty -Name "Memory" -Value 800
	$a | Add-Member -MemberType NoteProperty -Name "NICs" -Value (New-Object PSObject)
	$a.NICs | Add-Member -MemberType NoteProperty -Name "vmnic0" -Value "1000"
	$a.NICs | Add-Member -MemberType NoteProperty -Name "vmnic1" -Value "1000"
	$a.NICs | Add-Member -MemberType NoteProperty -Name "vmnic2" -Value "1000"
	$a.NICs | Add-Member -MemberType NoteProperty -Name "vmnic3" -Value "1000"
	$a | Add-Member -MemberType NoteProperty -Name "VMs" -Value (New-Object PSObject)
	$a.VMs | Add-Member -MemberType NoteProperty -Name "VM" -Value @()
	$a.VMs.VM += "foo"
	$a.VMs.VM += "bar"
	$a.VMs.VM += "bash"
	$a.VMs.VM += "bang"
 
	Convert-CustomObjectToXml $a
 
	Convert-CustomObjectToXml $a -depth 10 -rootEl "config"
}

Some sample output.

<root>
  <CPU>4</CPU>
  <Memory>800</Memory>
  <NICs>@{vmnic0=1000; vmnic1=1000; vmnic2=1000; vmnic3=1000}</NICs>
  <VMs>@{VM=System.Object[]}</VMs>
</root>
<config>
  <CPU>4</CPU>
  <Memory>800</Memory>
  <NICs>
    <vmnic0>1000</vmnic0>
    <vmnic1>1000</vmnic1>
    <vmnic2>1000</vmnic2>
    <vmnic3>1000</vmnic3>
  </NICs>
  <VMs>
    <VM>foo</VM>
    <VM>bar</VM>
    <VM>bash</VM>
    <VM>bang</VM>
  </VMs>
</config>

Comments (3)

  1. Krush

    Can you please explain How to add attribute to a node in the xml?
    Ex: <VM Name="xyz" band

    Regards,
    Krush

  2. Mediaocrity

    This is great. Exactly what I wanted to pull my SQL data into an xml sheet.

    Could you elaborate on how you would export this file? I’ve tried using export-clixml but it’s really messy.

    Also @ Krush you add more nodes like this
    $a | Add-Member -MemberType NoteProperty -Name “customer” -Value (New-Object PSObject)
    $a.customer | Add-Member -MemberType NoteProperty -Name “sourceid” -Value SMC

    This would open a node

    SMC

  3. Florian

    I was looking for an easy way to serialize PSCustomObjects as XML.
    That’s great, thanks!

    Small modification:
    Since Get-Member automatically orders the attributes by name I modified the script to preserve my custom order.

    So instead of…
    foreach ($prop in (Get-Member -InputObject $object -MemberType NoteProperty)) {
    $child = $object.($prop.Name)
    […]
    }

    …I am now using

    $object.PSObject.Properties | % {
    $prop = $_
    $child = $object.($prop.Name)
    […]
    }

    $myObject = New-Object PSCustomObject -Property ([Ordered]@{
    Attribute1 = “123”
    Data = New-Object PSCustomObject -Property ([Ordered]@{
    NestedObjAttribute1 = “1”
    NestedObjAttribute2 = “2”
    })
    })

    $xml = Convert-CustomObjectToXml $myObject -rootEl “Definition”

Leave a Comment

Your email address will not be published.