Иван Коробко
В предыдущей статье были рассмотрены теоретические аспекты построения
Active Directory и проведен обзор доступных провайдеров, с помощью которых
можно программно управлять Active Directory. Одним из таких провайдеров
является WinNT, основы программирования которого будут рассмотрены в данной
статье.
Объектная модель провайдера
WinNT
Рассмотрим программное управление ADSI с помощью провайдера WinNT, с помощью
которого осуществляется доступ к классам. Каждый класс содержит один или
несколько подклассов. Объектная модель протокола WinNT, в которой перечислены
только классы, приведена на рисунке 1.

Рисунок 1
Доступ к объектам по протоколу WinNT описывается
запросом, имеющим вид:
WinNT:[//DomainName[/ComputerName[/ObjectName[,ClassName]]]]
Доступ к провайдеру WinNT
осуществляется по одному из шаблонов:
1) Название
класса содержится в запросе. С помощью функции GetObject формируется запрос,
который включает в себя четыре параметра: название протокола – WinNT, имя домена
– DomainName, рабочей станции – ComputerName, название объекта – ObjectName,
название класса – ClassName. В этом случае доступ к подклассам осуществляется с
помощью цикла For. На VBScript в общем виде запрос выглядит следующим образом:
Пример 1а)
Set
obj=GetObject("WinNT://" & DomainName & "/" &
ComputerName & "/" & ObjectName & "," &
ClassName).
For Each element In obj
element.value
Next
Параметры
ComputerName и ObjectName могут отсутствовать в том случае, если осуществляется
поиск объектов.
2) Подключение
к классу с помощью фильтра. Метод по своей сути аналогичен предыдущему. Такой
способ доступа к данным позволяет значительно увеличить скорость исполнения
скрипта.
Пример 1б)
Set obj =
GetObject("WinNT://" & DomainName)
obj.Filter = Array("user")
For Each element In obj
element.value
Next
Приведем два примера: в первом примере будет
осуществляться поиск объектов класса и вывод свойств этих объектов, во втором –
чтение и вывод свойств заданного объекта. В первом примере с помощью скрипта на
VBScript будут определены учетные записи пользователей домена и прочитаны их
имена:
Пример 2а). Первый способ
доступа к объектной модели
strDomain="MyDomain"
Set Computer
=GetObject("WinNT://" & strDomain & ",user")
For Each User in
Computer
users_d=users_d
& " "& User.Name & chr(13)
Next
Wsh.Echo users_d
Пример 2б) Второй способ
доступа к объектной модели
strDomain="MyDomain"
Set Computer
=GetObject("WinNT://" & strDomain)
Computer.Filter =
Array("user")
For Each User in
Computer
users_d=users_d
& " "& User.Name & chr(13)
Next
Wsh.Echo users_d
Во втором примере явным образом задается имя
пользователя и осуществляется чтение его свойств:
Пример 3a). Первый способ
доступа к объектной модели
strDomain="MyDomain"
strUser="MyUserName"
Set Computer
=GetObject("WinNT://" & strDomain & "/" &
strUser & ",user")
users_d= User.Name
& chr(13)
Wsh.Echo users_d
Пример 3б). Второй способ
доступа к объектной модели
strDomain="MyDomain"
Set Computer
=GetObject("WinNT://" & strDomain)
Computer.Filter =
Array("user")
For Each User in
Computer
users_d=
User.Name & chr(13)
Next
Wsh.Echo users_d
Чтобы эффективно пользоваться объектной моделью,
необходимо знать назначение классов, какие они включают в себя подклассы и
какие параметры имеют подклассы. Назначение и название каждого класса приведено
в таблице 1:
Таблица 1
|
objectClass
|
Описание класса
|
|
Domain
|
Класс предназначен для подключения к домену.
Явное использование домена экономит сетевой трафик.
|
|
Computer
|
Класс предназначен для определения роли компбютера в
домену,
управления компьютера.
|
|
User
|
Осуществляется управление пользователями: создание,
удаление.
Управление свойствами пользователя: активизация
пользователя, подключение домашнего каталога или сценария загрузки;
управление параметрами, касающихся пароля; Чтение характеристик пользователя:
описание, расположение, телефон и др. параметры.
|
|
Group
|
Управление группами: создание локальных/глобальных групп,
преобразование типов групп, определение членства в группах
и т.д.
|
|
FileShare
|
Управление файловыми ресурсами: предоставление ресурсов
пользователям.
|
|
PrintQueue
|
Управление локальным принтером: перезагрузка принтера,
его приостановка, возобновление работы; чтение полей
принтер.
|
|
PrintJobs
|
Подкласс класса PrintQueue, с помощью которого осуществляется
управление очередью печати: установка приоритетов заданий, управление
заданиями.
|
Соответствия классов и подклассов приведено в
таблице 2:
Таблица 2
|
Название класса
|
Описание класса
|
|
Namespace
|
Контейнер верхнего уровня
|
|
Domain
|
Доступные домены Windows
|
|
User
|
Управление пользователем
|
|
Group
|
|
|
UserGroupCollection
|
Управление группами пользователей
|
|
GroupCollection
|
Управление другими группами
|
|
Computer
|
Определение параметров компьютера
|
|
PrintJob
|
|
|
PrintJobsCollection
|
Управление заданием
|
|
PrintQueue
|
Управление принтером
|
|
Service
|
|
|
FileService
|
|
|
FileShare
|
Управление предоставлением объектов в общее пользование
|
|
Resource
|
Управление сервисами
|
|
Session
|
Управление сессиями
|
|
User
|
Управление локальными учетными записями пользователей
|
|
Group
|
|
|
UserCollection
|
Свойства локальных пользователей
|
|
GroupCollection
|
Свойства локальных групп
|
Из объектной модели протокола WinNT видно, что в
пространстве имен NameSpace существует всего два класса: Domain и Computer.
Рассмотрим каждый из этих классов в отдельности.
Класс Domain
Определение доступных доменов
Класс Domain является верхним уровнем пространства имен, поэтому для
определения доступных доменов в функции GetObject() ограничиваются название
протокола. Необходимо помнить, что название протокола должно быть написано
именно WinNT – в противном случае сценарий выдаст ошибку:
Пример 4
Set
obj=GetObject("WinNT:")
For Each element In obj
temp=element.Name
Next
MsgBox temp

Чтение параметров класса Domain
Класс Domain включает в себя восемь параметров. Все эти параметры задаются в
групповых политиках, за исключением параметра Name. Описание параметров см. в
Приложении.
При создании скрипта на VBScript необходимо
помнить, что VBScript не преобразует типы данных автоматически, поэтому
числовые данные необходимо преобразовывать в строковые с помощью функции
cstr().
Пример 5. Чтение всех полей
класса Computer
Set
obj=GetObject("WinNT:")
For Each element In obj
t1="Name: " +
cstr(element.Name)+chr(13)
t2="MinPasswordLength:
"+ cstr(element.MinPasswordLength)+chr(13)
t3="MinPasswordAge:
" + cstr(element.MinPasswordAge)+chr(13)
t4="MaxBadPasswordsAllowed:
"+ cstr(element.MaxBadPasswordsAllowed)+chr(13)
t5="AutoUnlockInterval:
" + cstr(element.AutoUnlockInterval)+chr(13)
t6="LockoutObservationInterval:
" + cstr(element.LockoutObservationInterval)
temp=temp+t1+t2+t3+t4+t5+t6+chr(13)+chr(13)
Next
MsgBox temp

Значения MinPasswordAge и MaxPasswordAge
указываются в групповых политиках в днях, поэтому необходим перевод в дни, для
чего полученное число необходимо разделить на 86400; значения MinPasswordAge и
LockoutObservationInterval указываются в групповых политиках в минутах, поэтому
полученные значения необходимо разделить на 60.
Обновление параметров класса
Domain
Установка новых параметров перечисленных значений осуществляется с помощью
метода SetInfo.
Пример 6. Изменение значения
минимальной длины пароля в домене (NewLenght=10)
NewLenght=10
Set
obj=GetObject("WinNT:")
For Each element In obj
element.MinPasswordLength=
NewLenght
obj.SetInfo
temp ="NEW:
MinPasswordLength: "+ cstr(element.MinPasswordLength)+chr(13)
Next
MsgBox temp
Перечисление объектов класса
Domain
Просмотр содержимого контейнера осуществляется с помощью конструкции For в
соответствии с приведенным ниже шаблоном. В качестве значения переменной
Container может быть имя домена или компьютера:
Пример 7
Container="Value"
Set obj=GetObject("WinNT://"&
Container)
For Each element In obj
temp = temp +
element.name + "; "
Next
MsgBox temp
Такой метод перечисления объектов будет
возвращать все содержимое любой базы SAM – контроллера домена, сервера или
рабочей станции.
В приведенном примере возвращались объекты всех
классов, содержащиеся в домене (или в локальной базе SAM), поскольку тип
объектов не определялся. Поскольку в домене огромное количество объектов, для
увеличения скорости работы скрипта целесообразно использовать фильтр. Фильтр
может в себя включать следующие объекты:
Таблица 3
|
Объект
|
Описание
|
Объект
|
Описание
|
|
User
|
Учетная запись
пользователя
|
Group
|
Все группы
|
|
Computer
|
Учетная запись
компьютера
|
LocalGroup
|
Локальная группа
|
|
Service
|
Сервис
|
GlobalGroup
|
Глобальная группа
|
Пример 8: Определение всех
учетных записей пользователей, входящих в домен
Set objDomain=GetObject("WinNT:")
For Each
domain_element In objDomain
Domain_Name=
domain_element.Name
Next
Set obj=GetObject("WinNT://"
& Domain_Name)
obj.filter=array("user")
For
Each element In obj
temp
=temp+element.name+"; "
Next
Создание, переименование и
удаление объектов в домене
В Active Directory существует три типа встроенных объектов: учетная запись
пользователя; группа, которая может быть локальной или глобальной; учетная
запись компьютера. С учетной записью пользователя можно проделывать следующие
операции: создавать, удалять, переименовывать; группу можно создавать и
удалять; учетную запись компьютера можно создавать и удалять.
Создание объектов
Создание учетной записи пользователя осуществляется с помощью функции
Create(). Приведем пример, в котором создается учетная запись пользователя с
именем UserName. При создании скрипта манипуляции с паролем и другими
параметрами учетной записи должны производиться, когда учетная запись
существует, т.е. после применения метода: SetInfo.
Пример 9
Set
objDomain=GetObject("WinNT:")
For Each domain_element
In objDomain
Domain_Name=
domain_element.Name
Next
Set
obj=GetObject("WinNT://" & Domain_Name)
NewUser="UserName"
Set
CU=obj.Create("User",NewUser)
CU.SetInfo
Создание учетной записи группы отличается тем,
что необходимо указать тип группы с помощью функции Put(). Локальной группе
соответствует значение «4», глобальной – «2».
Пример 10. Создания локальной
группы с именем GroupName
Set
objDomain=GetObject("WinNT:")
For Each domain_element
In objDomain
Domain_Name=
domain_element.Name
Next
Set
obj=GetObject("WinNT://" & Domain_Name)
NewGroup="GroupName"
Set
CG=obj.Create("Group",NewGroup)
CG.Put
"groupType", 4
CG.SetInfo
Создание учетной записи
компьютера аналогично созданию учетной записи пользователя, за исключением
следующего:
n объект должен быть создан с использованием класса
computer;
n у объекта должен быть установлен
пользовательский флаг Ошибка! Недопустимый объект гиперссылки. (см. раздел
«Манипулирование пользовательскими флагами функцией UserFlags»);
n начальный пароль учетной записи должен
соответствовать имени компьютера, введенного строчными буквами. Результата
добиваются с помощью функции LCase().
Пример 11. Создания учетной
записи компьютера с именем ComputerName
Set
objDomain=GetObject("WinNT: ")
For Each domain_element
In objDomain
Domain_Name= domain_element.Name
Next
Set
obj=GetObject("WinNT://" & Domain_Name)
NewComputer="ComputerName"
Set
CC=obj.Create("Computer", UCase(NewComputer))
CC.SetInfo
Set CAccount=
GetObject("WinNT://" & ї
Domain_Name&"/"&
NewComputer&"$,user")
CAccount.Put
"UserFlags", (CAccount.Get("UserFlags") Or &H1000)
CAccount.SetPassword(LCase(NewComputer))
CAccount.SetInfo
Удаление объектов
Все три типа объектов удаляются, используя метод Delete. Приведем шаблон, в
котором переменная ClassName может принимать значение computer, user, group;
NameOfObject – имя удаляемого объекта:
Пример 12
Set
objDomain=GetObject("WinNT: ")
For Each domain_element
In objDomain
Domain_Name=
domain_element.Name
Next
Set
obj=GetObject("WinNT://" & Domain_Name)
ClassName="____"
NameOfObject="____"
Set
CC=obj.Delete (ClassName, NameOfObject)
Обратите внимание, что объект удаляется
немедленно и использовать метод SetInfo не нужно.
Переименование объектов
Среди трех ранее перечисленных объектов переименованию поддается только
учетная запись пользователя. Переименование учетной записи осуществляется с
помощью функции MoveHere():
Пример 13
Set
objDomain=GetObject("WinNT: ")
For Each domain_element
In objDomain
Domain_Name=
domain_element.Name
Next
OldUserName="____"
NewUserName="____"
Set
obj=GetObject("WinNT://" ї
&
Domain_Name&"/"& OldUserName&",user")
obj.MoveHere(User.AdsPath, NewUserName)
obj.Nothing
Подкласс User
Учетные записи пользователей домена содержатся в подклассе User. Подкласс
включает в себя более 20 параметров, некоторые из которых не поддерживаются
Windows 2k. Описание параметров см. в Приложении. Параметры подкласса
изначально задаются в групповых политиках.
Пример 14. Чтения параметров
подкласса User
Set obj=GetObject("WinNT:")
For Each str In obj
DomainName=str.Name
Next
Set
UserName="Value"
Set
element=GetObject("WinNT://" & DomainName &
"/"& UserName)
u1="FullName: "+
cstr(element.FullName)+chr(13)
u2="UserFlags: "+
cstr(element.UserFlags)+chr(13)
u3="LoginScript: "+
cstr(element.LoginScript)+chr(13)
u4="MaxBadPasswordsAllowed:
"+ cstr(element.MaxBadPasswordsAllowed)+chr(13)
u5="PasswordHistoryLength:
"+ cstr(element.PasswordHistoryLength)+chr(13)
u6="AutoUnlockInterval:
"+ cstr(element.AutoUnlockInterval)+chr(13)
u7="PasswordAge: "+
cstr(element.PasswordAge)+chr(13)
u8="PasswordExpired:
"+ cstr(element.PasswordExpired)+chr(13)
temp=""
temp=u1+u2+u3
Манипулирование
пользовательскими флагами функцией UserFlags
Для просмотра и изменения состояния пользовательских флагов в базе SAM
применяются методы Get() и Put(), соответственно. Ниже приведены константы и их
описание. Константы представляют собой шестнадцатеричные значения флагов:
Таблица 4
|
Название
|
Значение
|
Описание
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0001
|
Управление исполнения сценария загрузки
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0002
|
Управление флагом «Account is Disable»
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0003
|
Требуется домашний каталог
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0010
|
Управление блокировкой учетной записи
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0020
|
Не требуется пароль для регистрации в сети
и на локальном компьютере
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0040
|
Управление флагом «User Cannot Change
Password»
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0080
|
Разрешить пользователя отправлять зашифрованный пароль
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0100
|
Этот флаг обеспечивает пользователям доступ пользователя в
текущем домене, но не дают
им права доступа в домены, которые имеют доверительные
отношения с текущим доменом. Для данного домена учетная запись становится
локальной.
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0200
|
Типичная учетная запись пользователя
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X0800
|
Флаг, противоположный флагу Ошибка! Недопустимый объект
гиперссылки. Делает учетную запись глобальной
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X1000
|
Управление членством в домене рабочей станции
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X2000
|
Учетная запись компьютера BDC
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X10000
|
Управление флагом «Password Never
Expires»
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X20000
|
Учетная запись MNS Logon
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X40000
|
Необходимо использовать Smart-карту для регистрации
пользователя в сети
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X80000
|
Установка делигирования
|
|
Ошибка! Недопустимый объект гиперссылки.
|
0X100000
|
Флаг, противоположный Ошибка! Недопустимый объект
гиперссылки.
|
Обратите внимание, что в таблице
нет флага для параметра «User Must Change Password at Next Logon». Для
установки флага следует менять значение свойства PasswordExpired. О том, как
это сделать, речь пойдет позже. Для просмотра и изменения шестнадцатеричных
флагов используют операторы Or, Xor и And следующим образом:
n оператор Or – для начальной установки бита. На
практике используется в случае создания новой учетной записи пользователя;
n оператор Xor – для переключения статуса флага.
Флаг может быть активизирован и дезактивирован;
n оператор And – для просмотра значения,
хранящегося в базе SAM.
Для просмотра значения флага используется функция
Get(). Рассмотрим пример, в котором прочитаем значение параметра
ADS_UF_DONTEXPIREPASSWD – управление флагом «Password Never Expires»:
Пример 15
Set
obj=GetObject("WinNT:")
For Each str In
obj
DomainName=str.Name
Next
Set
UserName="Value"
temp=""
Set
element=GetObject("WinNT://" & DomainName &
"/"& UserName)
flag=element.Get("UserFlags")
if (flag AnD
&H10000)<>0 then
temp="Флаг
установлен"
else
temp="Флаг
не установлен"
end if
MsgBox temp
Для изменения значения флага используется функция
Put(), которая имеет следующий формат: value.Put «UserFlags» String. Рассмотрим
использование данной функции на примере, в котором изменим значение параметра на
противоположное ADS_UF_DONTEXPIREPASSWD. Для того чтобы изменения вступили в
силу, необходимо использовать метод value.SetInfo.
Пример 16
Set
obj=GetObject("WinNT:")
For Each str In
obj
DomainName=str.Name
Next
ADS_UF_DONTEXPIREPASSWD=&H0040
Set
UserName="Value"
Set
element=GetObject("WinNT://" & DomainName &
"/"& UserName)
element.put
"userFlags", element.Get("UserFlags") Xor
ADS_UF_DONTEXPIREPASSWD
element.setinfo
MsgBox
element.get("UserFlags")
Подкласс Group
Подкласс Group включает в себя 2 параметра: описание и SID группы. Чтение
этих параметров происходит аналогичным способом, описанным в предыдущем
разделе. Изменение описание группы осуществляется использованием метода
SetInfo.
Взаимосвязь учетных записей
пользователей и групп
В этом параграфе будут рассмотрены вопросы добавления и исключения учетной
записи пользователя из группы членства пользователей в группе, принадлежность
пользователя к группам.
1) Добавление пользователя в группу осуществляется
с помощью функции Add(), для удаления пользователя – функция Remove(). При
использовнии метода Add() чтобы изменения вступили в силу, необходимо
использовать метод SetInfo. Удаление учетной записи пользователя из группы
происходит сразу после вызова метода Remove.
Пример 17. Добавление учетной
записи Value_Name в группу Value_Group
Set
obj=GetObject("WinNT:")
For Each str
In obj
DomainName=str.Name
Next
Set
UserName="Value_Name"
Set
GroupName="Value_Group"
Set element_user=GetObject("WinNT://"
& DomainName & "/"& UserName & ", user")
Set
element_group=GetObject("WinNT://" & DomainName &
"/"& GroupName & ", group")
element_group.Add(element_user.ADsPath)
element_group.SetInfo
Для удаления учетной записи из группы в
приведенном примере последние две строки необходимо заменить на строку
element_group.Remove(element_user.ADsPath).
2) Для перечисления всех пользователей группы,
например, группы GroupName, используют свойство Members:
Пример 18
Set
obj=GetObject("WinNT:")
For Each str
In obj
DomainName=str.Name
Next
Set
GroupName="Value_Group"
Set
element_group=GetObject("WinNT://" & DomainName &
"/"& GroupName & ", group")
For each obj
inGroup.Members
temp=temp+Member.Name
Next
MsgBox temp
3) Просмотр списка групп, к которой принадлежит
пользователь. Использующийся в данном примере метод ISMember возвращает
значение типа Boolean, т.е. True/False. Сценарий условно можно разделить на три
части – определение текущего домена, определение списка групп в домене и
проверка членства в группе.
Пример 19
Set
objDomain=GetObject("WinNT: ")
For Each domain_element
In objDomain
Domain_Name=
domain_element.Name
Next
UserName="Administrator"
Set
element_user=GetObject("WinNT://" & DomainName &
"/"& UserName)
Set
obj=GetObject("WinNT://" & DomainName)
obj.filter=array("group")
For Each element
In obj
Set
element_group=GetObject("WinNT://" & DomainName&
"/"& element.name )
if
element_group.IsMember (element_user.ADsPath)="True" then
temp