Следующий код пытается сделать одну вещь. Он пытается найти идентификаторы, которые были добавлены в группу Active Directory с момента последнего запуска задания.
Для этого он считывает идентификаторы пользователей из группы Active Directory и сравнивает их с идентификаторами, сохраненными в файле накануне.
Сначала я прочитал группу AD в хэш-таблицу ($ADUsersHashtable). Затем я прочитал файл в аналогичную хеш-таблицу ($YesterdaysADUsersFile). Обе хеш-таблицы используют идентификатор пользователя в качестве ключа. Затем я проверяю, находится ли каждый идентификатор в $ADUsersHashtable в $YesterdaysADUsersFile. Идентификатор, который находится в $ADUsersHashtable, но отсутствует в $YesterdaysADUsersFile, — это идентификатор, который был добавлен в AD с момента последнего запуска этого задания.
Проблема в том, что если $YesterdaysADUsersFile содержит более одной записи, метод containskey всегда возвращает 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 [email protected]
dzrbcn [email protected]
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 [email protected]
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
Я явно чего-то не понимаю.
Любые предложения будут ценны.
$null
:) - person Mathias R. Jessen   schedule 05.03.2020$hash = @{MyKey = $null}; $hash.MyKey; $hash.MyKey.GetType()
. Потому что хэш-таблица ищет ключ, но возвращает значение, а$UserIDsFromPEALM_ALL_USERSFileHashTable.$key.GetType()
пытается получить тип значения. Я не уверен, что вообще возможно получить такой тип ключа. - person Dávid Laczkó   schedule 05.03.2020$key.GetType()
:) - person Mathias R. Jessen   schedule 05.03.2020$hash.Keys[0].GetType()
- person Mathias R. Jessen   schedule 05.03.2020$PEALM_ALL_USERSGroupMembersHashTable
, которую вы используете в цикле foreach, никогда не определялась. Откуда эта хеш-таблица? P.S. Если я могу быть таким смелым ... Почему вы используете такие невероятно трудные для чтения имена переменных? Код может быть намного легче читать и находить ошибки, если вы называете свои переменные коротко и по делу. - person Theo   schedule 05.03.2020String
, у него есть имя:$innerhash1 = @{Key1 = "innerhash1"}; $innerhash2 = @{Key2 = "innerhash2"}; $outerhash = @{$innerhash1 = "outerhash1"}; $outerhash += @{$innerhash2 = "outerhash2"}; $outerhash
. Но я не знаю, как получить доступ к таким именам, как$outerhash.Key1; $outerhash.{Key1}; $outerhash.@{Key1}; $outerhash.@{Key1 = "innerhash1"}; $outerhash.{Key1 = "innerhash1"}
- ни одно из них не работает, но работает:$outerhash.$innerhash1
. Таким образом, имя переменной каким-то образом обернуто, потому что это не позиционный поиск. - person Dávid Laczkó   schedule 06.03.2020$hash = @{MyKey = $null}; $hash += @{MyOtherKey = "NotNull"}; $hash; $hash.Keys[0]
. - person Dávid Laczkó   schedule 06.03.2020$obj1 = [object]::new();$obj2 = [object]::new();$hash = @{ $obj1 = 1; $obj2 = 2}
- в этом случае нет имени, соответствующего идентификатору ключей. Но$hash[$obj1]
или$hash[$hash.Keys[0]]
все еще работают, как и ожидалось :) - person Mathias R. Jessen   schedule 07.03.2020$outerhash[@{Key1 = "innerhash1"}]
, он синтаксически корректен и запускается, но ничего не возвращает. Теперь то, что находится внутри скобок, можно было бы назвать поиском по имени, потому что это своего рода шаблон, который существует внутри$outerhash
, но это не строка. Однако он не совпадает, потому что это отдельный объект, создаваемый каждый раз, когда он встречается в коде, и каждый раз имеет разный хэш-код:@{Key1 = "innerhash1"}.GetHashCode()
. - person Dávid Laczkó   schedule 20.03.2020