ИВАН КОРОБКО
Эффективно управляем полями пользователей в AD
Предположим, вам необходимо внести ряд однотипных изменений в свойствах всех пользователей или пользователей в пределах группы в Active Directory. Сделать их в одном поле у 10-20 пользователей не составит труда. А как быть, если количество полей 2-3, а объектов 200-300?
Для этих целей рекомендуется использовать сценарий, с помощью которого можно автоматически внести необходимые изменения в свойства объектов AD, практически исключив влияние человеческого фактора. О создании такого скрипта и пойдет речь в этой статье.
Функционал сценария
Предлагаемый сценарий обеспечивает следующий функционал: корректировку профиля, сценария загрузки, корректировку домашнего каталога (в случае необходимости создание домашнего каталога по указанному шаблону и его предоставление в общий доступ). Все эти свойства должны быть применены только для всех пользователей, входящих в указанную группу, либо для всех пользователей, не входящих в указанную группу. Выполнение одного или второго условия зависит исключительно от трудозатрат на включения пользователей в группу.
Язык создания сценария
В качестве языка программирования рекомендуется использовать VBScript, т.к. он имеет ряд преимуществ перед другими языками программирования:
- VBScript – встроенный в операционную систему Windows стандартный скриптовой язык.
- Поддерживает OLE-объекты, что позволяет получить доступ к AD.
- В нем реализована поддержка файловых систем FAT и NTFS – можно производить операции с файлами и папками, управлять уровнями доступа к файлам (только NTFS).
Параметры командной строки
Для успешной работы сценария необходимы следующие параметры командной строки:
- Домен. Может быть определен в автоматическом режиме. Задавать его в явном виде нет необходимости.
- Название группы, к членам которой применяется скрипт, либо наоборот: скрипт будет применен ко всем пользователям домена, кроме тех, которые входят в эту группу.
- Название сценария регистрации пользователей в сети.
- UNC-путь к профилю.
- UNC и локальный путь к домашнему каталогу.
Замечание: сценарий должен запускаться только с сервера, на котором необходимо корректировать домашние каталоги.
Определение имени домена
Имя домена может быть определено с помощью одного из провайдеров доступа к AD: WinNT или LDAP. При выборе провайдера необходимо учесть, что WinNT в качестве результата выдает массив, содержащий не только текущий домен, но и доступные рабочие группы, если таковые имеются. Рабочие группы могут временно появиться при подключении одной из рабочих станций к домену или в случае подключения стороннего портативного компьютера к ресурсам сети. Поэтому, несмотря на громоздкий синтаксис, рекомендуется использовать провайдер LDAP, с помощью которого можно определить как длинное имя домена, так и короткое:
set rootDSE_ = GetObject("LDAP://RootDSE")
d_def=rootDSE_.Get("defaultNamingContext")
long_Ldap_name = "LDAP://" + d_def
short_winnt_name= mid(d_def, instr(d_def,"=")+1, instr(d_def,",")-instr(d_def,"=")-1)
wscript.echo long_Ldap_name
wscript.echo short_winnt_name
Определение параметров командной строки
Для определения параметров, переданных скрипту из командной строки, необходимо использовать свойство Arguments объекта WScript. Параметры командной строки считываются сценарием как элементы массива:
Set objArgs=Wscript.Arguments
For Each arg in objArgs
t = t & arg & chr(13)
Next
MsgBox t
Поскольку все параметры в данной ситуации обязательны, то рекомендуется вставить обработчик ошибок:
Set objArgs=Wscript.Arguments
If len(cstr(objArgs(3)))=0 then
strShare="c:\root\home\"
strShare=InputBox("Share","ShareFolder","c:\root\home\")
else
strShare= cstr(objArgs(3))
If len(cstr(objArgs(2)))=0 then
strFolder="\\moscow\root\home\"
strFolder = InputBox("Folder:", "Home dir \%username%", "\\moscow\root\home\")
else
strFolder= cstr(objArgs(2))
…………………………………
End if
End if
где:
- strShare – локальный путь к папке, в которой будет создан домашний каталог. Его физическое имя совпадает с именем пользователя в сети (login), а название папки в сети (share name) совпадает с именем пользователя в сети со знаком доллара (hidden share).
- strFolder – сетевой путь к этой же папке.
- strProfile – сетевой путь к профилям пользователей. Если этот параметр не задан, то профили пользователей будут локальными.
- strGroup – имя группы безопасности в AD.
- strScript – содержит имя сценария загрузки пользователя в сети.
Определение членов группы
Провайдер WINNT был разработан для операционной системы Win 4.0, когда еще не было AD. Структура объектов WINNT одноуровневая, неиерархическая, поэтому чтение необходимых объектов осуществляется с помощью фильтров, в данном случае «group»:
Set GroupName="Value_Group"
Set user_group=GetObject("WinNT://" & short_winnt_name & "/"& GroupName & ", group")
For each obj inGroup.Members
temp=temp+Member.Name
Next
MsgBox temp
где short_winnt_name – короткое имя домена, GroupName – имя группы безопасности, членов которой необходимо определить.
Управление свойствами пользователя с помощью провайдера WINNT
Учетные записи пользователей домена содержатся в подклассе User. Подкласс включает в себя более 20 параметров (их описание см. в таблице 1), некоторые из которых не поддерживаются Windows 2k.
Таблица 1. Описание параметров подкласса User
Поддерживаемые свойства
|
Тип данных
|
Описание
|
AccountExpirationDate
|
Дата
|
Не поддерживается Windows 2k, т.к. провайдер WinNT был разработан для Windows NT
|
AutoUnlockInterval
|
Число
|
Интервал (сек), после которого учетная запись автоматически разблокируется, если она была заблокирована. Для установки бесконечного времени ожидания устанавливается значение равное «-1»
|
BadPasswordAttempts
|
Число
|
Количество неправильно введенных паролей в течение времени, указанного в параметре LockoutObservationInterval
|
|
Строка
|
Описание пользователя. В Windows 2k, как правило, используются другие поля, доступные только через протокол LDAP
|
FullName
|
Строка
|
Полное имя пользователя. Имеет формат: Second Name, First Name
|
HomeDirDrive
|
Буква
|
Буква домашнего каталога. Формат: буква:
|
HomeDirectory
|
Строка
|
Путь в формате UNC к домашнему каталогу в виде ServerFolder
|
UserFlags
|
Число
|
Флаг, с помощью которого определяется статус пользователя в сети
|
LockoutObservationInterval
|
Число
|
Интервал (сек), в течение которого контроллер домена хранит число неверных попыток регистрации в домене
|
LoginHours
|
Массив
|
Не поддерживается Windows 2k
|
LastLogin
|
Дата
|
Дата и время последней регистрации пользователя в сети
|
LastLogoff
|
Дата
|
Не поддерживается Windows 2k
|
|
Строка
|
Сценарий загрузки
|
LoginWorkstations
|
Строка
|
Не поддерживается Windows 2k
|
MinPasswordAge
|
Строка
|
Временной интервал (сек), в течение которого пользователь не сможет сменить свой пароль.
|
MinPasswordLength
|
Строка
|
Минимальная длина пароля. Если необходимо, разрешите использовать пустые пароли – установите значение, равно «-1»
|
MaxBadPasswordsAllowed
|
Число
|
Число попыток, после которого блокируется учетная запись. Значение параметра варьируется от 0 до 999. Для снятия ограничения параметру присваивается значение «-1»
|
MaxLogins
|
Строка
|
Не поддерживается Windows 2k
|
MaxPasswordAge
|
|
Срок действия пароля. Пароль имеет неограниченный срок действия, если значение параметра равно «-1»
|
ObjectSid
|
Строка
|
Не поддерживается Windows 2k
|
PasswordAge
|
Число
|
Время в секундах с момента смены пароля
|
PasswordExpirationDate
|
Дата
|
Дата и время окончания действия пароля
|
PasswordExpired
|
Число
|
Принимает значение 0/1. 0
|
PasswordHistoryLength
|
|
Размер списка паролей, хранящихся на контроллере домена для каждого пользователя. Данный список предотвращает повторное использование паролей. Для деактивации хранения истории паролей установите значение параметра равным «-1»
|
PrimaryGroupID
|
Число
|
ID-номер основной группы пользователя
|
Profile
|
Строка
|
Содержит путь, где хранится профиль в UNC-формате
|
Пример чтения полей пользователя USER (переменная UserName):
Set UserName="USER"
Set user=GetObject("WinNT://" & short_winnt_name & "/"& UserName)
u1="FullName: "+ cstr(user.FullName)+chr(13)
u2="UserFlags: "+ cstr(user.UserFlags)+chr(13)
u3="LoginScript: "+ cstr(user.LoginScript)+chr(13)
u4="MaxBadPasswordsAllowed: "+ cstr(user.MaxBadPasswordsAllowed)+chr(13)
u5="PasswordHistoryLength: "+ cstr(user.PasswordHistoryLength)+chr(13)
u6="AutoUnlockInterval: "+ cstr(user.AutoUnlockInterval)+chr(13)
u7="PasswordAge: "+ cstr(user.PasswordAge)+chr(13)
u8="PasswordExpired: "+ cstr(user.PasswordExpired)+chr(13)
temp=""
temp=u1+u2+u3+u4+u5+u6+u7+u8
MsgBox temp
Изменение свойств полей осуществляется с помощью метода SetInfo после банального присвоения нового значения какого-либо параметра:
User.HomeDirDrive="Y:"
User.HomeDirectory="\\" & strDomain & "\"& user.name & "$"
User.LoginScript=strScript
User.Profile=strProfile & user.name
User.setinfo
Таким образом, переданные сценарию параметры из командной строки, определение членов группы и механизм изменения свойств можно объединить в единое целое:
set rootDSE_ = GetObject("LDAP://RootDSE")
d_def=rootDSE_.Get("defaultNamingContext")
short_winnt_name = "LDAP://" + d_def
For each user in users_domain
i=0
a=user.name
Set user_group = GetObject("WinNT://" & short_winnt_name & "/" & strGroup)
For each user_group in user_group.Members
b=user_group.name
if b=a then
i=1
end if
next
if i=0 then
User.HomeDirDrive="Y:"
User.HomeDirectory="\\" & short_winnt_name & "\" & user.name & "$"
User.LoginScript=strScript
if not User.Profile="" then
User.Profile=strProfile & user.name
end if
User.setinfo
end if
next
В приведенном примере обрабатываются учетные записи пользователей, не входящих в группу strGroup. Для того чтобы изменить условие, т.е. производить действия над пользователями, принадлежащими группе, необходимо изменить условие цикла if с «if i=0 then» на «if i=1 then» или «if i<>0 then».
Управление домашним каталогом
Сценарий должен последовательно выполнять следующие действия:
- определить, существует ли у домашнего пользователя каталог;
- предоставить папку в доступ с правильным именем (смена sharename);
- изменить права на файловую структуру NTFS в соответствии с установленными правилами;
- сделать необходимые изменения в свойствах учетной записи пользователя в AD.
Создание и удаление папок
Создание и удаление каталогов осуществляется с помощью методов CreateFolder(path) и DeleteFolder(path) объекта USER. Параметром каждого из этих методов является путь к каталогу – path. Применяя эти методы, необходимо проверять наличие или отсутствие папки перед выполнением операции. Приведем два примера: первым из них проиллюстрируем процесс создания новой папки C:TempFolder, используя обработчик ошибок; во втором – удаления папки.
Создание папки:
path="C:\TempFolder"
Temp=""
Set user=WScript.CreateObject("Scripting.FileSystemObject")
If user.FolderExists(path)=0 then
user.CreateFolder(path)
Temp= "Folder " + path + " Created "
Else
Temp= "Folder " + path + " Already Exists"
End If
MsgBox Temp
Удаление папки:
path="C:\TempFolder"
Temp=""
Set user=WScript.CreateObject("Scripting.FileSystemObject")
If user.FolderExists(path)<>0 then
user.DeleteFolder(path)
Temp= "Folder " + path + " Deleted"
Else
Temp= "Folder " + path + " is Absent "
End If
MsgBox Temp
Программное создание и удаление совместно используемого ресурса
Для управления совместно используемыми ресурсами используется контейнер LanmanServer (см. таблицу 2).
Таблица 2. Описание параметров контейнера LanmanServer
Поддерживаемые свойства
|
Тип данных
|
Описание
|
CurrentUserCount
|
Строка
|
Количество пользователей, одновременно работающих с ресурсом в настоящее время
|
|
Строка
|
Описание ресурса
|
HostComputer
|
Строка
|
Название рабочей станции, на которой расположен ресурс, предоставленный в общее пользование
|
Path
|
Строка
|
Путь в формате UNC
|
MaxUserCount
|
Число
|
Максимальное количество одновременно подключенных пользователей
|
Создание совместно используемого ресурса осуществляется с помощью метода Create. В свойствах метода указывается тип создаваемого ресурса, в данном случае fileshare, и название ресурса (ShareName). Метод Create обязательно сопровождается методом Path, с помощью которого задается путь к ресурсу, и методом SetInfo, который сохраняет сделанные изменения. Пример, в котором предоставим в общее пользование папку, локальный путь к которой «c:folder001». Сетевой путь папки должен быть «1000pcShare1». Описание папки – «Shared Folder #1»:
Set PC_Name="1000pc"
Set Share_Name="Share1"
Set Folder_Path="c:\Folder1"
Set Description_Name="Shared Folder #1"
Set object=GetObject("WinNT://" & short_winnt_name &"/" & PC_Name &"/LanmanServer")
Set element=object.Create("fileshare", Share_Name)
element.Path= Folder_Path
element.Description= Description_Name
element.MaxUserCount =10
element.SetInfo
Для удаления используемого ресурса вместо метода Create используют Delete. Изменения вступают в силу немедленно:
Set PC_Name="1000pc"
Set Share_Name="Share1"
Set Folder_Path="c:\Folder1"
Set Description_Name="Shared Folder #1"
Set object=GetObject("WinNT://" & short_winnt_name &"/" & PC_Name &"/LanmanServer")
Call object.Delete("fileshare", Share_Name)
Управление правами доступа на файлы и папки
Создав домашний каталог для пользователя, рекомендуется изменить созданные по умолчанию права. Оставив права Full Control членам группы Domain Administrators и самому пользователю – права Modify.
Библиотека ADsSequrity.dll
Программное управление правами доступа к файлам и папкам можно реализовать с помощью библиотеки ADs-Sequrity.dll, входящей в комплект поставки ADSI Resource Kit (http://www.microsoft.com/ntserver/nts/downloads/other/ADSI25/default.asp).
Перед использованием библиотеки ее необходимо зарегистрировать на компьютере, на котором будет запускаться сценарий. Команда регистрации библиотеки выглядит следующим образом:
regsvr32.exe /s ADsSequrity.dll
Доступ к вышеуказанной библиотеке осуществляется с помощью функции CreateObject(«ADsSecurity») по следующему сценарию:
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\folder")
Set dacl = sd.DiscretionaryAcl
For Each ace In dacl
Wscript.Echo cstr(ace.Trustee)+" " + cstr(ace.AccessMask) + " " + cstr(ace.AceType) + chr(13)+chr(10)
Next
Wscript.Echo dacl.AceCount
Как видно из примера, для управления правами необходимо создать новый экземпляр объекта ADsSecurity и указать к нему путь, который является параметром функции GetSecurityDescriptor(). Таким образом, можно получить доступ к коллекции DiscretionaryAcl, членами которой являются Trustee, AccessMask, AceType, AceCount и не фигурирующий в данном шаблоне RemoveAcl (см. таблицы 3-5).
Таблица 3. Объекты коллекции DiscretionaryAcl
Параметр
|
Описание
|
Trustee
|
Объект (пользователь или группа), которому определяется уровень доступа
|
AccessMask
|
Определяет уровень доступа к ресурсу (Full Control, Modify, Read, Execute и т. д.)
|
RemoveAcl
|
Удаление существующего объекта (группы или пользователя)
|
AceType
|
Определяет тип доступа (Allow, Deny, Audit)
|
AceCount
|
Количество объектов, которым назначены права
|
Таблица 4. Возможные значения параметра AceType
Таблица Type
|
Flag
|
Deny
|
&h1
|
Allow (Full Control)
|
&h0
|
Audit
|
&h2
|
Таблица 5. Набор возможных атрибутов
Установка атрибута
|
Фактические атрибуты
|
.AccessMask
|
.AceFlags
|
Full Control
|
Full Control
Modify
Read & Execute
List Folder Contents
Read
Write
|
&h10000000
|
&h3
|
Modify
|
Modify
Read & Execute
List Folder Contents
Read
Write
|
&h20, &h10000, &h80000000, &h40000000
|
&h3
|
Read & Execute
|
Read & Execute
List Folder Contents
Read
|
&h20000000+&h80000000
|
&h2
|
List Folder Contents
|
List Folder Contents
|
&h20000000+&h80000000
|
&h3
|
Read
|
Read
|
&h80000000
|
&h3
|
Write
|
Write
|
&h2, &h4, &h10, &h100
|
&h3
|
Добавление новых объектов
В качестве новых объектов могут выступать пользователи или группы. Приведем пример добавления нового пользователя:
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\Folder")
Set dacl = sd.DiscretionaryAcl
Set ace = CreateObject("AccessControlEntry")
ace.Trustee = "Domain\Administrator"
ace.AccessMask = &h20000000
ace.AceType = &h0
ace.AceFlags = &h3
dacl.AddAce ace1
sd.DiscretionaryAcl = dacl
sec.SetSecurityDescriptor sd
set dacl=nothing
set sec=nothing
Если требуется добавить сразу несколько новых объектов, то необходимо учесть некоторые нюансы, о которых подробнее читайте после примера:
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\Folder")
Set dacl = sd.DiscretionaryAcl
Set ace1 = CreateObject("AccessControlEntry")
ace1.Trustee = "domain\user1"
ace1.AccessMask = &h20000000
ace1.AceType = &h0
ace1.AceFlags = &h3
dacl.AddAce ace1
for i=0 to 10000000
next
Set ace2 = CreateObject("AccessControlEntry")
ace2.Trustee = "domain\user2"
ace2.AccessMask = &h20000000
ace2.AceType = &h0
ace2.AceFlags = &h3
dacl.AddAce ace2
sd.DiscretionaryAcl = dacl
sec.SetSecurityDescriptor sd
set dacl=nothing
set sec=nothing
Внимательно изучив пример, можно обнаружить две особенности:
- Для каждого нового добавляемого объекта необходимо создать свой собственный объект AccessControlEntry, при этом описание объекта GetSecurityDescriptor и ADsSecurity у них может быть общим.
- После добавления нового объекта должно пройти некоторое время (особенно, если сценарий находится на одном сервере, a объект, права доступа на который необходимо изменить, на другом), прежде чем он станет доступен для последующих действий. Для этого необходимо сделать в сценарии паузу. Поскольку в VBScript не существует такой функции, то предлагается использовать следующую:
Q = Timer + x ‘ x – количество секунд задержки
Do
Loop Until Timer >= Q
Удаление существующих объектов
Удаление существующих групп или пользователей осуществляется с помощью свойства RemoveAcl коллекции объектов DiscretionaryAcl.
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\2")
Set dacl = sd.DiscretionaryAcl
For Each ace In dacl
If (ace.Trustee="EveryOne")
dacl.RemoveAce ace
end if
Next
sd.DiscretionaryAcl = dacl
set dacl=nothing
set sec=nothing
Таким образом, часть сценария, отвечающая за домашний каталог пользователя, выглядит следующим образом:
If Not FS.FolderExists(strFolder&user.name) Then
FS.CreateFolder(strFolder&user.name)
End If
On Error Resume Next
ShareServiceObj.Delete "Fileshare", user.name&"$"
set NewShare = ShareServiceObj.Create("Fileshare",user.name&"$")
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://"& strShare)
Set dacl = sd.DiscretionaryAcl
For Each ace In dacl
If (ace.Trustee="EveryOne")
dacl.RemoveAce ace
end if
Next
Set ace1 = CreateObject("AccessControlEntry")
Ace1.Trustee = short_winnt_name +" \ "+ user.name
ace1.AccessMask = &h10000000
ace1.AceType = &h0
ace1.AceFlags = &h3
dacl.AddAce ace1
for i=0 to 10000000
next
Set ace2 = CreateObject("AccessControlEntry")
ace2.Trustee = short_winnt_name +" \ "+ user.name
ace2.AccessMask = &h20+&h1000+&h40000000+&80000000
ace2.AceType = &h0
ace2.AceFlags = &h3
dacl.AddAce ace2
sd.DiscretionaryAcl = dacl
sec.SetSecurityDescriptor sd
set dacl=nothing
set sec=nothing
NewShare.Path = strShare&user.name
NewShare.MaxUserCount = 10
NewShare.setinfo
С помощью созданного сценария можно легко корректировать свойства доменных пользователей, входящих или исключенных из группы. Данный скрипт принесет огромную пользу при переносе домашних каталогов с одного сервера на другой, при миграции из одного домена в другой.