Private/ConvertTo-TLNormalizedObject.ps1
|
function ConvertTo-TLNormalizedObject { <# .SYNOPSIS Normalizes a data tree for deterministic diffing. .DESCRIPTION - removes volatile properties (case-insensitive) - orders object properties alphabetically - sorts arrays deterministically (by id/domain/skuPartNumber for object arrays, by value for scalar arrays) #> [CmdletBinding()] param( [AllowNull()] [object]$InputObject, [string[]]$VolatileProperty = @() ) if ($null -eq $InputObject) { return $null } if ($InputObject -is [string] -or $InputObject.GetType().IsValueType) { return $InputObject } if ($InputObject -is [System.Collections.IDictionary]) { $normalized = [ordered]@{} foreach ($key in (@($InputObject.Keys) | Sort-Object)) { if ($VolatileProperty -contains [string]$key) { continue } $normalized[[string]$key] = ConvertTo-TLNormalizedObject -InputObject $InputObject[$key] -VolatileProperty $VolatileProperty } return $normalized } if ($InputObject -is [System.Collections.IEnumerable]) { $items = @(foreach ($item in $InputObject) { ConvertTo-TLNormalizedObject -InputObject $item -VolatileProperty $VolatileProperty }) if ($items.Count -gt 1) { $first = $items[0] if ($first -is [System.Collections.IDictionary]) { $sortKey = $null foreach ($candidate in @('id', 'domain', 'skuPartNumber', 'displayName')) { if ($first.Contains($candidate)) { $sortKey = $candidate; break } } if ($sortKey) { $items = @($items | Sort-Object -Property @{ Expression = { [string]$_[$sortKey] } }) } } else { $items = @($items | Sort-Object -Property @{ Expression = { [string]$_ } }) } } return , $items } # PSCustomObject $normalized = [ordered]@{} foreach ($property in ($InputObject.PSObject.Properties | Sort-Object -Property Name)) { if ($VolatileProperty -contains $property.Name) { continue } $normalized[$property.Name] = ConvertTo-TLNormalizedObject -InputObject $property.Value -VolatileProperty $VolatileProperty } return $normalized } |