При настройке авторизации пользователей через операционную систему многие разработчики сталкиваются с досадной проблемой: стандартная функция платформы ПользователиОС() (или устаревшая ПользователиWindows()) возвращает таблицу значений, содержащую ровно 100 пользователей, хотя в домене Active Directory их могут быть тысячи. Это создает серьезные неудобства, так как администраторам приходится вводить имена учетных записей вручную вместо выбора из списка.
В этой статье мы подробно проанализируем ситуацию, выясним технические причины такого поведения системы и рассмотрим несколько способов решения проблемы — от системных обновлений до написания альтернативных функций на языке 1С.
Разберем ситуацию с технической стороны. Ограничение в 100 записей не является случайным числом или настройкой 1С. Это стандартный размер порции данных (буфера), который возвращает низкоуровневая функция WinAPI SamrQueryDisplayInformation при использовании протокола SAMR (Security Account Manager Remote Protocol).
Когда платформа 1С запрашивает список пользователей у контроллера домена, происходит следующее:
STATUS_BUFFER_OVERFLOW).Важно понимать, что это не ограничение MaxPageSize в LDAP (где лимит обычно составляет 1000 записей), а именно специфика работы протокола SAMR, который 1С использует "под капотом" в своих стандартных функциях.
Первым делом проанализируем программное окружение. Опыт показывает, что проблема наиболее остро проявляется на связке Windows Server 2019 и старых релизов платформы 1С (ниже 8.3.15).
Рекомендуемые действия:
Если обновление системы невозможно или не дает результата, мы можем написать собственную функцию для получения списка пользователей. Рассмотрим пример использования провайдера WinNT. Этот метод позволяет опрашивать группы домена напрямую.
Проанализируем пример кода:
Функция ПолучитьСписокПользователейВГруппеДомена(ИмяДомена, ИмяГруппы) Экспорт
Результат = Новый Массив;
Попытка
// Подключаемся к конкретной группе домена через WinNT
objNameSpace = ПолучитьCOMОбъект("WinNT://" + СокрЛП(ИмяДомена) + "/" + СокрЛП(ИмяГруппы) + ", Group");
Для каждого item Из objNameSpace.Members Цикл
// Добавляем имя пользователя в массив
Результат.Добавить(item.Name);
КонецЦикла;
Исключение
// Обработка ошибок доступа или отсутствия группы
ЗаписатьЛогСобытий("Ошибка получения пользователей: " + ОписаниеОшибки());
КонецПопытки;
Возврат Результат;
КонецФункции
Преимущество: метод работает стабильно и обходит ограничение в 100 записей.
Недостаток: метод WinNT работает медленнее, чем LDAP, и требует наличия прав на чтение состава групп.
Самый надежный и профессиональный способ получения данных из Active Directory — это использование технологии ADSI через COM-объект ADODB.Connection. Этот метод позволяет выполнять SQL-подобные запросы к базе данных домена и полностью контролировать процесс получения данных.
Разберем реализацию по шагам:
&НаСервере
Процедура ОбновитьСписокПользователейAD()
// Инициализируем системные объекты
АДСИ = Новый COMОбъект("ADSystemInfo");
Домен = АДСИ.DomainDNSName;
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.Provider = "ADSDSOObject";
Соединение.Open("Active Directory Provider");
// Формируем текст запроса.
// sAMAccountName - логин, displayName - полное имя
// subTree означает поиск по всему дереву каталога
ТекстЗапроса = "<LDAP://" + Домен + ">;(&(objectCategory=person)(objectClass=user));sAMAccountName,displayName,adspath;subTree";
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Соединение;
Команда.CommandText = ТекстЗапроса;
// Настройка постраничного вывода (важно для больших списков!)
Команда.Properties("Page Size").Value = 1000;
Команда.Properties("Timeout").Value = 30;
Выборка = Команда.Execute();
Пока НЕ Выборка.EOF Цикл
Логин = Выборка.Fields("sAMAccountName").Value;
ПолноеИмя = Выборка.Fields("displayName").Value;
// Здесь можно записывать данные в справочник или таблицу значений
// Например: НоваяСтрока = ТЗПользователи.Добавить();
Выборка.MoveNext();
КонецЦикла;
Соединение.Close();
КонецПроцедуры
В этом примере мы явно указываем Page Size = 1000. Это заставляет драйвер LDAP запрашивать данные порциями, что гарантирует получение всех записей из домена, даже если их десятки тысяч.
Еще один альтернативный вариант — использование инструментария WMI (Windows Management Instrumentation). Рассмотрим, как можно получить список учетных записей через объект Win32_UserAccount.
Посмотрим на пример кода:
Функция ПолучитьПользователейЧерезWMI()
Список = Новый Массив;
Попытка
Локатор = Новый COMОбъект("WbemScripting.SWbemLocator");
Сервис = Локатор.ConnectServer(".", "root\cimv2");
// Запрос к системному классу аккаунтов
Запрос = Сервис.ExecQuery("SELECT Name, Domain FROM Win32_UserAccount WHERE Disabled = False");
Для каждого Объект Из Запрос Цикл
Список.Добавить(Объект.Domain + "\" + Объект.Name);
КонецЦикла;
Исключение
Сообщить("Ошибка WMI: " + ОписаниеОшибки());
КонецПопытки;
Возврат Список;
КонецФункции
Важный нюанс: при использовании WMI в клиент-серверном варианте запрос будет выполняться от имени учетной записи, под которой запущена служба "1C:Enterprise 8.3 Server Agent". Убедитесь, что у этой учетной записи достаточно прав для чтения данных из Active Directory.
Проанализировав ситуацию, можно сделать вывод, что лимит в 100 пользователей — это не приговор, а следствие технических особенностей взаимодействия 1С с устаревшими протоколами Windows в определенных версиях ОС.
Краткий чек-лист для исправления:
ПользователиОС() продолжают выдавать 100 строк, используйте ADO/LDAP запросы. Это наиболее гибкий и быстрый способ, позволяющий фильтровать пользователей (например, исключать заблокированные учетные записи или технические аккаунты).Read all user information часто решает проблемы с неполным списком.Используя предложенные программные методы, вы сможете создать удобный интерфейс выбора пользователей, который будет корректно работать в любой сетевой инфраструктуре.