Рубрика:
Администрирование /
Администрирование
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
Вадим Андросов
Синхронизация ACL и структуры организации Часть 1
В статье описывается создание надстройки для операционной системы Windows Server 2003, позволяющей эффективно совместно использовать два ее основных механизма разграничения доступа: на основе структуры организации и списков контроля доступа (ACL). В итоге основная работа по управлению доступом к защищаемым ресурсам сводится к поддержанию адекватной структурной модели организации.
Постановка задачи
Операционная система Windows Server 2003 позволяет создавать модели структуры организации, однако содержит довольно ограниченные средства использования подобных моделей для защиты корпоративных информационных систем. Главная причина этому – сложность и уникальность правил защиты на различных предприятиях. Все разнообразие подходов операционная система поддерживать не может. Однако она содержит мощные средства расширения своей функциональности. Их использование было рассмотрено в октябрьском номере журнала [1].
Windows Server 2003 предоставляет стандартную для операционных систем своего класса возможность разграничения прав доступа на основе списков доступа. Обычно учетные записи пользователей для повышения удобства и гибкости администрирования объединяются в группы, и права на доступ к различным объектам предоставляются именно группам. Это нужный и часто используемый механизм, однако он лежит в плоскости, ортогональной организационной структуре предприятия. Объединение пользователей в группы никак не связано с их принадлежностью определенной организационной единице.
Так что в результате мы получаем два мощных механизма, которые, однако, нелегко использовать согласованно, особенно для обеспечения безопасности в организациях со сложной структурой. Цель статьи – обеспечить возможность совместного использования структуры предприятия и списков контроля доступа. Защита основных элементов информационной системы должна осуществляться преимущественно на основе организационной структуры предприятия. Изначально строится модель структуры, и распределяются права (случаи, когда доступ к объектам имеют все сотрудники определенного отдела, очень распространены). Затем главной задачей администратора должна стать поддержка адекватной модели структуры организации. Другими словами при переходе пользователя из одного отдела в другой системный администратор не должен вручную переназначать ему все необходимые права – достаточно переместить объект пользователя в нужную организационную единицу. Еще одно требование к разрабатываемым механизмам: они не должны препятствовать использованию стандартных процедур назначения прав при реализации прав доступа, не соответствующих структуре предприятия.
Под моделью будем понимать объект, в достаточной степени повторяющий свойства моделируемого объекта. В статье рассматривается организационная подсистема предприятия, которая может быть в достаточной для решаемой задачи степени смоделирована с помощью штатных средств Windows 2003 Server, а именно средствами Active Directory. Так, используя оснастку Active Directory Users and Computers, можно задать структуру организации, а также принадлежность пользователей и рабочих станций определенным подразделениям. Требуется лишь незначительная доработка стандартной схемы Active Directory для реализации прикрепления групп безопасности к организационным единицам. Сначала сформулируем основные идеи совместного использования модели организационной структуры предприятия и списков контроля доступа.
В статье будут описаны два уровня взаимосвязи списков контроля доступа и структуры организации. Основная идея заключается в существовании специальной группы пользователей, прикрепленной к организационной единице. При добавлении нового пользователя в отдел он будет автоматически регистрироваться и в этой группе. Аналогично удаление пользователя из организационной единицы должно приводить к его автоматическому удалению также из группы. В результате в рамках домена будет существовать набор групп, состав которых соответствует персоналу отдела. Поддержка вручную подобной функциональности возможна (более того, в подавляющем числе случаев она именно так и осуществляется), но связана с большим количеством рутинных действий, что чревато ошибками, особенно при условии высокого уровня динамики структуры предприятия. Другая проблема – масштабные изменения организации, когда меняется позиция отдела или целого поддерева. Важно обеспечить единое место редактирования структуры организации.
Первый уровень синхронизации – это создание группы, которая будет автоматически включать всех пользователей, принадлежащих своей организационной единице. Это самый примитивный уровень соответствия, который, однако, позволит существенно повысить удобство разграничения доступа к ресурсам на уровне отдельных отделов.
Следующий уровень – группа, содержащая пользователей текущего отдела и всех его дочерних подразделений. То есть группа, представляющая поддерево. С ее помощью можно реализовать более сложные правила разграничения доступа к ресурсам.
Отмечу, что добавленная функциональность никак не затронет стандартных способов использования пользовательских групп. Администратор и далее будет иметь возможность создавать любое количество групп для реализации правил разграничения доступа, не соответствующих структуре организации.
Особенности функционирования
Первым делом определим механизм прикрепления групп организационным единицам. Первый вариант – на основе имени. В каждом отделе будут существовать по две группы с названиями вида «Название_отдела_Group_Single» и «Название_отдела_Group_Subtree». Таким образом, можно получить удобный механизм связывания, как с точки зрения программирования, так и использования. Однако такое решение является недостаточно гибким. Администратор может предпочесть другую схему именования. Поэтому нужно предоставить альтернативный способ привязки групп к организационным единицам, оставив, однако, приведенный способ именования в качестве решения по умолчанию.
Добавим в класс «Организационная единица» атрибуты для идентификации привязанных групп. Их понадобится два:
- groupSingle – для группы с пользователями одной организационной единицы;
- groupTree – для группы, включающей пользователей поддерева структуры организации, начиная с указанной единицы.
Теперь нужно определить, какой атрибут группы можно использовать в качестве указателя. Воспользуемся утилитой WMI CIM Studio, которую можно бесплатно загрузить с сайта Microsoft [2].
Для указателя нам потребуется атрибут, уникальным образом идентифицирующий пользовательскую группу. Из рис. 1 видно, что для групп в операционной системе используется составной ключ, состоящий из двух полей: имени домена и группы. Если предположить, что мы работаем в пределах одного домена, имя группы будет ее уникальным идентификатором. Для случая использования нескольких доменов можно воспользоваться ссылкой вида <Имя группы>@<Имя домена>, например «management@dynamic.ua».
Рисунок 1. Атрибуты класса Win32_Group
Итак, ссылка может быть строкового типа и содержать имя группы. Однако такое решение сильно затруднит переименование объектов (придется отслеживать операции переименования и обновлять связи). Существует другое поле, уникальным образом идентифицирующее объект – GUID [7]. Тип этого свойства: Octet String. Оно является системным и не предназначено для непосредственного редактирования пользователями. Поэтому для связи с группами более удачным решением является использование ссылки на GUID группы. Привязанные группы можно будет при необходимости удалить – в этом случае значением ссылки будет пустое значение. Ссылку будем хранить в формате юникодной строки, так как присваивание объектов типа Octet String должным образом не реализовано. Кроме того, для поиска объектов с помощью LDAP-запросов все равно требуется строковое представление GUID.
Иногда нужно не включать сотрудников некоторых отделов поддерева к общим ресурсам. Например, в финансовое подразделение предприятия входят бухгалтерия, плановый отдел, отдел сбыта и вспомогательный персонал. С одной стороны было бы удобно назначить права доступа к общим ресурсам (финансовой документации) сразу всему финансовому подразделению. Но с другой, отдел «Вспомогательный персонал» не нуждается в подобном доступе. Поэтому должна быть возможность исключения из поддерева некоторых отделов.
Сначала рассмотрим общий механизм регистрации пользователей в специальных группах. Как уже говорилось, таких групп должно быть два вида: содержащих пользователей текущего подразделения (Single group) и пользователей поддерева отделов с корнем в текущем (Tree group). Предлагаю следующий способ формирования групп типа Tree. В них автоматически включается группа типа Single текущего подразделения и группы типа Tree непосредственных дочерних организационных единиц. Таким образом, нужно будет заботиться только о поддержании связей с ближайшими дочерними подразделениями, делегируя им управление своими потомками. Такой подход организации древовидных структур для представления иерархий часть-целое соответствует распространенному паттерну «Компоновщик» (Composite) [3].
Он позволяет легко отключить определенный отдел от получения прав поддерева – достаточно удалить из его специальной группы типа Tree группу типа Single. При этом мы не потеряем возможность манипулировать разрешениями пользователей этого отдела с помощью одной группы.
На рис. 2 показана диаграмма классов, отражающая логическую организацию надстройки. Физически существуют только объекты класса «User group», классы «Single group» и «Tree group» наследуют его только в смысле другого поведения (другой реакции на события над объектами). Новые классы операционной системы было решено не создавать во избежание излишней сложности.
Рисунок 2. Структура классов модели
Остановимся на вопросе удаления специальных групп. Было решено не блокировать эту возможность, но в этом случае нужно определиться с поведением надстройки. При удалении группы типа Tree все решается просто – ее обязанности берет на себя такая группа родительского подразделения (иначе будет потеряно поддерево, начиная с организационной единицы с удаленной группой). С группой типа Single дела обстоят несколько сложнее. Очевидной реакции здесь назначить нельзя. Остановимся на следующем решении: пользователи отдела с удаленной специальной группой типа Single вообще не будут участвовать в распределении прав на основе структуры организации. Это жесткий подход, однако остальные варианты (когда пользователи этого отдела включались бы в состав группы типа Single или Tree родительского подразделения) могут оказаться неочевидными для администратора, а поэтому чреваты ошибками.
Одной из самых опасных ошибок администратора будем считать предоставление доступа к ресурсам организации пользователям, которые в них не нуждаются. От них и страхует полное исключение пользователей отдела с удаленной группой типа Single из предлагаемого механизма распределения прав доступа. С его помощью доступ к ресурсам разрешается неявно (посредством помещения пользователя в нужную организационную единицу), поэтому важно свести к минимуму вероятность «случайного» предоставления прав.
Отдельно остановимся на вопросе работы со структурами, которые нельзя отнести к строго иерархическим. Поддержку в таких случаях достаточно легко организовать. Например (см. рис. 3), сотрудникам бухгалтерии и производственного отдела может понадобиться общий доступ к специальному виду документации. Для его обеспечения достаточно создать группу, в которую включить группы типа Single или Tree (в зависимости от того, требуется ли предоставить доступ конкретным отделам или целым подструктурам). Предоставив необходимые права данной группе, администратор в дальнейшем будет лишен необходимости работы с нею – достаточно будет поддерживать корректность структурной модели.
Рисунок 3. Пример структуры организации
Рассмотрим наиболее важные вопросы реализации предложенных методов. Сначала нужно расширить схему Active Directory, добавив к объекту «Организационная единица» необходимые атрибуты (groupSingle и groupSubtree). Механизм расширения схемы был рассмотрен в статье [1], поэтому подробно останавливаться на нем не будем. Расширение схемы делается с помощью специальной оснастки «Active Directory Schema» [1, 4].
Программная реализация
В этом разделе рассмотрим сценарии, обеспечивающие конфигурирование надстройки с использованием оснастки Active Directory Users and Computers через новые контекстные меню подобно тому, как это было сделано
в статье [1]. Сценарии, вызываемые в ответ на выбор определенного раздела меню, получают отличительное имя выбранного в оснастке объекта в качестве первого параметра с помощью вызова oArgs.item(0). Мы будем использовать расширенную функцию регистрации новых контекстных меню, так как в отличие от [1] нам потребуются команды не только для организационных единиц, но и для групп.
function operateMenu(operation, className, id, name, criptPath)
Set root= GetObject("LDAP://rootDSE")
sConfig = root.Get("configurationNamingContext")
sPath = "LDAP://cn=" & className & "-Display,cn=409, cn=DisplaySpecifiers," & sConfig
Set obj= GetObject(sPath)
sValue = id & "," & name & "," & scriptPath
vValue = Array(sValue)
obj.PutEx operation, "adminContextMenu", vValue
obj.SetInfo
end function
Для начала создадим промежуточную функцию operateMenu. Она будет использоваться как для добавления новых пунктов меню в оснастку Active Directory Users And Computers, так и для их последующего удаления. Конкретная операция будет определяться первым параметром функции. Для установки нового пункта меню нужно будет воспользоваться следующей функцией:
const ADS_PROPERTY_APPEND = 3
function installMenu(className, id, name, scriptPath)
operateMenu(ADS_PROPERTY_APPEND, className, id, name, scriptPath)
end function
Функция устанавливает контекстное меню для заданного объекта. В качестве первого параметра ей передается имя класса объекта, остальные – аналогичны подобной функции из [1]: идентификатор для определения позиции меню, название и путь к сценарию, выполняемому при вызове команды. Для удобства были определены отдельные функции для подключения меню к соответственно организационным единицам и группам:
function installOUMenu(id, name, scriptPath)
installMenu "organizationalUnit", id, name, scriptPath
end function
function installGroupMenu(id, name, scriptPath)
installMenu "group", id, name, scriptPath
end function
Сначала должны быть разработаны сценарии создания специальных групп. Их вызов будет осуществляться из специальных контекстных меню класса «Организационная единица». Приведу пример сценария добавления группы типа Single, поскольку процесс создания второго типа групп очень похож:
Const ADS_GROUP_TYPE_LOCAL_GROUP = &h4
Const ADS_GROUP_TYPE_SECURITY_ENABLED = &h80000000
set ouObj = getObject(oArgs.item(0))
newGroupName = inputBox("Enter single attached group name", "New attached group", ouObj.ou & "_Group_Single")
if isEmpty(newGroupName) then WScript.Quit
set groupObj = ouObj.create("Group", "cn=" & newGroupName)
groupObj.sAMAccountName = ouObj.ou & "Single"
groupObj.groupType = ADS_GROUP_TYPE_LOCAL_GROUP Or ADS_GROUP_TYPE_SECURITY_ENABLED
groupObj.description = "All users from " & ouObj.ou & " OU"
groupObj.SetInfo
ouObj.groupSingle = groupObj.guid
ouObj.setInfo
При вызове контекстного меню выполняется этот сценарий, первым параметром которому передается отличительное имя (Distinguished Name) текущей организационной единицы [1].
Пользователь получает приглашение ввести название прикрепленной единицы. По умолчанию предлагается название «Имя организационной единицы_Group_Single». В этом месте пользователь еще может отменить операцию, нажав соответствующую кнопку.
Создается группа с заданным именем в текущей организационной единице. Комментарием к новой группе назначается строка «Все пользователи из организационной единицы». И в конце сценария имя новой группы привязывается к организационной единице.
Подробнее остановимся на вопросе об области действия прикрепленных групп [4]. В данном примере используются локальные в домене группы (константа ADS_GROUP_TYPE_LOCAL_GROUP). Они могут включать в себя группы или учетные записи как из своего домена, так и из других. Доступ же с их помощью можно назначить только к объектам своего домена. Есть еще два типа групп. Во-первых, глобальные. С их помощью можно предоставлять доступ к ресурсам в любом домене, однако включать в них можно только группы глобального типа, что может затруднить реализацию надстройки (требование использовать только группы одного типа является слишком ограничивающим). Существует еще один тип групп, который появился в ОС Windows 2000 Server – универсальные. С одной стороны они являются наиболее удобными для описываемой надстройки: позволяют включать группы и назначать доступ к ресурсам в любом домене. Однако широкое использование универсальных групп может негативно сказаться на общей производительности сети, кроме того, их применение возможно только в доменах, работающих в собственном режиме (native mode). В любом случае приведенный пример показывает лишь создание прикрепленной группы с типом по умолчанию – при необходимости администратор сможет самостоятельно присоединить к организационной единице группу необходимого типа (возможность этого будет реализована в дальнейшем).
Обратите внимание, что добавлять группы любого типа в локальные становится возможным только после поднятия функционального уровня домена (Raise Domain Functional Level) до уровня Windows Server 2003 с помощью оснастки Active Directory Domains and Trusts.
Создадим контекстное меню для вывода дополнительных свойств организационной единицы, как это было сделано в [1]. Теперь администратор сможет узнать, какие группы прикреплены (см. рис. 4).
Рисунок 4. Информация о прикрепленных группах
Далее рассмотрим вывод информации об организационной единице на экран. Сценарий вызывается из контекстного меню организационной единицы:
set ouObj = getObject(oArgs.item(0))
singleStr = getGroupName(ouObj.groupSingle)
treeStr = getGroupName(ouObj.groupTree)
msgbox "Single: " & singleStr & chr(10) & "Subtree: " & treeStr, vbInformation, "OU attached groups"
В основе работы сценария лежит функция, определяющая название группы по ее идентификатору. Ниже приведен ее текст. Принцип работы функции прост. Если идентификатор группы – пустое значение, возвращается текст, обозначающий отсутствие прикрепленной группы (none). В противном случае осуществляется поиск объекта на основе GUID:
function isGroupExist(guid)
isGroupExist = Not isEmpty(guid)
end function
function getGroupName(guid)
if isGroupExist(guid) then
set singleGroup = getObject("LDAP://<GUID=" & guid & ">")
getGroupName = singleGroup.cn
else
getGroupName = "none"
end if
end function
Далее рассмотрим вспомогательные сценарии контекстного меню, позволяющие прикрепить произвольную ранее существующую группу к организационной единице, а также отключить группу. Начнем с подключения группы (делается с помощью дополнительного контекстного меню для объектов типа группа):
set groupObj = getObject(oArgs.item(0))
set ouObj = getObject("LDAP://" & getOU(oArgs.item(0)))
if isSomeAttached(ouObj) then
if msgbox("Current organizational unit(" & ouObj.ou & _
") already has attached group(" & _
getGroupName(ouObj.groupSingle) & _
"). Do you wish to unattach this group and " & _
"attach yours(" & groupObj.cn & ") as Single?", _
vbYesNo, "Group already attached") = vbNo _
then WScript.quit
end if
ouObj.groupSingle = groupObj.guid
ouObj.setInfo
msgbox "Group attached as single"
function getOU(dn)
getOU = right(dn, len(dn) - instr(1, dn, ",", vbTextCompare))
end function
function isSomeAttached(ou)
isSomeAttached = isGroupExist(ou.groupSingle)
end function
Работа функций достаточно проста. Вызывается сценарий из контекстного меню группы. В поле организационной единицы groupSingle записывается идентификатор группы. Подключение группы в качестве поддерева будет выглядеть аналогично, только поле для записи GUID будет называться groupTree. Если к организационной единице уже прикреплена группа, сценарий выводит ее название и запрашивает подтверждение на замену.
Также для настройки нам понадобится возможность отключения групп от организационных единиц, когда нам нужно приостановить наблюдение за определенным отделом. Следующий сценарий будет вызываться из контекстного меню организационной единицы:
const ADS_PROPERTY_CLEAR = 1
set ouObj = getObject(oArgs.item(0))
if isSomeAttached(ouObj) then
if msgbox("Attached single group is " & _
getGroupName(ouObj.groupSingle) & _
chr(10) & "Unattach?", vbYesNo, "Unattach...") = vbNo _
then WScript.Quit
ouObj.puEx ADS_PROPERTY_CLEAR, "groupSingle", ""
ouObj.setInfo
else
msgbox "This ou has no attached single groups", vbInformation, "Nothing to unattach"
end if
В ходе выполнения сценария мы просто получаем объект организационной единицы и очищаем ей свойство groupSingle. Делается это с помощью метода putEx, которому передается константа, обозначающая очистку, и название поля.
Теперь отдельно остановимся на операции подключения групп типа Tree. Здесь логика несколько сложнее. Такая группа должна при необходимости «склеить» дерево. Рассмотрим это на примере из рис. 3. Допустим, мы устанавливаем группу типа Tree для подразделения «Учет». Корректное подключение должно сопровождаться следующими действиями. Пусть новая группа называется «Учет_поддерево».
- В подключаемую группу нужно добавить группу типа Single этого подразделения.
- «Учет_поддерево» должна быть добавлена в группу типа Tree родительского подразделения («Производство»).
- В «Учет_поддерево» нужно добавить группы этого типа дочерних подразделений.
Реализуем этот алгоритм в функции подключения группы. Для последующей поддержки перемещения поддеревьев выделим регистрацию дочернего подразделения в родительском в отдельную функцию:
Function registerInParent (childOU, parentOU)
parentTreeGUID = parentOU.groupTree
if not isGroupExist(parentTreeGUID) then Exit Function
set parentTreeGroup = Getobject("LDAP://<GUID=" & _
parentTreeGUID & ">")
if not isGroupExist(childOU.groupTree) then
childOU.groupTree = parentTreeGUID
childOU.setInfo
attach parentTreeGroup, childOU
end If
on Error Resume Next
parentTreeGroup.Add("LDAP://<GUID=" & childOU.groupTree & ">")
parentTreeGroup.setInfo
on Error Goto 0
End Function
Сценарий прослушивания событий операций над группами должен также поддерживать функциональность групп типа Tree. Рассмотрим подробнее его обязанности на примере из [1] (см. рис. 3).
Допустим, группы типа Single содержатся в каждой организационной единице. Будем использовать соглашения именования групп, принятые в начале статьи. Так группа типа Singe для подразделения «Управление» будет называться «Управление_Group_Single», а группа типа Tree того же отдела – «Управление_Group_Subtree». Тогда группа «Организация_Group_Subtree» будет включать группу «Организация_Group_Single», а также группы «Производство_Group_Subtree» и «Управление_Group_Subtree». Группы типа Tree листовых узлов будут включать только их группы первого типа. В случае если администратор решит удалить группу «Учет_Group_Subtree», на ее место должна быть автоматически установлена ссылка на группу родительского подразделения («Производство_Group_Subtree»). То есть группы поддержки поддеревьев родительских подразделений могут при необходимости выполнять функции дочерних. Ссылки на прикрепленные группы родительских подразделений позволят значительно упростить функции обработки событий с пользователями, поскольку в этих случаях не потребуется обрабатывать особым образом ситуации, когда организационная единица не имеет собственной группы.
Сначала мы получаем группу типа Tree родительского подразделения. Если у текущей организационной единицы нет прикрепленной группы этого типа – устанавливаем в ее качестве группу родителя. Таким образом, одна группа может включать учетные записи сотрудников сразу из нескольких подразделений. Это полезно, когда ряд отделов имеет доступ к одним и тем же ресурсам. С помощью функции attach выполняется добавление во вновь прикрепленную группу типа Tree таких групп из дочерних подразделений. Далее мы рассмотрим ее подробнее. Ну и в конце мы добавляем группу, отвечающую за поддерево текущего подразделения, в родительское.
Итак, рассмотрим функцию attach. В процессе добавления групп дочерних подразделений они могут уже принадлежать целевой группе. Чтобы не делать специальных проверок, будем игнорировать возникающие в этом случае ошибки с помощью директивы «on Error Resume Next». Дело в том, что метод isMember класса «группа» в отличие от add не работает с LDAP-запросами поиска по идентификатору, требуя передачи только отличительного имени (DN). Поэтому здесь проще игнорировать ошибки, чем предварительно проверять принадлежность добавляемого объекта группе.
function attach(treeGroup, ou)
on error resume next
singleGUID = ou.groupSingle
if isGroupExist(singleGUID) Then
treeGroup.Add ("LDAP://<GUID=" & singleGUID & ">")
treeGroup.setInfo
end If
for each childOU in ou
if childOU.class = "organizationalUnit" then
if isTreeAttached(childOU) then
if childOU.groupTree <> treeGroup.GUID Then
treeGroup.add ("LDAP://<GUID=" & childOU.groupTree & ">")
treeGroup.setInfo
Else
attach treeGroup, childOU
end If
end if
end if
next
on error goto 0
end function
Сначала в группу типа Tree добавляется группа типа Single текущего подразделения. Затем перебираются все дочерние организационные единицы и их группы типа Tree добавляются в родительскую. Если же у подчиненных отделов нет своих Tree-групп, на их место устанавливается эта группа текущего отдела с помощью рекурсивного вызова этой же функции attach.
Отмечу, что прикрепление и отключение специальных групп не сопровождается в текущей реализации никакими побочными действиями. При подключении группы типа Single можно добавлять в нее всех пользователей текущего отдела. Подключая же группу типа Tree – добавлять в нее группы этого вида дочерних подразделений. Но в качестве решения по умолчанию такой подход опасен, так как представляет собой большое количество неявных действий, которых администратор может не ожидать. Такую функциональность логично сделать опциональной, причем изначально отключенной.
Итак, в первой части статьи были сформулированы основные принципы функционирования надстройки. Также были разработаны функции для реализации базовой функциональности. Но данная работа по сложности существенно превосходит надстройку из [1]. Поэтому использовать только базовые и наиболее распространенные приемы работы со сценариями WSH стало нецелесообразным. В следующий раз рассмотрим более сложные методы оформления сценариев, которые, однако, позволяют более эффективно управляться с громоздкими решениями. Также будет завершена разработка подпрограмм, обеспечивающих полную функциональность надстройки.
- Андросов В. Реализуем нестандартные правила управления доступом на основе архитектуры организации в Windows Server 2003. //Системный администратор, №10, 2007 г. – С. 48-58.
- Сайт Microsoft – www.microsoft.com.
- Гамма Э., Хелм Р., Джонсон Р., Влиссидес Д. «Приемы объектно-ориентированного проектирования. Паттерны проектирования». – СПб.: Питер, 2007. – 366 с.
- Чарли Рассел, Шарон Кроуфорд, Джейсон Джеренд. «Windows server 2003 +SP1 и R2. Справочник администратора». – М.: Издательство «ЭКОМ», 2006. – 1424 с.
- Alain Lissoir. «Understanding WMI Scripting». – Digital Press, 2003.
- Microsoft Development Network – msdn.microsoft.com.
- Чекмарев А.Н. «Windows 2000 Active Directory». – СПб.: БХВ-Петербург, 2001. – 400 с.
- Don Jones, Jefferey Hicks «Advanced VBScript for Microsoft Windows Administrators». – Washington: Microsoft Press, 2006.
- Microsoft® Windows® 2000 Scripting Guide «Enhanced WMI Monitoring Scripts».
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|