notcontains не работает для пользовательских объектов, извлеченных из групп AD - PullRequest
0 голосов
/ 01 февраля 2019

При использовании notcontains для проверки объекта в массиве он говорит 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 для всех пользователей, даже когда объект находится в массиве.

В режиме отладки я выполняю проверку вручную, и она по-прежнему вызывает True, даже если объект User находится в массиве.

Я даже установил в обеих группах одинаковых пользователей, и он по-прежнему не работает.

1 Ответ

0 голосов
/ 02 февраля 2019

tl; dr

Не сохраняйте пользовательские объекты AD себя в своих массивах, вместо этого используйте их значение свойства .SamAccountName (обычно выбирайтесвойство, которое однозначно идентифицирует объекты):

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

См. следующий раздел, если вы хотите узнать, почему хранение самих объектов не работает.

В качестве альтернативы - для более быстрого поиска - используйте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 (членство в коллекции):

Как подразумевают Олаф и Lee_Daily в комментариях, PowerShell операторы сдерживания (-contains / notcontains и -in / -notin) проверить операнд сравнения для равенство ссылок (тождество) с элементами входного массива, если эти элементы являются экземплярами .NET ссылочных типов , за исключением [string] экземпляров, которые обрабатываются как значения типов , которые тестируются с
значение равенства (эквивалентность) - см. Сравнения равенства .

Вы можете рассматривать операторы множеств как неявный цикл над элементами входного массива, проверяя каждый из них с операндом сравнения с помощью -eq оператор (или, если вы используете регистрозависимый вариант, такой как -ccontains, с -ceq), с использованием равенства ссылок или значений в зависимости от типа элемента.

Важно : Из-за гибких правил автоматического преобразования типов PowerShell, операндом является LHS в операции -eq. Использование -in или -contains означает, что LHS подразумеваемой операции -eq является элементом массива , проверяемым по , как показывают следующие примеры:

 # `, 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

В первых двух операциях LHS, являющийся числом ([int]), также переводит строку RHS ([string]) в число ([int]), а шестнадцатеричная «строка чисел» '0xa' преобразуетв [int] с десятичным значением 10.

В последних 2 LHS, являющийся строкой ([string]), заставляет число 10 также стать строкой, а '10'очевидно, не совпадает '0xa'.

Значение равенства (эквивалентность) означает, что два объекта имеют одинаковое содержимое , хотя,с различными объектами типа значения этот контент по определению хранится в разных местах памяти.

Числовые типы, такие как [int] и [double], например, являются типами значений.Как правило грубое , объекты, которые имеют свойства , часто являются ссылочными типами.Вы можете проверить свойство .IsValueType данного типа;Например, [int].IsValueType возвращает $true.

Ссылочное равенство (тождество) означает, что два значения считаются равными, только если они указывают на очень один и тот же объект впамять , т. е. тот же экземпляр ссылочного типа.

В противном случае они считаются не равными, даже если они представляют концептуально одного и того же объекта,что и произошло в вашем случае: два отдельных вызова Get-ADUser возврат различных объектов , даже если вы (частично) запрашиваете одних и тех же пользователей в обоих случаях (Get-ADUser возвращает экземпляр типа Microsoft.ActiveDirectory.Management.ADUser, который является ссылочным типом).

Примеры:

# 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...