internal/functions/Confirm-ObjectValueEqualityDeep.ps1
#Requires -PSEdition Core function Confirm-ObjectValueEqualityDeep { [CmdletBinding()] param( $existingObj, $definedObj ) if ($definedObj -eq $existingObj) { # Covers $null, value types, strings and objects referring to the same object return $true } elseif ($definedObj -is [datetime] -or $existingObj -is [datetime]) { $definedDateString = $definedObj if ($definedObj -is [datetime]) { $definedDateString = $definedObj.ToString("yyyy-MM-dd") } $existingDateString = $existingObj if ($existingObj -is [datetime]) { $existingDateString = $existingObj.ToString("yyyy-MM-dd") } return $definedDateString -eq $existingDateString } else { # Normalize if PSCustomObject or Hashtable $isHashtable = $false $definedHashtable = @{} if ($null -ne $definedObj) { if ($definedObj -is [System.Collections.IDictionary]) { $definedHashtable = $definedObj.Clone() Remove-EmptyFields -definition $definedHashtable $isHashtable = $true } elseif ($definedObj -is [PSCustomObject] -and $definedObj -isnot [System.Collections.IList]) { $definedHashtable = ConvertTo-HashTable $definedObj Remove-EmptyFields -definition $definedHashtable $isHashtable = $true } } $existingHashtable = @{} if ($null -ne $existingObj) { if ($existingObj -is [System.Collections.IDictionary]) { $existingHashtable = $existingObj.Clone() Remove-EmptyFields -definition $existingHashtable $isHashtable = $true } elseif ($existingObj -is [PSCustomObject] -and $existingObj -isnot [System.Collections.IList]) { $existingHashtable = ConvertTo-HashTable $existingObj Remove-EmptyFields -definition $existingHashtable $isHashtable = $true } } if ($isHashtable) { if ($definedHashtable.psbase.Count -ne $existingHashtable.psbase.Count) { return $false } foreach ($key in $existingHashtable.Keys) { if ($definedHashtable.ContainsKey($key)) { if (!(Confirm-ObjectValueEqualityDeep -existingObj $existingHashtable.$key -definedObj $definedHashtable.$key)) { return $false } } else { return $false } } return $true } else { # normalize arrays if one or both operands are an array $isList = $false [array] $definedList = @() if ($null -ne $definedObj) { if ($definedObj -is [System.Collections.IList]) { $definedList = $definedObj $isList = $true } else { $definedList += $definedObj } } [array] $existingList = @() if ($null -ne $existingObj) { if ($existingObj -is [System.Collections.IList]) { $existingList = $existingObj $isList = $true } else { $existingList += $existingObj } } if ($isList) { if ($definedList.Count -ne $existingList.Count) { # arrays of differing lengths are by definition not equal return $false } elseif ($definedList.Count -eq 0 -and $existingList.Count -eq 0) { # two zero length arrays are equal return $true } else { $existingArrayList = [System.Collections.ArrayList]::new($existingList) foreach ($definedItem in $definedList) { $foundMatch = $false $existingCount = $existingArrayList.Count for ($i = 0; $i -lt $existingCount; ++$i) { $existingItem = $existingArrayList[$i] if (Confirm-ObjectValueEqualityDeep -existingObj $existingItem -definedObj $definedItem) { $existingArrayList.RemoveAt($i) $foundMatch = $true break } } if (!$foundMatch) { return $false } } return $true } } else { # Value type, equality already tested at beginning return $false } } } } |