internal/ConvertTo-OrderedDictionary.ps1
|
function ConvertTo-OrderedDictionary { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] [AllowNull()] $InputObject ) begin { function _Get-OrderedDictionarySortKey { param($Item) if ($null -eq $Item) { return '' } if ( $Item.GetType().IsPrimitive -or $Item -is [string] -or $Item -is [decimal] -or $Item -is [datetime] -or $Item -is [datetimeoffset] -or $Item -is [timespan] -or $Item -is [guid] -or $Item -is [enum] ) { return [string]$Item } $keyParts = [System.Collections.Generic.List[string]]::new() if ($Item -is [System.Collections.IDictionary]) { foreach ($key in ($Item.Keys | Sort-Object { [string]$_ })) { if ($keyParts.Count -ge 3) { break } $val = $Item[$key] if ( $null -eq $val -or $val.GetType().IsPrimitive -or $val -is [string] -or $val -is [decimal] -or $val -is [datetime] -or $val -is [datetimeoffset] -or $val -is [timespan] -or $val -is [guid] -or $val -is [enum] ) { $keyParts.Add([string]$val) } } } else { try { $props = @( $Item.PSObject.Properties | Where-Object { $_.IsGettable -and $_.MemberType -in [System.Management.Automation.PSMemberTypes]::NoteProperty, [System.Management.Automation.PSMemberTypes]::Property } | Sort-Object Name ) foreach ($prop in $props) { if ($keyParts.Count -ge 3) { break } try { $val = $prop.Value } catch { continue } if ( $null -eq $val -or $val.GetType().IsPrimitive -or $val -is [string] -or $val -is [decimal] -or $val -is [datetime] -or $val -is [datetimeoffset] -or $val -is [timespan] -or $val -is [guid] -or $val -is [enum] ) { $keyParts.Add([string]$val) } } } catch { } } return $keyParts -join "`0" } } process { if ($null -eq $InputObject) { return $null } if ( $InputObject.GetType().IsPrimitive -or $InputObject -is [string] -or $InputObject -is [decimal] -or $InputObject -is [datetime] -or $InputObject -is [datetimeoffset] -or $InputObject -is [timespan] -or $InputObject -is [guid] -or $InputObject -is [enum] ) { return $InputObject } if ($InputObject -is [System.Collections.IDictionary]) { $outputObject = [ordered]@{} $sortedKeys = [System.Collections.Generic.List[Object]]::new() foreach ($key in $InputObject.Keys) { $insertAt = $sortedKeys.Count for ($i = 0; $i -lt $sortedKeys.Count; $i++) { if ([string]::CompareOrdinal([string]$key, [string]$sortedKeys[$i]) -lt 0) { $insertAt = $i break } } $sortedKeys.Insert($insertAt, $key) } foreach ($key in $sortedKeys) { $outputObject[$key] = ConvertTo-OrderedDictionary -InputObject $InputObject[$key] } return $outputObject } if ($InputObject -is [System.Array]) { $outputArray = @() foreach ($item in ($InputObject | Sort-Object { _Get-OrderedDictionarySortKey $_ })) { $outputArray += ConvertTo-OrderedDictionary -InputObject $item } return $outputArray } if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { $outputArray = @() foreach ($item in ($InputObject | Sort-Object { _Get-OrderedDictionarySortKey $_ })) { $outputArray += ConvertTo-OrderedDictionary -InputObject $item } return $outputArray } $properties = @( $InputObject.PSObject.Properties | Where-Object { $_.MemberType -in [System.Management.Automation.PSMemberTypes]::NoteProperty, [System.Management.Automation.PSMemberTypes]::Property -and $_.IsGettable } ) if ($properties.Count -gt 0) { $outputObject = [ordered]@{} $sortedProperties = [System.Collections.Generic.List[Object]]::new() foreach ($property in $properties) { $insertAt = $sortedProperties.Count for ($i = 0; $i -lt $sortedProperties.Count; $i++) { if ([string]::CompareOrdinal([string]$property.Name, [string]$sortedProperties[$i].Name) -lt 0) { $insertAt = $i break } } $sortedProperties.Insert($insertAt, $property) } foreach ($property in $sortedProperties) { try { $propertyValue = $property.Value } catch { continue } $outputObject[$property.Name] = ConvertTo-OrderedDictionary -InputObject $propertyValue } return [PSCustomObject]$outputObject } return $InputObject } } |