PowerShell - Как определить, идентичны ли два объекта
Допустим, у вас есть два идентичных объекта (то есть они имеют одинаковые свойства и одинаковые значения соответственно).
Как вы проверяете на равенство?
пример
$obj1
& $obj2
идентичны
Вот что я попробовал:
if($obj1 -eq $obj2)
{
echo 'true'
} else {
echo 'false'
}
# RETURNS "false"
if(Compare-Object -ReferenceObject $obj1 -DifferenceObject $obj2)
{
echo 'true'
} else {
echo 'false'
}
# RETURNS "false"
редактировать
Это не идентично
5 ответов
Вы можете сравнить два PSObject
объекты на равенство свойств и значений с помощью Compare-Object
сравнить Properties
свойства обоих PSObject
объекты. Пример:
if ( -not (Compare-Object $obj1.PSObject.Properties $obj2.PSObject.Properties) ) {
"object properties and values match"
}
else {
"object properties and values do not match"
}
Если вы хотите это в функции:
function Test-PSCustomObjectEquality {
param(
[parameter(Mandatory=$true)]
[PSCustomObject] $firstObject,
[parameter(Mandatory=$true)]
[PSCustomObject] $secondObject
)
-not (Compare-Object $firstObject.PSObject.Properties $secondObject.PSObject.Properties)
}
Я бы предложил использовать Compare-Object
для этой задачи:
Function Test-Objects
{
Param(
[Parameter(Mandatory,Position=0)]
[PSCustomObject]$Obj1,
[Parameter(Mandatory,Position=1)]
[PSCustomObject]$Obj2
)
[Void](Compare-Object -ReferenceObject $Obj1.PSObject.Properties -DifferenceObject.PSObject.Properties $Obj2 -OutVariable 'Test')
## Tests whether they are equal, no return = success
If (-not $Test)
{
$True
}
Else
{
$False
}
}
PS C:\> $Obj1 = [PSCustomObject]@{
Property1 = 'Value1'
Property2 = 'Value2'
Property3 = 'Value3'
Property4 = 'Value4'
Property5 = 'Value5'
}
PS C:\> $Obj2 = [PSCustomObject]@{
Property1 = 'Value1'
Property2 = 'Value2'
Property3 = 'Value3'
Property4 = 'Value4'
Property5 = 'Value5'
}
PS C:\> Test-Objects $Obj1 $Obj2
True
PS C:\> $Obj2 | Add-Member -MemberType 'NoteProperty' -Name 'Prop6' -Value 'Value6'
PS C:\> Test-Objects $Obj1 $Obj2
False
Если вы хотите проверить на равенство для каждого свойства объекта, по одному, чтобы сравнить и сопоставить два объекта и увидеть, какие отдельные части отличаются, вы можете использовать следующую функцию, адаптированную из этой статьи о том, как сравнивать все свойства двух объектов в Windows PowerShell
Function Compare-ObjectProperties {
Param(
[PSObject]$leftObj,
[PSObject]$rightObj
)
$leftProps = $leftObj.PSObject.Properties.Name
$rightProps = $rightObj.PSObject.Properties.Name
$allProps = $leftProps + $rightProps | Sort | Select -Unique
$props = @()
foreach ($propName in $allProps) {
# test if has prop
$leftHasProp = $propName -in $leftProps
$rightHasProp = $propName -in $rightProps
# get value from object
$leftVal = $leftObj.$propName
$rightVal = $rightObj.$propName
# create custom output -
$prop = [pscustomobject] @{
Match = $(If ($propName -eq "SamAccountName" ) {"1st"} Else {
$(If ($leftHasProp -and !$rightHasProp ) {"Left"} Else {
$(If ($rightHasProp -and !$leftHasProp ) {"Right"} Else {
$(If ($leftVal -eq $rightVal ) {"Same"} Else {"Diff"})
})
})
})
PropName = $propName
LeftVal = $leftVal
RightVal = $rightVal
}
$props += $prop
}
# sort & format table widths
$props | Sort-Object Match, PropName | Format-Table -Property `
@{ Expression={$_.Match}; Label="Match"; Width=6},
@{ Expression={$_.PropName}; Label="Property Name"; Width=25},
@{ Expression={$_.LeftVal }; Label="Left Value"; Width=40},
@{ Expression={$_.RightVal}; Label="Right Value"; Width=40}
}
А затем используйте как это:
$adUser1 = Get-ADUser 'Grace.Hopper' -Properties *
$adUser2 = Get-ADUser 'Katherine.Johnson' -Properties *
Compare-ObjectProperties $adUser1 $adUser2
Пара интересных заметок:
- Как проверить, есть ли у элемента свойство
- Как получить значение свойства по имени
- Как создать пользовательский объект PS
- Как создать вложенный условный / троичный оператор
- Как отформатировать таблицу с фиксированной шириной
- Попытка раскрасить вывод с помощью последовательностей выхода VT или
Write-PSObject
, но не смог заставить его работать с фиксированной шириной столбца, которая имела приоритет
Вот функция, которую я использовал:
function Test-ObjectEquality {
param(
[Parameter(Mandatory = $true)]
$Object1,
[Parameter(Mandatory = $true)]
$Object2
)
return !(Compare-Object $Object1.PSObject.Properties $Object2.PSObject.Properties)
}
Примеры:
PS C:\> $obj1 = [pscustomobject] @{ 'a' = '5'; 'b' = 7; };
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
True
PS C:\> $obj2 = [psobject] @{ 'a' = '5'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = New-Object -TypeName PSObject -Property @{ 'a' = '5'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
True
PS C:\> $obj2 = [pscustomobject] @{ 'c' = '6'; 'b' = 7; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = 8; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = 7; c = 8 };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
PS C:\> $obj2 = [pscustomobject] @{ 'a' = '5'; 'b' = '7'; };
PS C:\> Test-ObjectEquality $obj1 $obj2
False
Я конечно полагаю, что для этого возможно пропустить вещи; Однако, если вы посмотрите на то, что в Properties
Вы можете увидеть, что сравнивается для каждого свойства объекта:
PS C:\> $obj1.PSObject.Properties | Select-Object -First 1
MemberType : NoteProperty
IsSettable : True
IsGettable : True
Value : 5
TypeNameOfValue : System.String
Name : a
IsInstance : True
Это не часто, что я заботился о более чем MemberType
, Name
, TypeNameOfValue
, или же Value
свойств объекта.
Кроме того, обратите внимание, что если вам действительно нужно, вы можете сравнить .PSObject.Members
вместо .PSObject.Properties
, Это позволит сравнить свойства и методы, хотя вы сравниваете только вызовы методов, а не определения методов.
Я написал функцию, которая проверяет точное равенство:
function Global:Test-IdenticalObjects
{
param(
[Parameter(Mandatory=$true)]$Object1,
[Parameter(Mandatory=$true)]$Object2,
$SecondRun=$false
)
if(-not ($Object1 -is [PsCustomObject] -and $Object2 -is [PsCustomObject))
{
Write-Error "Objects must be PsCustomObjects"
return
}
foreach($property1 in $Object1.PsObject.Properties)
{
$prop1_name = $property1.Name
$prop1_value = $Object1.$prop1_name
$found_property = $false
foreach($property2 in $Object2.PsObject.Properties)
{
$prop2_name = $property2.Name
$prop2_value = $Object2.$prop2_name
if($prop1_name -eq $prop2_name)
{
$found_property = $true
if($prop1_value -ne $prop2_value)
{
return $false
}
}
} # j loop
if(-not $found_property) { return $false }
} # i loop
if($SecondRun)
{
return $true
} else {
Test-IdenticalObjects -Object1 $Object2 -Object2 $Object1 -SecondRun $true
}
} # function