internal/functions/Confirm-ObjectValueEqualityDeep.ps1
function Confirm-ObjectValueEqualityDeep { [CmdletBinding()] param( [Parameter(Position = 0)] $object1, [Parameter(Position = 1)] $object2 ) if ($object1 -eq $object2) { return $true } else { if ($null -eq $object1) { # $object2 is not $null (always true); swap object 1 and object2, so that $object1 is always not $null $tempObject = $object2 $object2 = $object1 $object1 = $tempObject } $type1 = $object1.GetType() $typeName1 = $type1.Name $type2 = $null $typeName2 = "null" if ($null -ne $object2) { $type2 = $object2.GetType() $typeName2 = $type2.Name } if ($typeName1 -in @( "Object[]", "ArrayList") -or $typeName2 -in @( "Object[]", "ArrayList")) { if ($null -eq $object2) { return $object1.Count -eq 0 } else { if ($typeName1 -notin @( "Object[]", "ArrayList")) { # convert single element $object1 into an array $object1 = @( $object1 ) } if ($typeName2 -notin @( "Object[]", "ArrayList")) { # convert single element $object2 into an array $object2 = @( $object2 ) } # both objects are now of type array or ArrayList if ($object1.Count -ne $object2.Count) { return $false } else { # iterate and recurse $object2List = [System.Collections.ArrayList]::new($object2) foreach ($item1 in $object1) { $foundMatch = $false for ($i = 0; $i -lt $object2List.Count; $i++) { $item2 = $object2List[$i] if ($item1 -eq $item2 -or (Confirm-ObjectValueEqualityDeep $item1 $item2)) { $foundMatch = $true $null = $object2List.RemoveAt($i) break } } if (!$foundMatch) { return $false } } return $true } } } elseif ($typeName1 -eq "DateTime" -or $typeName1 -eq "DateTime") { $dateString1 = $object1 if ($typeName1 -eq "DateTime") { $dateString1 = $object1.ToString("yyyy-MM-dd") } $dateString2 = $object2 if ($typeName2 -eq "DateTime") { $dateString2 = $object2.ToString("yyyy-MM-dd") } return $dateString1 -eq $dateString2 } elseif ($typeName1 -eq "String" -or $typeName2 -eq "String") { if ($typeName1 -ne "String") { $object1 = $object1.ToString() } if ($null -eq $object2) { $object2 = "" } elseif ($typeName2 -ne "String") { $object2 = $object2.ToString() } return $object1 -eq $object2 } elseif (($typeName1 -in @( "Hashtable", "OrderedDictionary", "OrderedHashtable" ) -or $object1 -is [PSCustomObject]) ` -and ($typeName2 -in @( "null", "Hashtable", "OrderedDictionary", "OrderedHashtable" ) -or $object2 -is [PSCustomObject])) { if ($object1 -is [PSCustomObject]) { $object1 = Get-DeepClone $object1 -AsHashTable } if ($null -eq $object2) { $object2 = @{} } elseif ($object2 -is [PSCustomObject]) { $object2 = Get-DeepClone $object2 -AsHashTable } # walk both sets of keys $uniqueKeys = @(@($object1.Keys) + @($object2.Keys) | Sort-Object -Unique ) foreach ($key in $uniqueKeys) { #recurse $item1 = $object1.$key $item2 = $object2.$key if ($item1 -ne $item2 -and !(Confirm-ObjectValueEqualityDeep $item1 $item2)) { return $false } } return $true } else { # equality of other types handled in the then clause of the outer else clause return $false } } } |