Powershell hashtable.containskey всегда возвращает true - PullRequest
1 голос
/ 05 марта 2020

Следующий код пытается сделать одну вещь. Он пытается найти идентификаторы, которые были добавлены в группу Active Directory с момента последнего запуска задания.

Это делается путем считывания идентификаторов пользователей из группы Active Directory и сравнения их с идентификаторами, сохраненными в файле накануне.

Сначала я прочитал группу AD в хеш-таблицу ($ ADUsersHashtable). Затем я прочитал файл в похожую хеш-таблицу ($ YesterdaysADUsersFile). В обеих хеш-таблицах в качестве ключа используется идентификатор пользователя. Затем я проверяю, есть ли каждый идентификатор в $ ADUsersHashtable в $ YesterdaysADUsersFile. Идентификатор, который находится в $ ADUsersHashtable, но не находится в $ YesterdaysADUsersFile, является идентификатором, который был добавлен в AD с момента последнего запуска этого задания.

Проблема в том, что если в $ YesterdaysADUsersFile содержится более одной записи, метод содержит ключ всегда возвращает значение true (см. Вывод ниже)

Если я удаляю все, кроме одной записи в файле, код работает, как и ожидалось.

Если у меня есть более одной записи в файле, код не работает должным образом.

Ниже приведен код, который считывает AD и файл в хеш-таблицы, а затем сравнивает ключи.

$scriptName = $MyInvocation.MyCommand.Name
$LogFile = "D:\Polarion\data\logs\User Access Dates\$scriptName.log"
$Today = Get-Date
$outDate = get-date -format "yyyy-MM-dd"
Add-content $LogFile "$Today Running $scriptName"
$MyServer = $env:computername
Add-content $LogFile "`t$Today Running on $MyServer"

#Will be populated with IDs from AD that i didn't find yesterday
$NewUsersFile = "D:\Polarion\data\logs\User Access Dates\NewUsersInPEALM_ALL_USERSADGroup.txt" 
clear-content $NewUsersFile #I only want the new users from todays AD group.

$ADUsersHashtable = @{} #Contains IDs of the members in the AD Group.
Get-ADGroupMember -Identity PEALM_ALL_USERS -Recursive `
    | Get-ADObject -Properties SamAccountName, mail `
    | select SamAccountName, mail `
    | foreach {$ADUsersHashtable.Add($_.SamAccountName, $_.mail)}
#$ADUsersHashtable

$YesterdaysADUsersFile = "D:\Polarion\data\logs\User Access Dates\UserIdFromPEALM_ALL_USERS.txt" #Contains the IDs that I knew about the last time this ran.
$YesterdaysADUsersHashTable = @{}
$YesterdaysADUsersHashTable = Get-Content($YesterdaysADUsersFile) | 
    foreach {$_.ToString().Replace(":", "=")} | 
    ConvertFrom-StringData
$YesterdaysADUsersHashTable

$NoNewUsersFound = $true
foreach ($UserIDFromAD in $ADUsersHashtable.keys){ #For each user ID in Todays AD group
    if ($YesterdaysADUsersHashTable.containsKey($UserIDFromAD)){ #If the UserID is in Yesterdays list ignore it.
        write-host YesterdaysADUsersHashTable contains key $UserIDFromAD
    } else {
        $NoNewUsersFound = $false
        write-host YesterdaysADUsersHashTable Doesnt contains key $UserIDFromAD 
        write-host "`tadding $UserIDFromAD to the $NewUsersFile file."
        Add-content $LogFile "`t$Today Adding $UserIDFromAD to $NewUsersFile file"
        Add-Content $NewUsersFile "$UserIDFromAD : $outDate" #if its not in yesterdays list write it to the new users file.
    }
}
if ($NoNewUsersFound){
    Add-content $LogFile "`t$Today No new users IDs found in Active Directory."
}
#Clear-Content $YesterdaysADUsersFile #we want to overwrite the file, not append to it. 
#$ADUsersHashtable.keys `
#    | %{ Add-Content $YesterdaysADUsersFile "$_ : $($ADUsersHashtable.$_)" } #writes the content of the hashtable to a file.

Ниже приводится вывод, когда файл (и, следовательно, $ YesterdaysADUsersHashTable) содержит две записи. Первые четыре строки - это дамп $ YesterdaysADUsersHashTable. Следующие пять строк взяты из выходных данных команд write-host в блоке if-containskey. Они показывают, что hashtable.containskey возвращает true для каждого ключа в $ ADUsersHashtable. Но эти ключи не в $ YesterdaysADUsersHashTable, это то, что я не понимаю.

Name                           Value                                                                                                                                               
----                           -----                                                                                                                                               
QZMRW2                         xxxx.xxxx@xxxx.com                                                                                                                 
dzrbcn                         xxxx.xxxx@xxxx.com  

YesterdaysADUsersHashTable contains key QZMRW2
YesterdaysADUsersHashTable contains key dzrbcn
YesterdaysADUsersHashTable contains key MZDP2G
YesterdaysADUsersHashTable contains key BZ5LBQ
YesterdaysADUsersHashTable contains key FZ080Y

$ YesterdaysADUsersHashTable явно не содержит «MZDP2G», «BZ5LBQ» или «FZ080Y»

И, если я удаляю из файла все, кроме одного идентификатора пользователя, код похоже на работу. $ YesterdaysADUsersHashTable теперь имеет только одну запись "QZMRW2", и код, похоже, работает.

Name                           Value                                                                                                                                               
----                           -----                                                                                                                                               
QZMRW2                         xxxx.xxxx@xxxx.com  

YesterdaysADUsersHashTable contains key QZMRW2
YesterdaysADUsersHashTable Doesnt contains key dzrbcn
    adding dzrbcn to the D:\Polarion\data\logs\User Access Dates\NewUsersInPEALM_ALL_USERSADGroup.txt file.
YesterdaysADUsersHashTable Doesnt contains key MZDP2G
    adding MZDP2G to the D:\Polarion\data\logs\User Access Dates\NewUsersInPEALM_ALL_USERSADGroup.txt file.
YesterdaysADUsersHashTable Doesnt contains key BZ5LBQ
    adding BZ5LBQ to the D:\Polarion\data\logs\User Access Dates\NewUsersInPEALM_ALL_USERSADGroup.txt file.
YesterdaysADUsersHashTable Doesnt contains key FZ080Y

Я явно чего-то не понимаю.

Буду признателен за любые предложения.

Ответы [ 2 ]

0 голосов
/ 06 марта 2020

Я получил код для работы, изменив hashtable.containskey на -contains. В следующем фрагменте кода я прокомментировал нашу строку, содержащую .containsKey ($ UserIDFromAD), и добавил строку, содержащую $ UserIDsFromFile.keys -contains $ UserIDFromAD. Код теперь работает как положено.

Это должно быть связано с разницей между проверкой по ссылке и проверкой по значению. Я знаю, как это работает в Java, но не в Powershell.

#if ($UserIDsFromFile.containsKey($UserIDFromAD)){ #If the UserID is in Yesterdays list ignore it.
if ($UserIDsFromFile.keys -contains $UserIDFromAD){ #If the UserID is in Yesterdays list ignore it.
0 голосов
/ 05 марта 2020

Тот факт, что ключ существует , не означает, что соответствующее значение не равно $null.

. Ниже приведен пример:

$a = @{ keyName = "Value" }
$b = @{ keyName = $null }

foreach($key in $a.Keys){
    if($b.ContainsKey($key)){
        $bValue = $b[$key] # or `$b.$key` if the key is a string

        if($null -eq $bValue){
            Write-Host "Key '$key' exists in '`$b', but its value is `$null :("
        }
    }
}

Без подробности о том, как вы заполняете свои хеш-таблицы, трудно сказать почему :)

...