При работе с Active Directory (AD) через механизмы ADO и COM-объекты в 1С часто возникает необходимость найти конкретную запись по её уникальному идентификатору objectGUID. Однако при попытке передать GUID через параметры Command.Parameters или обычным сопоставлением со строкой в секции WHERE разработчики сталкиваются с ошибками провайдера ADsDSOObject.
В этой статье мы разберем причину возникновения проблемы, проанализируем порядок байтов при конвертации GUID и рассмотрим практические способы поиска и получения объектов по objectGUID из 1С.
Выясним особенности работы OLE DB провайдера для Active Directory (ADsDSOObject):
ADsDSOObject: Провайдер ADO для LDAP не поддерживает подстановку бинарных параметров через знак ? и коллекцию Command.Parameters. При попытке передать параметр подсистема возвращает исключение Provider: Произошла одна или несколько ошибок во время обработки команды.CAST и CONVERT.objectGUID: В Active Directory атрибут objectGUID хранится в виде 16-байтового массива (тип OctetString). Чтобы выполнить выборку по строковому GUID (например, {E2B589DD-DE54-475E-BCD4-DD894F6BF9EE}), его необходимо перевести в бинарный вид с учетом правил хранения данных Microsoft GUID (Little-Endian для первых трех групп).Рассмотрим, как правильно подготовить строковый GUID для подстановки непосредственно в текст SQL-запроса. Для этого требуется переставить байты в соответствии с правилами структуры GUID и записать их через обратный слэш \ в одиночных кавычках.
Правило перестановки байтов из строкового GUID (на примере E2B589DD-DE54-475E-BCD4-DD894F6BF9EE):
E2B589DD) записываются в обратном порядке: DD, 89, B5, E2.DE54) записываются в обратном порядке: 54, DE.475E) записываются в обратном порядке: 5E, 47.BCD4-DD894F6BF9EE) записываются в прямом порядке: BC, D4, DD, 89, 4F, 6B, F9, EE.Посмотрим на пример функции 1С, которая преобразует стандартную строку GUID в формат для SQL-запроса ADO:
Функция ПодготовитьGUIDДляLDAP(Знач СтрокаGUID) Экспорт
// Удаляем скобки и дефисы
Стр = СтрЗаменить(СтрокаGUID, "{", "");
Стр = СтрЗаменить(Стр, "}", "");
Стр = СтрЗаменить(Стр, "-", "");
Если СтрДлина(Стр) <> 32 Тогда
Возврат "";
КонецЕсли;
// Перестановка байтов (Little-Endian для первых трех секций)
Результат = "\" + Сред(Стр, 7, 2) + "\" + Сред(Стр, 5, 2) + "\" + Сред(Стр, 3, 2) + "\" + Сред(Стр, 1, 2)
+ "\" + Сред(Стр, 11, 2) + "\" + Сред(Стр, 9, 2)
+ "\" + Сред(Стр, 15, 2) + "\" + Сред(Стр, 13, 2)
+ "\" + Сред(Стр, 17, 2) + "\" + Сред(Стр, 19, 2)
+ "\" + Сред(Стр, 21, 2) + "\" + Сред(Стр, 23, 2)
+ "\" + Сред(Стр, 25, 2) + "\" + Сред(Стр, 27, 2)
+ "\" + Сред(Стр, 29, 2) + "\" + Сред(Стр, 31, 2);
Возврат Результат;
КонецФункции
Разберем пример исполнения запроса ADO с созданной строкой:
ГуидСтр = "{E2B589DD-DE54-475E-BCD4-DD894F6BF9EE}";
LdapGuid = ПодготовитьGUIDДляLDAP(ГуидСтр);
ADODB_Command = Новый COMОбъект("ADODB.Command");
ADODB_Command.ActiveConnection = Connection;
ADODB_Command.Properties("Page Size").Value = 1000;
ADODB_Command.Properties("Timeout").Value = 30;
ADODB_Command.Properties("Cache Results").Value = Ложь;
// Формируем текст запроса с экранированной байтовой строкой
ТекстЗапроса = "SELECT ADsPath, objectGUID, sAMAccountName, userPrincipalName " +
"FROM 'LDAP://" + Адрес + "/" + RootPath + "' " +
"WHERE objectGUID = '" + LdapGuid + "'";
ADODB_Command.CommandText = ТекстЗапроса;
rs = ADODB_Command.Execute();
Если задача состоит в том, чтобы просто получить данные конкретного объекта Active Directory по известному GUID, можно обойтись без выполнения поиска через ADODB.Command. В AD поддерживается прямое связывание с объектом по пути вида LDAP://<GUID=...>.
Проанализируем применение прямого связывания в коде 1С:
ГуидСтр = "E2B589DD-DE54-475E-BCD4-DD894F6BF9EE";
ГуидСтр = СтрЗаменить(СтрЗаменить(ГуидСтр, "{", ""), "}", "");
ПутьLDAP = "LDAP://<GUID=" + ГуидСтр + ">";
Попытка
ОбъектAD = ПолучитьCOMОбъект(ПутьLDAP);
ЛогинПользователя = ОбъектAD.Get("sAMAccountName");
UPN = ОбъектAD.Get("userPrincipalName");
Исключение
Сообщить("Не удалось найти объект в AD по GUID: " + ОписаниеОшибки());
КонецПопытки;
Преимущество данного подхода: при прямом связывании не требуется менять порядок байтов или применять слэши — платформа Active Directory сама преобразует стандартный строковый GUID.
При получении поля objectGUID из результата запроса ADO (rs.Fields("objectGUID").Value) возвращается массив байтов в формате COMSafeArray. Для дальнейшего сохранения GUID в текстовый реквизит информационной базы 1С необходимо выполнить обратную конвертацию.
Рассмотрим пример функции перевода байтового массива в строку формата GUID:
Функция ПреобразоватьCOMGUIDВСтроку(COMobjectGUID) Экспорт
МассивБайт = COMobjectGUID.Выгрузить(); // Выгружаем COMSafeArray в Массив 1С
// Вспомогательная логика перевода байта в 2-символьный HEX-вид
GUID = "{";
GUID = GUID + НЕХ(МассивБайт[3]) + НЕХ(МассивБайт[2]) + НЕХ(МассивБайт[1]) + НЕХ(МассивБайт[0]) + "-";
GUID = GUID + НЕХ(МассивБайт[5]) + НЕХ(МассивБайт[4]) + "-";
GUID = GUID + НЕХ(МассивБайт[7]) + НЕХ(МассивБайт[6]) + "-";
GUID = GUID + НЕХ(МассивБайт[8]) + НЕХ(МассивБайт[9]) + "-";
GUID = GUID + НЕХ(МассивБайт[10]) + НЕХ(МассивБайт[11]) + НЕХ(МассивБайт[12]) + НЕХ(МассивБайт[13]) + НЕХ(МассивБайт[14]) + НЕХ(МассивБайт[15]);
GUID = GUID + "}";
Возврат GUID;
КонецФункции
Таким образом, мы разжились инструментами для полноценной работы с objectGUID. Для построения выборок с фильтрами в ADO используйте подготовку байтовой строки через слэши, а для точечной работы с известным объектом применяйте прямое связывание по пути LDAP://<GUID=...>.