Private/ConvertFrom-XML.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
<#
.COPYRIGHT Copyright (c) ECIT Solutions AS. All rights reserved. Licensed under the MIT license. See https://github.com/ecitsolutions/Autotask/blob/master/LICENSE.md for license information. #> Function ConvertFrom-XML { <# .SYNOPSIS This function converts an array of XML elements to a custom psobject for easier parsing and coding. .DESCRIPTION The function an array of XML elements and recursively converts each element to a custom PowerShell object. Each XML property is converted to an object property with a value of datetime, double, integer or string. .INPUTS [System.XML.Xmlelement []] .OUTPUTS [System.Object[]] .EXAMPLE $element | ConvertFrom-XML Converts variable $element with must contain 1 or more Xml.Xmlelements to custom PSobjects with the same content. .NOTES NAME: ConvertFrom-XML #> [cmdletbinding()] Param ( [Parameter( Mandatory = $true, ValueFromPipeLine = $true, ParameterSetName = 'Input_Object' )] [Xml.Xmlelement[]] $InputObject ) begin { # Enable modern -Debug behavior if ($PSCmdlet.MyInvocation.BoundParameters['Debug'].IsPresent) { $DebugPreference = 'Continue' } Write-Debug ('{0}: Begin of function' -F $MyInvocation.MyCommand.Name) $result = @() # Set up TimeZone offset handling $timezoneid = if ($IsMacOS -or $IsLinux) { 'America/New_York' } else { 'Eastern Standard Time' } $EST = [System.Timezoneinfo]::FindSystemTimeZoneById($timezoneid) } process { foreach ($element in $InputObject) { # Get properties $properties = $element | Get-Member -MemberType property # Create a new, empty object $object = New-Object -TypeName PSObject # Loop through all properties and add a member for each foreach ($property in $properties) { # We are accessing property values by dynamic naming. It is a lot easier # to reference dynamic property names with a string variable $propertyName = $property.Name # Extract/create a value based on the property definition string switch -Wildcard ($property.Definition) { # Most properties are returned as strings. We will use a few tests to # try to recognise other value types 'string*' { # Test if it is a date first if ($element.$propertyName -match '^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))') { # Convert to a Datetime object in two steps to explicitly set datetime Kind to unspecified # $d = [DateTime]$element.$propertyName # $dateTime = New-Object DateTime $d.Year, $d.Month, $d.Day, $d.Hour, $d.Minute, $d.Second, ([DateTimeKind]::Unspecified) [DateTime]$dateTime = $element.$propertyName # Add timezone difference $value = [TimeZoneInfo]::ConvertTime($dateTime, [TimeZoneInfo]::Local, $EST) } else { # This isn't a date. We'll use a regex to avoid turning integers into doubles switch -regex ($element.$propertyName) { '^\d+\.\d{4}$' { [Double]$double = $element.$propertyName $value = $double } '^\d+$' { [Int64]$Integer = $element.$propertyName $value = $Integer } Default { $value = $element.$propertyName } } } Add-Member -InputObject $object -MemberType Noteproperty -Name $propertyName -Value $value } # For properties that are XML elements; recurse 'System.Xml.Xmlelement*' { # A bit of recursive magic here... $value = $element.$propertyName | ConvertFrom-XML Add-Member -InputObject $object -MemberType Noteproperty -Name $propertyName -Value $value } # Arrays. Loop through elements and perform recursive magic 'System.Object*' { $value = @() foreach ($Item in $element.$propertyName) { $value += $Item | ConvertFrom-XML } Add-Member -InputObject $object -MemberType Noteproperty -Name $propertyName -Value $value } } } } $result += $object } end { Return $result } } |