Работа с Active Directory из 1С

Администрирование - Защита, права, пароли

Пример работы с AD из 1С

Всем доброго времени суток.
Возникла необходимость работы с AD из 1с в частности создавать пользователей, группы безопасности и организационные единицы.
Нижеприведенный код распологается во общем модуле.
Для работы используется LDAP провайдер ADSI
Пример содержимого передаваемых и возвращаемых переменных:

  • Организационная единица: "OU=TestOU,DC=domain,DC=internal"
  • Группа безопасности: "CN=TestGroup,OU=TestOU,DC=domain,DC=internal"
  • Пользователь: "CN=TestUser,OU=TestOU,DC=domain,DC=internal"

SID пользователя и группы возвращается в виде COMSafeArray. Я его преобразовывавю в читаемый вид. Он мне нужен для установки прав на каталоги и файлы.
Все функции возвращают результат выполнения Ложь/Истина. В случае возникновения ошибки описание возвращается в переменную ОписаниеОшибки.
Надо не забывать, что пользователь, от имени которого запускается 1с (или пользователь сервера приложения если процедуры будут запускаться на сервере) должен обладать соответствующими правами для работы с AD

Привожу на суд общественности результаты:

1) Cоздание организационной единицы

Функция СоздатьОрганизационнуюЕдиницу(
	ИмяОрганизационнойЕдиницы,
	ОрганизационнаяЕдиницаВладелец,
	Описание,
	
	ГруппаДелегат = "",
	ПолноеИмяОрганизационнойЕдиницы = "", //возращается путь до созданой OU
	ОписаниеОшибки = ""
	) Экспорт
	фРезультат					= Истина;
	Попытка	
		ОрганизационнаяЕдиницаВладелецОбъект	= ПолучитьCOMОбъект("LDAP://" + ОрганизационнаяЕдиницаВладелец);
		ОрганизационнаяЕдиница			= ОрганизационнаяЕдиницаВладелецОбъект.Create("OrganizationalUnit", "OU=" + ИмяОрганизационнойЕдиницы);
		ОрганизационнаяЕдиница.description	= Описание;
		Если Не ПустаяСтрока(ГруппаДелегат) Тогда
			ОрганизационнаяЕдиница.managedBy	= ГруппаДелегат;
		КонецЕсли;
		
		ОрганизационнаяЕдиница.SetInfo();
	Исключение
		фРезультат	= Ложь;
		ОписаниеОшибки	= ОписаниеОшибки();
	КонецПопытки;
	Если фРезультат Тогда
		ПолноеИмяОрганизационнойЕдиницы	= ОрганизационнаяЕдиница.distinguishedName;
	КонецЕсли;
	
	Возврат фРезультат;
КонецФункции

2) Создание группы безопасности

Функция СоздатьГруппуБезопасности(
	ИмяГруппыБезопасности,
	ОрганизационнаяЕдиницаВладелец,
	Описание,
	
	ПолноеИмяГруппыБезопасности = "",
	SID = "",
	ОписаниеОшибки = ""
	) Экспорт
	фРезультат					= Истина;
	//ADS_GROUP_TYPE_GLOBAL_GROUP        = 2;
	//ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP  = 4;
	//ADS_GROUP_TYPE_LOCAL_GROUP         = 4;
	//ADS_GROUP_TYPE_UNIVERSAL_GROUP     = 8;
	//ADS_GROUP_TYPE_SECURITY_ENABLED    = -2147483648;
	
	Попытка	
		ОрганизационнаяЕдиницаВладелецОбъект	= ПолучитьCOMОбъект("LDAP://" + ОрганизационнаяЕдиницаВладелец);
		ГруппаБезопасности			= ОрганизационнаяЕдиницаВладелецОбъект.Create("Group", "CN=" + ИмяГруппыБезопасности);
		ГруппаБезопасности.sAMAccountName	= ИмяГруппыБезопасности;
		ГруппаБезопасности.displayName		= ИмяГруппыБезопасности;
		ГруппаБезопасности.description		= Описание;
		ГруппаБезопасности.groupType		= -2147483646;//ADS_GROUP_TYPE_GLOBAL_GROUP + ADS_GROUP_TYPE_SECURITY_ENABLED; //глобальная группа
		ГруппаБезопасности.SetInfo();
	Исключение
		фРезультат	= Ложь;
		ОписаниеОшибки	= ОписаниеОшибки();
	КонецПопытки;
	
	Если фРезультат Тогда
		SID	= ПреобразоватьSID(ГруппаБезопасности.objectSid);
		ПолноеИмяГруппыБезопасности	= ГруппаБезопасности.distinguishedName;
	КонецЕсли;
	Возврат фРезультат;
КонецФункции

3) Создание пользователя

Функция СоздатьПользователя(
	Логин,
	ПарольПользователя,
	ОрганизационнаяЕдиница,
	АдресЭлектроннойПочты,
	МенятьПарольПриВходе = Истина,
	Описание,
	
	ПутьПользователяAD = "",
	SID = "",
	ОписаниеОшибки = ""
	) Экспорт
	фРезультат					= Истина;
	Попытка	
		ОрганизационнаяЕдиницаОбъект		= ПолучитьCOMОбъект("LDAP://" + ОрганизационнаяЕдиница);
		ПользовательAD						= ОрганизационнаяЕдиницаОбъект.Create("user", "CN=" + Логин);
		ПользовательAD.sAMAccountName		= Логин;
		ПользовательAD.description			= Описание;
		ПользовательAD.userPrincipalName	= Логин + "@" + Константы.НаименованиеДомена.Получить();
		Если Не ПустаяСтрока(АдресЭлектроннойПочты) Тогда
			ПользовательAD.mail					= АдресЭлектроннойПочты;
		КонецЕсли;
		Если МенятьПарольПриВходе Тогда
			ПользовательAD.pwdLastSet		= 0;
		Иначе
			ПользовательAD.pwdLastSet		= -1;
		КонецЕсли;
		
		ПользовательAD.SetInfo();
		ПользовательAD.SetPassword(ПарольПользователя);
	Исключение
		фРезультат	= Ложь;
		ОписаниеОшибки	= ОписаниеОшибки();
	КонецПопытки;

	Если фРезультат Тогда
		SID	= ПреобразоватьSID(ПользовательAD.objectSid);
		ПутьПользователяAD	= ПользовательAD.distinguishedName;
	КонецЕсли;
	
	Если фРезультат Тогда
		ПользовательAD.AccountDisabled = Ложь;
		ПользовательAD.SetInfo();
	КонецЕсли;

	Возврат фРезультат;
КонецФункции

В константе НаименованиеДомена находится название домена типа "domain.internal".

4) Добавление пользователя в группу

Функция ДобавитьПользователяВГруппу(
	ПолноеИмяГруппыБезопасности,
	ПутьПользователяAD,

	ОписаниеОшибки = ""
	) Экспорт
	фРезультат					= Истина;
	Попытка	
		ГруппаБезопасности			= ПолучитьCOMОбъект("LDAP://" + ПолноеИмяГруппыБезопасности);
		ГруппаБезопасности.Add("LDAP://" + ПутьПользователяAD);
		ГруппаБезопасности.SetInfo();
	Исключение
		фРезультат	= Ложь;
		ОписаниеОшибки	= ОписаниеОшибки();
	КонецПопытки;
	
	Возврат фРезультат;
КонецФункции

5) Удаление пользователя из группы

Функция УдалитьПользователяИзГруппы(
	ПолноеИмяГруппыБезопасности,
	ПутьПользователяAD,
	
	ОписаниеОшибки = ""
	) Экспорт
	фРезультат					= Истина;
	Попытка	
		ГруппаБезопасности			= ПолучитьCOMОбъект("LDAP://" + ПолноеИмяГруппыБезопасности);
		ГруппаБезопасности.Remove("LDAP://" + ПутьПользователяAD);
		ГруппаБезопасности.SetInfo();
	Исключение
		фРезультат	= Ложь;
		ОписаниеОшибки	= ОписаниеОшибки();
	КонецПопытки;
	
	Возврат фРезультат;
КонецФункции

6) Переобразование SID из массива в читаемый вид типа "S-1-5-21-3784850290-2022084444-2521399107-4676"

Функция ПреобразоватьSID(objectSid)
	SID	= "S-";
	
	МассивSID	= Новый Массив;
	Для Каждого ЭлементSID Из objectSid Цикл
		МассивSID.Добавить(ЭлементSID);
	КонецЦикла;
	//SID_REVISION
	SID	= SID + Строка(МассивSID[0]) + "-";
	
	КоличествоДашей	= МассивSID[1];
	
	SECURITY_NT_AUTHORITY	= 0;
	Для Инд = 0 По 5 Цикл
		SECURITY_NT_AUTHORITY	= SECURITY_NT_AUTHORITY + МассивSID[2 + Инд] * Pow(2, (5 - Инд) * 8);
	КонецЦикла;
	SID	= SID + Строка(SECURITY_NT_AUTHORITY);
	
	Для Инд = 0 По КоличествоДашей - 1 Цикл
		SID	= SID + "-";
		Даш	= 0;
		Для ИндДаш = 0 По 3 Цикл
			Даш	= Даш + МассивSID[8 + 4 * Инд + ИндДаш] * Pow(2, (ИндДаш) * 8);
		КонецЦикла;
		SID	= SID + Строка(Даш);
	КонецЦикла;
	
	Возврат SID;	
КонецФункции

7) Ну и бонусом привожу процедуру установки прав на каталог. Права ставятся с наследованием на нижестоящие объекты. Для установки используется утилита операционки (в моём случае win 2012 в Asure). При вызове (в толстом клиенте) у 1С теряется фокус. К сожалению как установить права другим способом (например WMI) я не нашел. Планирую копать в сторону PowerShell.

Функция УстановитьПраваНаКаталог(
	ПутьККаталогу,
	SIDГруппы,
	
	Описание = "") Экспорт
	фРезультат	= Истина;
	КодВозврата	= Неопределено;
	Попытка
		ЗапуститьПриложение("icacls " + ПутьККаталогу + " /grant *" + SIDГруппы + ":(CI)(OI)F", , Истина, КодВозврата) 
	Исключение
		Описание	= ОписаниеОшибки();
		фРезультат	= Ложь;
	КонецПопытки;
	
	Если фРезультат Тогда
		Если КодВозврата <> 0 Тогда
			фРезультат	= Ложь;
			Описание	= "Код возврата: " + Строка(КодВозврата);
		КонецЕсли;
	КонецЕсли;
	
	Возврат фРезультат;
КонецФункции

Список использованных ссылок:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa772203%28v=vs.85%29.aspx

http://www.script-coding.com/Python/LDAP.html

http://blogs.msdn.com/b/oldnewthing/archive/2004/03/15/89753.aspx

http://technet.microsoft.com/ru-ru/library/cc753525%28v=ws.10%29.aspx

Незаменимой вешью оказалась утилита Марка Руссиновича

Active Directory Explorer (AD Explorer)

См. также

Вознаграждение за ответ
Показать полностью
Комментарии
1. poyson (poyson) 07.05.14 09:24 Сейчас в теме
Большое спасибо. Будем пробовать....
2. EvgeniuXP EvgeniuXP (EvgeniuXP) 07.05.14 23:56 Сейчас в теме
права на папки можно через командную строку установить - сам не раз так делал, только какая команда сейчас не вспомню, т.к. делал лет 5 назад...
3. Станислав Копылов (ksuman) 11.05.14 06:18 Сейчас в теме
Наш суд общественности - самый гуманный суд в мире!
Может хватит морочить людям голову задачами, не имеющими практического значения.
Все эти операции: удалить, добавить, назначить права - отлично делаются специальными инструментами администрирования.
Единственное что могло бы пригодиться, это вычисление: входит ли текущий пользователь в указанную группу AD и, получение списка доступных групп AD для назначения прав своим внутренним объектам 1С.
4. Migele Migele (migele) 93 11.05.14 12:36 Сейчас в теме
(3) ksuman,
Ну на счет практического использования это Ваше сугубо субъективное мнение.
Алгоритмы используются на вполне боевой системе провижининга. А специальными инструментами администрирования попробуйте пакетно создать 100 пользователей AD, 100 пользователей 1с в 30 различных базах и привязать их к соответствующим учеткам.
9. Михаил Кочнев (Mi4man) 138 27.05.14 14:35 Сейчас в теме
(4) есть ли у Вас реализация поиска по ГУИДу в запросе?
10. Brr (brr) 180 27.05.14 16:27 Сейчас в теме
(9) Mi4man, SELECT ADsPath FROM 'LDAP://10.0.0.254' WHERE objectGUID='\b4\e1\e1\85\3a\15\ac\4b\81\06\db\44\b0\05\14\11­'
11. Михаил Кочнев (Mi4man) 138 27.05.14 16:41 Сейчас в теме
(10) brr, что-то я пробовал, но никак не получалось. Эх...
12. Brr (brr) 180 27.05.14 16:55 Сейчас в теме
(11) Mi4man, а ГУИД именно такое имел представление? Пример: b4e1e1853a15ac4b8106db44b0051411.
13. Михаил Кочнев (Mi4man) 138 27.05.14 18:25 Сейчас в теме
(12) brr, нет, вот такое: \b4\e1\e1\85\3a\15\ac\4b\81\06\db\44\b0\05\14\11 (строка).

А надо было просто b4e1e1853a15ac4b8106db44b0051411 ?
16. Brr (brr) 180 28.05.14 11:33 Сейчас в теме
(13) Mi4man, нет, просто я не понял какое представление ГУИД вы использовали
6. Виктор Радомский (Gulf_Stream) 12.05.14 19:56 Сейчас в теме
(3) ksuman, немного не согласен, вы видимо не администрировали АД с хотя бы 1000 пользователей. На основании этого кода очень удобно выполнять массовые действия над учетными записями. Тоже накатал под свои нужды конфу для работы с LDAP но выложить на общее обозрение не рискну ибо код там уж больно неряшлив :(
33. Илья Логинов (Neverpoint) 29.10.17 05:52 Сейчас в теме
(3) Вы далеки от реального управления бизнесом. В частности у нас в 1С создают новых клиентов, карточки и они автоматом прописываются в AD который как LDAP раздает в FreePBX и еще ряд специальных услуг для клиентов пароли и юзернеймы. Вы не понимаете о чем речь
5. Станислав Раташнюк (stanru1) 81 12.05.14 16:44 Сейчас в теме
Спасибо за потраченное время! Я тоже проводил похожие исследования для импорта пользователей из AD, но с созданием так и не хватило терпения разобраться :) Обязательно в будущем воспользуюсь идеями!
7. Надежда (user_2010) 202 15.05.14 12:30 Сейчас в теме
Нужно в 1С.ЗУП для физических лиц формировать сетевое имя пользователя, e-mail, а потом уже глобальная задача: создавать пользователя в AD.

Вот вопрос: я сформирую для физ лица сетевое имя - мне же нужно проверить, что такого пользователя еще нет в AD. Как это сделать?
8. Михаил Кочнев (Mi4man) 138 27.05.14 14:29 Сейчас в теме
(7) user_2010, для этого необходимо выполнить запрос

ТекстЗапроса = "SELECT ADsPath FROM 'LDAP://"+Домен+"' WHERE objectClass='User' AND userPrincipalName='"+ДоменноеИмя+"'";


Если результат пустой, то соответственно в базе нет такого юзера.
14. Vladimir K (KroVladS) 28.05.14 09:47 Сейчас в теме
гдеб найти примеры работы с openLDAP из под Linux?
15. Dmitry E (harmer) 3 28.05.14 09:54 Сейчас в теме
Спасибо.
Небольшое замечание: SID формируется с символами НПП.
SID    = SID + Строка(Даш);
17. Kostya Zhurov (It-developer) 20 27.02.15 19:34 Сейчас в теме
Не получается создать пользователя. Пишет "Ошибка получения объекта COM: Сервер возвратил ссылку". Что может быть?
Вроде все по схеме
element_group = ПолучитьCOMОбъект("LDAP://OU=Папка 2,OU=Пользователи домена,OU=sim,DC=dc,DC=my_company,DC=com)");
18. Евгений (jake_qwert) 22 23.03.15 10:52 Сейчас в теме
А каким кодом можно изменить организационную единицу (OrganizationalUnit) у существующего пользователя? Т.е. мне нужно перенести в другую папку пользователя. Пробывал изменить distinguishedName, выдает ошибку.
19. Евгений (jake_qwert) 22 23.03.15 12:09 Сейчас в теме
Разобрался сам, вот так, если кому-то интересно (первая строка куда перемещаем, вторая откуда)
set cont = GetObject("LDAP://dc=dom,dc=com")
set newobj = cont.MoveHere("LDAP://cn=jeffsmith,ou=sales,dc=dom,dc=com", "cn=jeffsmith")
20. Ильяс Сарт (i_rebel) 9 10.01.16 08:37 Сейчас в теме
Как получить список групп пользователя из AD ? хочу открывать пользователя AD и видеть его группы AD? ; нужно видеть все группы и те которые присвоены данному пользователю
21. Armando Armando (Armando) 1382 11.01.16 00:33 Сейчас в теме
(20) i_rebel, код на vbs для получения своих групп:
Set objADSysInfo = CreateObject("ADSystemInfo")
Set objUser = GetObject("LDAP://" & objADSysInfo.UserName)
For Each objGroup in objUser.memberOf
    NameGroup = GetObject("LDAP://" & objGroup).cn
Next
23. Ильяс Сарт (i_rebel) 9 20.01.16 12:30 Сейчас в теме
(21) Armando, мне нужно все группы, чтобы потом мог сделать интерактивно добавление или удаление из группы
22. Роман Борисовский (imbaZeratul) 18 15.01.16 07:31 Сейчас в теме
каким кодом можно считать данные пользователя, допустим описание, телефон и так далее
24. Евгений (jake_qwert) 22 10.02.16 12:50 Сейчас в теме
Все получилось всем спасибо.
25. Danil (Danila-Master) 81 02.06.16 14:25 Сейчас в теме
Весь инет перерыл, так и не смог найти нормального примера/описания как переименовать пользователя в AD.
Задача такая:
В 1С сотрудник сменил ФИО, зная ее доменное имя, как поменять на новое ФИО в самом AD?
26. Юрий Дешин (blackhole321) 73 02.06.16 16:25 Сейчас в теме
27. Danil (Danila-Master) 81 30.06.16 11:15 Сейчас в теме
Помогите разобтаться. Почему-то не хочет работать powershell.

В 1С делаю ЗапуститьПриложение("powershell.exe -Command {Set-ADUser -Identity ""1ctest"" -Surname ""Иванов"" -GivenName ""Иван""}");
Имя учетни не меняется.
В cmd.exe пишу строку: powershell.exe -Command {Set-ADUser -Identity "1ctest" -Surname "Иванов" -GivenName "Иван"}
Так же, имя учетки не меняется.
Но если в самой консоле PowerShell'а написать строку: Set-ADUser -Identity "1ctest" -Surname "Иванов" -GivenName "Иван"
То все ништяк, Имя в учетке поменялось.

1С, cmd и консоль PowerShell запущенны от именю учетки, у которой есть права на изменение данных в домене. Так что этот момент стразу отсекаю.
28. Юрий Дешин (blackhole321) 73 30.06.16 12:38 Сейчас в теме
(27) Danila-Master, в 1С код выполняется на том же компьютере, где Вы открывали консоль PowerShell? (М.б. Вы открывали консоль на своей клиентской машине, а ЗапуститьПриложение выполняли на сервере)
29. Danil (Danila-Master) 81 01.07.16 06:39 Сейчас в теме
(28) blackhole321,
(М.б. Вы открывали консоль на своей клиентской машине, а ЗапуститьПриложение выполняли на сервере)

Так оно и есть и будет. Но запуск происходит от одной и той же учетки, что на моем компе, что на сервере.
Но перед тем как писать в 1С, мне нужно из командной строки добится результата. Поэтому пока делаю все на своем компе.

Столкнулся с интересной ситуацией:
В cmd пишу powrshell.exe, проваливаюсь в сам сонсоль PS.
Далее в PS пишу: Get-ADUser -Identity "1ctest"
Выдает ошибку, что команда Get-ADUser не найдена.
Как оказалось нужно подключить модуль для работы с AD.
> Import-Module ActiveDirectory
> Get-ADUser -Identity "1ctest"
о чудо, Get-ADUser выдал результат. но при этом, даже после подключения модуля, команда Set-ADUser -Identity "1ctest" -Surname "Иванов" -GivenName "Иван"
так и выполнилась. И ошибок нет.
30. Danil (Danila-Master) 81 01.07.16 11:11 Сейчас в теме
В общем разобрался я :)
1. Нужно поставить PowerShell версии 4.0 (по-умолчанию у windows 7 и 2008 R2 стоит версия 2.0)
В версии 4.0 не нужно импортировать разные модули, shell сама все делает.
2. Рабочая команда в cmd: powershell.exe Set-ADUser -Identity '1ctest' -Surname 'Иванов' -GivenName 'Иван' -DisplayName 'Иванов Иван'
где
Identity - параметр поиска (в данном случае доменное имя пользователя)
Surname - Фамилия
GivenName - Имя
DisplayName - Отображаемое имя
31. Danil (Danila-Master) 81 15.07.16 08:41 Сейчас в теме
Все, разобралися.
Вдруг кому пригодится, вот рабочий код:
ТекстКоманды = "powershell.exe -command ""$user = Get-ADUser -Identity '" + ДоменноеИмя + "'";
ТекстКоманды = ТекстКоманды + " ; Set-ADUser -Identity $user -Surname '" + ТРег(ФамилияEn) + "' -GivenName '" + ТРег(ИмяEn) + "' -DisplayName '" + ПолноеИмя + "'";
ТекстКоманды = ТекстКоманды + " ; Rename-ADObject -Identity $user -NewName '" + ПолноеИмя + "'""";
			
ЗапуститьПриложение(ТекстКоманды);
32. Юрий Степанян (user695952_stepanyan) 10.03.17 11:02 Сейчас в теме
Какой командой можно добавить роль в список ролей MemberOf ? И как получить ссылку на саму группу?
Оставьте свое сообщение