function ConvertFrom-Xml { <# .SYNOPSIS Used to convert an object from Xml to a hashtable (think `$xml | ConvertFrom-Xml | ConvertTo-Json`) .PARAMETER Node Some XML node to be passed in #> param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [System.Xml.XmlNode]$Node ) if ($node.DocumentElement) { $Node = $Node.DocumentElement } $name = $Node.Name $orderedHashtable = [Ordered]@{ $name = [Ordered]@{} } foreach($attribute in $Node.Attributes) { $attributeName = $attribute.Name $orderedHashtable.$name.$attributeName = $attribute.FirstChild.InnerText } foreach($child in $Node.ChildNodes) { $childName = $child.Name $value = $null if ($child -is [System.Xml.XmlComment]) { $childName = "xmlComments" $value = $child.OuterXml } elseif ($child -is [System.Xml.XmlText]) { $value = $child.InnerText $childName = $name } else { $value = (ConvertFrom-Xml $child).$childName # this hackery lets an object like text become elem: { attr = x; elem = val; } but val becomes elem: val # simple hack is best hack # Thanks I hate it too if (($null -ne $value.$childName) -and ($value.Keys.Count -eq 1)) { $value = $value.$childName } else { $value = [PSCustomObject]$value } } if ($null -eq $value) { continue } if ($null -eq $orderedHashtable.$name.$childName) { $orderedHashtable.$name.$childName = $value } else { # the key already exists, so we need to be using an array for the values if (!($orderedHashtable.$name.$childName -is [Array])) { $current = @($orderedHashtable.$name.$childName) $orderedHashtable.$name.$childName = $current } $orderedHashtable.$name.$childName += $value } } return [PSCustomObject]$orderedHashtable }