不包含不适用于从广告组中拉出的用户对象

时间:2019-02-01 16:49:00

标签: powershell

当使用notcontains检查数组中的对象时,当它应该为false时说True。这是我的代码。

$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,即使对象在数组中也是如此。

在调试模式下,我手动进行检查,即使User对象位于数组中,它仍然会显示True。

我甚至将两个组都设置为具有完全相同的用户,但仍然无法正常工作。

1 个答案:

答案 0 :(得分:0)

tl; dr

不要将AD用户对象自己存储在数组中,而是使用其.SamAccountName属性值(通常,选择一个唯一标识对象的属性):

# ...
$SPSecUKUsers += $SPSecUser.SamAccountName
# ...
if ($SPSecUKUsers -notcontains $UKUser.SamAccountName) { # ...

如果想知道为什么存储对象本身不起作用,请参见下一节。

或者-为了更快地查找-使用 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的 containment operators-contains / notcontains-in / -notin如果输入的元素是 .NET reference types 的实例,请检查与输入数组的元素是否具有 引用相等性(标识)的比较操作数。 strong>,但[string]个实例除外,它们被value types对待,并通过
进行了测试 值相等性(等效性)-参见Equality Comparisons

您可以将集合运算符视为输入数组元素上的隐式循环,使用 -eq运算符对比较操作数进行测试(或者,如果使用case-敏感变体,例如-ccontains-ceq),根据元素类型使用引用相等或值相等。

重要:由于PowerShell灵活的自动类型转换规则,在-eq操作中,哪个操作数是LHS很重要。 使用-in-contains意味着隐含的-eq操作的LHS是要测试的 array元素 ,如下所示示例显示:

 # `, 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'也将转换为带有十进制值[int]的{​​{1}}。

在后一个2中,LHS是字符串(10)强制数字[string]也变成字符串,并且10显然与'10'不匹配

值相等(相等)意味着两个对象具有相同的内容 ,即使具有不同的值类型对象,该内容按照定义存储在不同的存储位置。

例如,'0xa'[int]等数字类型是值类型。根据粗略的经验法则,具有属性的对象通常是引用类型。 您可以检查给定类型的[double]属性;例如,.IsValueType返回[int].IsValueType

引用相等(同一性)意味着两个值仅在指向内存中的非常相同的对象(即相同的实例)时才被视为相等引用类型。

否则,即使它们表示概念上相同的实体,也将它们视为不相等,这就是您所遇到的情况:对$true的两个单独调用返回区别对象,即使您(部分)在两种情况下都要求相同的用户(Get-ADUser返回类型为Microsoft.ActiveDirectory.Management.ADUser的实例,这是引用类型)。

示例:

Get-ADUser