Last active
June 28, 2022 09:28
-
-
Save dbroeglin/c6ce3e4639979fa250cf to your computer and use it in GitHub Desktop.
A simple Compare-Hashtable function for powershell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ErrorActionPreference = "Stop" | |
function Compare-Hashtable { | |
<# | |
.SYNOPSIS | |
Compare two Hashtable and returns an array of differences. | |
.DESCRIPTION | |
The Compare-Hashtable function computes differences between two Hashtables. Results are returned as | |
an array of objects with the properties: "key" (the name of the key that caused a difference), | |
"side" (one of "<=", "!=" or "=>"), "lvalue" an "rvalue" (resp. the left and right value | |
associated with the key). | |
.PARAMETER left | |
The left hand side Hashtable to compare. | |
.PARAMETER right | |
The right hand side Hashtable to compare. | |
.EXAMPLE | |
Returns a difference for ("3 <="), c (3 "!=" 4) and e ("=>" 5). | |
Compare-Hashtable @{ a = 1; b = 2; c = 3 } @{ b = 2; c = 4; e = 5} | |
.EXAMPLE | |
Returns a difference for a ("3 <="), c (3 "!=" 4), e ("=>" 5) and g (6 "<="). | |
$left = @{ a = 1; b = 2; c = 3; f = $Null; g = 6 } | |
$right = @{ b = 2; c = 4; e = 5; f = $Null; g = $Null } | |
Compare-Hashtable $left $right | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory = $true)] | |
[Hashtable]$Left, | |
[Parameter(Mandatory = $true)] | |
[Hashtable]$Right | |
) | |
function New-Result($Key, $LValue, $Side, $RValue) { | |
New-Object -Type PSObject -Property @{ | |
key = $Key | |
lvalue = $LValue | |
rvalue = $RValue | |
side = $Side | |
} | |
} | |
[Object[]]$Results = $Left.Keys | % { | |
if ($Left.ContainsKey($_) -and !$Right.ContainsKey($_)) { | |
New-Result $_ $Left[$_] "<=" $Null | |
} else { | |
$LValue, $RValue = $Left[$_], $Right[$_] | |
if ($LValue -ne $RValue) { | |
New-Result $_ $LValue "!=" $RValue | |
} | |
} | |
} | |
$Results += $Right.Keys | % { | |
if (!$Left.ContainsKey($_) -and $Right.ContainsKey($_)) { | |
New-Result $_ $Null "=>" $Right[$_] | |
} | |
} | |
$Results | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$here = Split-Path -Parent $MyInvocation.MyCommand.Path | |
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.' | |
. "$here\$sut" | |
Describe "Compare-Hashtable" { | |
Context "When both are empty" { | |
$Left, $Right = @{}, @{} | |
It "should return nothing" { | |
Compare-Hashtable $Left $Right | Should BeNullOrEmpty | |
} | |
} | |
Context "When both have one identical entry" { | |
$Left, $Right = @{ a = "x" }, @{ a = "x" } | |
It "should return nothing" { | |
Compare-Hashtable $Left $Right | Should BeNullOrEmpty | |
} | |
} | |
Context "When left contains a key with a null value" { | |
$Left, $Right = @{ a = $Null }, @{} | |
It "should return nothing" { | |
[Object[]]$result = Compare-Hashtable $Left $Right | |
$result.Length | Should Be 1 | |
$result.side | Should Be "<=" | |
$result.lvalue | Should Be $Null | |
$result.rvalue | Should Be $Null | |
} | |
} | |
Context "When right contains a key with a null value" { | |
$Left, $Right = @{}, @{ a = $Null } | |
It "should return nothing" { | |
[Object[]]$result = Compare-Hashtable $Left $Right | |
$result.Length | Should Be 1 | |
$result.side | Should Be "=>" | |
$result.lvalue | Should Be $Null | |
$result.rvalue | Should Be $Null | |
} | |
} | |
Context "When both contain various stuff " { | |
$Left = @{ a = 1; b = 2; c = 3; f = $Null; g = 6; k = $Null } | |
$Right = @{ b = 2; c = 4; e = 5; f = $Null; g = $Null; k = 7 } | |
$Result = Compare-Hashtable $Left $Right | |
It "should contain 5 differences" { | |
$Result.Length | Should Be 5 | |
} | |
It "should return a: 1 <=" { | |
($Result | ? { $_.Key -eq "a" }).Side | Should Be "<=" | |
($Result | ? { $_.Key -eq "a" }).LValue | Should Be 1 | |
($Result | ? { $_.Key -eq "a" }).RValue | Should Be $Null | |
} | |
It "should return c: 3 <= 4" { | |
($Result | ? { $_.Key -eq "c" }).Side | Should Be "!=" | |
($Result | ? { $_.Key -eq "c" }).LValue | Should Be 3 | |
($Result | ? { $_.Key -eq "c" }).RValue | Should Be 4 | |
} | |
It "should return e: <= 5" { | |
($Result | ? { $_.Key -eq "e" }).Side | Should Be "=>" | |
($Result | ? { $_.Key -eq "e" }).LValue | Should Be $Null | |
($Result | ? { $_.Key -eq "e" }).RValue | Should Be 5 | |
} | |
It "should return g: 6 !=" { | |
($Result | ? { $_.Key -eq "g" }).Side | Should Be "!=" | |
($Result | ? { $_.Key -eq "g" }).LValue | Should Be 6 | |
($Result | ? { $_.Key -eq "g" }).RValue | Should Be $Null | |
} | |
It "should return k: != 7" { | |
($Result | ? { $_.Key -eq "k" }).Side | Should Be "!=" | |
($Result | ? { $_.Key -eq "k" }).LValue | Should Be $Null | |
($Result | ? { $_.Key -eq "k" }).RValue | Should Be 7 | |
} | |
} | |
} |
Thanks for sharing this @dbroeglin! Would you be willing to release this under an open-source license? If so, mentioning the license name in the comments would be enough for my purpose, and would be a huge help.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Have added an option -includeEqual to have a full Hashtable comparisation