Я не думаю, что использование directoryEntry.Children.Find("CN=" + userName)
значительно улучшит производительность. Атрибут sAMAccountName
является индексированным атрибутом, поэтому поиск выполняется очень быстро. Это один из самых быстрых поисков, которые вы можете совершить.
Но учтите, что ваши два кодовых блока не равны. Find("CN=" + userName)
пытается сопоставить userName
с именем учетной записи: атрибут cn
. Но ваш кодовый блок с DirectorySearcher
соответствует userName
атрибуту sAMAccountName
. Атрибуты cn
и sAMAccountName
не обязательно совпадают (хотя они могут находиться в вашем домене).
Но, если вы все еще хотите использовать Children.Find()
, я подозреваю, что проблема может быть в вашем Path
из DirectoryEntry
. Зачем ты это делаешь?
userEntry.Path = userEntry.Path.Replace(":389", "");
Ваш ADScriptService.Properties.Settings.Default.ActiveDirectoryPath
имеет :389
? В этом нет необходимости, если он начинается с LDAP://
(порт LDAP по умолчанию - 389).
Ваш userEntry.Path
должен выглядеть примерно так (в зависимости от вашего домена) LDAP://CN=user,OU=Users,DC=domain,DC=com
. Если это не так, то вам нужно это исправить.
Примечание: есть кое-что, что вы можете сделать, чтобы ускорить это намного больше, чем изменить поиск. Коллекция Properties
использует кэш. Когда вы получаете доступ к свойству, оно проверяет, находится ли оно уже в кеше, и, если так, использует кеш. Но если свойство не находится в кэше, оно будет запрашивать у Active Directory каждый атрибут, имеющий значение . Это дорого и не нужно, если вы хотите прочитать только один или два атрибута (особенно если вы делаете это для тысяч учетных записей).
Чтобы обойти это, нужно указать только те атрибуты, которые вы хотите использовать, используя RefreshCache
, прежде чем вы получите доступ к любому из Properties
. Как это:
userEntry.RefreshCache(new [] { "sAMAccountName", "userAccountControl" });
Затем, когда вы получите доступ к этим свойствам, они уже будут храниться в кэше и не смогут связаться с AD, чтобы получить что-либо.
Кроме того, если вы выполняете это в большом цикле на тысячах учетных записей, тогда я предлагаю вам вставить DirectoryEntry
в оператор using
(или вызвать userEntry.Dispose()
, когда вы закончите с ним). Обычно в этом нет необходимости, поскольку сборка мусора довольно хороша для их очистки. Но поскольку вы выполняете большой цикл, сборщик мусора не имеет возможности выполнить какую-либо очистку, поэтому ваш процесс может в конечном итоге занимать все больше и больше памяти до тех пор, пока цикл, наконец, не остановится. У меня были такие большие работы, которые занимали несколько ГБ памяти, пока я не начал избавляться от неиспользуемых DirectoryEntry
объектов.
Обновление: На самом деле, забудьте о том, что я сказал о DirectoryEntry
выше. Вам вообще не нужно использовать DirectoryEntry
. Не используйте searchResult.GetDirectoryEntry()
. Проблема в том, что вы уже выполнили поиск, чтобы найти аккаунт. Но теперь вы создаете DirectoryEntry
, который просто сделает еще один вызов в AD, чтобы получить информацию, которая у вас уже есть. Это, вероятно, где ваш основной успех производительности.
Вместо этого используйте атрибуты, полученные в результате поиска. Теперь, как и DirectoryEntry.Properties
, если вы не укажете, какие атрибуты вы хотите вернуть в поиске, он вернет все из них, которые вам не обязательно нужны. Таким образом, вы должны установить коллекцию PropertiesToLoad
следующим образом:
search.PropertiesToLoad.AddRange(new [] { "sAMAccountName", "userAccountControl" });
Затем, после поиска, вы можете использовать это, чтобы получить sAMAccountName
аккаунта, который вы нашли:
searchResult.Properties["sAMAccountName"][0]