以下内容对我来说似乎很奇怪:
$user1 = Get-ADUser sameuser
$user2 = Get-ADUser sameuser
$user1 -eq $user2 # -> false
# the same for groups:
$group1 = Get-ADGroup samegroup
$group2 = Get-ADGroup samegroup
$group1 -eq $group2 # -> false
实际上,Powershell用户似乎很高兴1 -eq 1
是真的。也:
"1" -eq 1 # -> true
@("1") -contains 1 # -> true
可是:
$h1 = @{bla = 1}
$h2 = @{bla = 1}
$h1 -eq $h2 # -> false
$h1.GetHashCode(), $h2.GetHashCode() # -> 60847006, 5156994
# the above return values of course vary
$a1 = @(1;2;3)
$a2 = @(1;2;3)
$a1.GetHashCode(), $a2.GetHashCode() # -> 52954848, 34157931
# surprise, surprise:
$a1 -eq $a2 # no return value at all? (tested with versions 4.0 and 5.1)
($a1 -eq $a2).GetType() # or an Array?
($a1 -eq $a2).count # -> 0
除了这些有趣的行为之外,真正令人沮丧的是我不能简单地这样做:
$ones = Get-ADPrincipalGroupMembership one
$seconds = Get-ADPrincipalGroupMembership second
$excl_ones = $ones | ? { $_ -notin $seconds }
但必须做这样的事情:
$second_nms = $seconds | % name
$excl_ones = $ones | ? { $_.name -notin $second_nms }
我错过了什么吗?
答案 0 :(得分:8)
要理解你看到的一些奇怪的事情,我们必须退一步考虑更大的图景,即框架PowerShell建立在.NET之上!
$user1 -eq $user2
失败,因为$user1
和$user2
两个不同的对象 - 尽管他们可能代表在Active中的同一个对象目录。
当谈到.NET中的对象相等时,您需要区分值相等和引用相等。
值类型的两个变量,例如[int]
,如果它们的基础值相同,则被视为相等:
$a = 1
$b = 1
$a.Equals($b) # $true
引用类型的两个变量 - 任何不是值类型的变量 - 如果它们具有相同的标识,通常只被认为是相等的 - 也就是说,它们引用内存中的同一个对象:
$a = New-Object object
$b = New-Object object
$a.Equals($b) # $false
我们知道,$a
和$b
完全相同,但它们指的是内存中两个不同的[object]
实例。
类型定义可以覆盖GetHashCode()
(用于确定对象的身份的函数)和Equals()
(用于确定两个对象之间相等的函数) ),因此您可能会发现某些引用类型在比较时似乎充当了值类型 - [string]
是一个主要示例:
$a = "test"
$b = "test"
$a.Equals($b)
ADEntity
类(ActiveDirectory模块中所有输出对象的基本类型)不会尝试这样的事情,这就是你看到结果的原因。
上述内容并没有解释你提出的另一个奇怪的事情,即:
$a1 = @(1;2;3)
$a2 = @(1;2;3)
$a1 -eq $a2 # NOTHING! WHAT'S GOING ON HERE?
要了解这里发生了什么,您需要在PowerShell中研究比较运算符行为!
所有比较运算符(-eq
,-ne
,-gt
,-like
,-match
等)根据左侧支持两种不同的模式side argument:标量和过滤。
在标量模式下,比较运算符将单个对象作为其左侧操作数,将值表达式作为其右侧操作数,并返回布尔结果:$true
或$false
。
在过滤模式下,比较运算符将集合(数组或列表)作为其左侧操作数,将值表达式作为其右侧操作数(就像之前一样)并返回左手集合中满足比较的所有个人成员。
要查看此操作,请尝试以下操作:
$names = "James","Jane","John"
$prefix = "Ja"
$names -like "$prefix*"
您会看到-like
操作返回两个字符串 - James
和Jane
。
如果我们将这些新发现的知识应用于您的示例
@(1;2;3) - eq @(1;2;3)
很明显为什么没有返回 - 左手操作数显然是一个数组,随后的比较(1 -eq @(1;2;3)
,2 -eq @(1;2;3)
等)都不会返回$true
现在谈谈你问题的实际部分。 Active Directory的设计方式使目录中的每个对象都有一个唯一的标识符,您可以使用该标识符来确定它的标识 - objectGUID
值。 .NET中的GUID
恰好是值类型,因此您可以安全地将其用作比较的基础:
$ones = Get-ADPrincipalGroupMembership one
$seconds = Get-ADPrincipalGroupMembership second
$excl_ones = $ones | ? { $_.objectGUID -notin $seconds.objectGUID }
对于安全主体(组,用户,计算机等),另一个可以安全使用的唯一标识符是objectSID
- 安全标识符始终是唯一的。