ハッシュテーブルをCompare-Objectで比較する注意点

 以前、PowerShellのCompare-Objectで2つのオブジェクトを比較するときの注意点があったのですが、またまたCompare-Objectで困ったという話題です。
 今度はハッシュテーブルの比較となります。例えば

$a = @{x = 1; y = 2}
$b = @{x = 3; y = 4}

のとき、psobjectのときと同じように、

PS C:\> Compare-Object -ReferenceObject $a -DifferenceObject $b -Property x, y

としても結果はNullとなり比較できていません。ハッシュテーブルの比較はオブジェクトと同じようにはできない。ということです。
 ネットを調べてみると、$a.Keysや$b.Valuesなどとして比較してみてはとのこと。

PS C:\> Compare-Object -ReferenceObject $a.Keys -DifferenceObject $b.Keys

は、キーが同じなので、Compare-Objectの結果として同じでNullとなります。
 ハッシュテーブルの値での比較、

PS C:\> Compare-Object -ReferenceObject $a.Values -DifferenceObject $b.Values

InputObject SideIndicator
----------- -------------
{4, 3}      =>
{2, 1}      <=

とのことでちゃんと比較できているようです。でも結果を見ると値全体で比較しています。$aの順番を入れ替えた

$c = @{y = 2; x = 1}

との比較はどうでしょうか。

PS C:\> Compare-Object -ReferenceObject $a.Values -DifferenceObject $c.Values

InputObject SideIndicator
----------- -------------
{1, 2}      =>
{2, 1}      <=

 ダメです。$aと$cは同じキーと値を持つハッシュテーブルですが、値の比較では順番が異なると違うものとして認識されます。これでは単純にValuesで比較できません。
 結局、Compare-Objectはオブジェクト型に対応なのでハッシュテーブルをpscustomobjectに変換してと違いを検出。順番が違う場合は、

PS C:\> Compare-Object -ReferenceObject ([pscustomobject]$a) -DifferenceObject ([pscustomobject]$c) -Property x, y

でNullの結果で同じものとして認識されました。
 もちろん元から値が異なるハッシュテーブルの比較では

PS C:\> Compare-Object -ReferenceObject ([pscustomobject]$a) -DifferenceObject ([pscustomobject]$b) -Property x, y

x y SideIndicator
- - -------------
3 4 =>
1 2 <=

と、違いが検出できています。このオブジェクトに変換してから比較という方法が正解のようです。
 結論としてCompare-Objectでハッシュテーブルを比較する場合は、pscustomobjectに型変換してから、psobjectと同じようにして比較するのがいいみたいです。こうなってくるとCompare-Objectを使うことに固執せずに、Keysをforeachで回して比較するのが確実なような気がします。