notcontains 不适用于从 AD 组中提取的用户对象 [英] notcontains not working for User objects pulled from AD Groups
问题描述
当使用 notcontains 检查数组中的对象时,它在应该为假时说真.这是我的代码.
When using notcontains to check for an object in array it is saying True when it should be false. This is the code that I have.
$SPSecUsers = Get-ADGroupMember Test
$AllLondon = Get-ADGroupMember Test_AllLondon
$SPSecUKUsers = @()
$SPSecUSUsers = @()
foreach ($SPSecUser in $SPSecUsers) {
if ($SPSecUser.distinguishedName -match "DC=uk,DC=company,DC=com") {
$SPSecUKUsers += $SPSecUser
} else {
$SPSecUSUsers += $SPSecUser
}
}
foreach ($UKUser in $AllLondon) {
if ($SPSecUKUsers -notcontains $UKUser) {
Write-Host $UKUser.name -ForegroundColor Green
} else {
Write-Host $UKUser.name -ForegroundColor Red
}
}
每次运行时, $SPSecUKUsers -notcontains $UKUser 都会为所有用户显示 True,即使对象在数组中也是如此.
Every time I run this, $SPSecUKUsers -notcontains $UKUser brings up True for all users, even when object is in the array.
在调试模式下,我手动进行了检查,即使 User 对象在数组中,它仍然显示 True.
In debug mode I manually do a check and it still brings up True even though the User object is in the Array.
我什至将两个组设置为具有完全相同的用户,但它仍然不起作用.
I have even set both groups to have the exact same users, and it still does not work.
推荐答案
tl;dr
不要将 AD 用户对象自身存储在您的数组中,而是使用它们的 .SamAccountName
属性值(通常,选择唯一标识对象的属性):
Don't store the AD user objects themselves in your arrays, use their .SamAccountName
property value instead (generally, pick a property that uniquely identifies the objects):
# ...
$SPSecUKUsers += $SPSecUser.SamAccountName
# ...
if ($SPSecUKUsers -notcontains $UKUser.SamAccountName) { # ...
如果您想知道为什么存储对象本身不起作用,请参阅下一节.
See the next section, if you want to know why storing the objects themselves doesn't work.
或者 - 为了更快地查找 - 使用 哈希表:
Alternatively - for faster lookups - use a hashtable:
$SPSecUKUsers = @{} # initialize hashtabe
# ...
# Create an entry for the object at hand, using its .SamAccountName
# as the entry *key*; you can store the object itself as the entry *value*.
# If all you need are lookups by SAM account name, however, you can just
# use a fixed value such as $true.
$SPSecUKUsers[$SPSecUser.SamAccountName] = $SPSecUser
# ...
if ($SPSecUKUsers.ContainsKey($UKUser.SamAccountName)) { # ...
<小时>
关于 PowerShell 的遏制(集合-会员)操作符:
正如 Olaf 和 Lee_Daily 在评论中暗示的那样,PowerShell 的 包含操作符(-contains
/notcontains
和 -in
/-notin
) 检查引用相等(身份)与输入数组元素的比较操作数,如果这些元素是的实例>.NET 引用类型,除了 [string]
实例,它们被视为 值类型,使用
进行测试价值相等(等价) - 参见 相等比较.
About PowerShell's containment (collection-membership) operators:
As Olaf and Lee_Daily imply in the comments, PowerShell's containment operators (-contains
/ notcontains
and -in
/ -notin
) check the comparison operand for reference equality (identity) with the elements of the input array, if those elements are instance of .NET reference types, with the exception of [string]
instances, which are treated like value types, which are tested with
value equality (equivalence) - see Equality Comparisons.
您可以将集合运算符视为对输入数组元素的隐式循环,使用 -eq
运算符(或者,如果您使用区分大小写的变体,例如 -ccontains
,和 -ceq
),使用引用相等或值相等,具体取决于元素类型.
You can think of the set operators as an implicit loop over the input array's elements, testing each against the comparison operand with the -eq
operator (or, if you use the case-sensitive variant such as -ccontains
, with -ceq
), using reference equality or value equality, depending on the element type.
重要:由于 PowerShell 灵活的自动类型转换规则,-eq
操作中哪个操作数是 LHS 很重要.使用-in
或-contains
意味着隐含的-eq
操作的LHS 是被测试的数组元素,如下例所示:
Important: Due to PowerShell's flexible automatic type-conversion rules, which operand is the LHS in an -eq
operation matters. Using -in
or -contains
means that the LHS of the implied -eq
operation is the array element being tested against, as the following examples show:
# `, 10` creates a single-element array
'0xa' -in , 10 # equivalent of: 10 -eq '0xa' => $true
, 10 -contains '0xa' # ditto
#
10 -in , '0xa' # equivalent of: '0xa' -eq 10 => $false
, '0xa' -contains 10 # ditto
在前 2 个操作中,LHS 是一个数字 ([int]
) 强制字符串 RHS ([string]
) 变成一个数字 ([int]
) 也是,十六进制数字字符串"'0xa'
转换为带有十进制值 10
的 [int]
In the first 2 operations, the LHS being a number ([int]
) forces the string RHS ([string]
) to a number ([int]
) too, and the hex "number string" '0xa'
converts to an [int]
with decimal value 10
too.
在后 2 个中,LHS 是一个字符串 ([string]
) 迫使数字 10
也变成一个字符串,而 '10'
显然与 '0xa'
不匹配.
In the latter 2, the LHS being a string ([string]
) forces the number 10
to become a string too, and '10'
obviously doesn't match '0xa'
.
值相等(等价)意味着两个对象具有相同的内容,即使对于不同的值类型对象,内容根据定义存储在不同的内存位置.
Value equality (equivalence) means that two objects have the same content, even though, with distinct value-type objects, that content is by definition stored in different memory locations.
例如,[int]
和 [double]
等数值类型就是值类型.作为粗略的经验法则,具有属性的对象通常是引用类型.您可以检查给定类型的 .IsValueType
属性;例如,[int].IsValueType
返回 $true
.
Numeric types such as [int]
and [double]
are value types, for instance. As a rough rule of thumb, objects that have properties are often reference types.
You can check a given type's .IsValueType
property; e.g., [int].IsValueType
returns $true
.
引用相等(身份)意味着只有当两个值指向内存中非常相同的对象,即相同的实例引用类型.
Reference equality (identity) means that two values are only considered equal if they point to the very same object in memory, i.e., the same instance of a reference type.
否则,它们被视为不相等,即使它们代表概念上相同的实体,这就是您的情况:对 Get-ADUser的两次单独调用code> 返回不同的对象,即使您(部分)在两种情况下请求相同的用户(
Get-ADUser
返回 Microsoft.ActiveDirectory.Management.ADUser
,这是一个引用类型).
Otherwise, they're considered not equal, even if they represent what is conceptually the same entity, which is what happened in your case: two separate calls to Get-ADUser
return distinct objects, even if you (in part) ask for the same users in both cases (Get-ADUser
returns instance of type Microsoft.ActiveDirectory.Management.ADUser
, which is a reference type).
示例:
# Create a custom object...
$customObject = [pscustomobject] @{ one = 1; two = 2 }
# which is an instance of a reference type.
$customObject.GetType().IsValueType # -> $false
# Create an array comprising a value-type instance (1)
# and a reference-type instance (the custom object).
$arr = 1, $customObject
# Look for the value-type instance.
$objectToLookFor = 1
$arr -contains $objectToLookFor # value equality -> $true
# Create another custom object, with the same properties as above.
$objectToLookFor = [pscustomobject] @{ one = 1; two = 2 }
# This lookup *fails*, because $objectToLookFor, despite having the same
# properties as the custom object stored in the array, is a *different object*
$arr -contains $objectToLookFor # reference equality -> $false(!)
# If we look for the very same object stored in the array, the lookup
# succeeds.
$arr -contains $customObject # -> $true
这篇关于notcontains 不适用于从 AD 组中提取的用户对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!