また、PSCustomObjectで差分を確認する際の演算子は、どちらが正しいのでしょうか。
構造的に同じかどうかを比較したい場合はどちらも不適切です。
試したこと の動作のイメージ
まず、-eq
演算子のときですが、PSCustomObjectの場合は左辺と右辺が同じ参照かどうかを比較します。
具体的には以下のような場合にTrueになります。
PowerShell
1$PSCsustomObject1[0] -eq $PSCsustomObject1[0]
2$PSCsustomObject2[0] -eq $PSCsustomObject2[0]
それ以外の場合はFalseになります。
-match
演算子のときは、-match
演算子は文字列を対象とした演算子のため、
左辺と右辺の両方が文字列に変換され、その上で文字列として比較が行われます。
今回の場合は、文字列化したときの結果がたまたま一致し、正規表現のメタ文字も含まれなかったため、結果がTrueとなりました。
仮に、プロパティが複数あり、文字列化したときのプロパティの表示の順番が異なっていれば、-match
演算子でもFalseになります。
具体的には以下のような場合はFalseになります。
PowerShell
1$pso1, $pso2 = @(@'
2[
3 {
4 "hoge":"foo",
5 "fuga":"bar"
6 },
7 {
8 "fuga":"bar",
9 "hoge":"foo"
10 }
11]
12'@ | ConvertFrom-Json).ForEach({$_})
13
14$pso1 -match $pso2
対策案
CSV化して比較
単純な値のみが含まれる場合は、ConvertTo-Csv
で文字列化して比較するのが簡単だと思われます。
ConvertTo-Csv
に複数のオブジェクトをパイプライン入力した場合、先頭のオブジェクトに合わせてプロパティの整列が行われるためです。
PowerShell
1$pso1, $pso2 = @(@'
2[
3 {
4 "hoge":"foo",
5 "fuga":"bar"
6 },
7 {
8 "fuga":"bar",
9 "hoge":"foo"
10 }
11]
12'@ | ConvertFrom-Json).ForEach({$_})
13
14# 1行目はヘッダーなので捨てる
15$null, [string]$pso1AsCsv, [string]$pso2AsCsv =
16 @($pso1, $pso2) |
17 ConvertTo-Csv -NoTypeInformation
18
19$pso1AsCsv -eq $pso2AsCsv
各プロパティについて詳細な比較
単純に文字列化できない要素を含んでいる場合は、各プロパティを列挙して比較することになるでしょう。
いろいろ考慮不足な簡易的な実装ですが、以下のコードのようなイメージです。
PowerShell
1using namespace System.Management.Automation
2
3function Test-PSCustomObject {
4<#
5.SYNOPSIS
6二つのオブジェクトが構造的に等しいかどうかを判定します。
7簡易的な実装です。
8https://teratail.com/questions/227831
9#>
10 Param(
11 [Parameter(Mandatory = $true)]
12 [PSCustomObject]$Base
13 ,
14 [Parameter(Mandatory = $true)]
15 [PSCustomObject]$Target
16 )
17 [PSMemberInfoCollection[PSPropertyInfo]]$targeteProps =
18 $Target.psobject.Properties
19 # 各プロパティについて名前を一致するプロパティを探し、値が一致するかどうか確認する
20 [PSPropertyInfo]$baseProp = $null
21 foreach ($baseProp in $Base.psobject.Properties) {
22 [ReadOnlyPSMemberInfoCollection[PSPropertyInfo]]$matchProps =
23 $targeteProps.Match($baseProp.Name)
24 if ($matchProps.Count -eq 0) {
25 Write-Verbose -Message ('$Targetに"{0}"という名前のプロパティがありません。' -f $baseProp.Name)
26 return $false
27 }
28
29 if ($matchProps[0].Value -ne $baseProp.Value) {
30 Write-Verbose -Message ('$Targetの"{0}"という名前のプロパティの値が$Baseと異なります(Base = {1}, Target = {2})。' -f $baseProp.Name, $baseProp.Value, $matchProps[0].Value)
31 return $false
32 }
33 }
34 return $true
35}
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。