Здравствуйте! Рассмотрим способ автоматизации назначения прав пользователей к ресурсам с помощью интерфейса ADSI и PowerShell. Изначально задача возникла при использовании старых контроллеров домена Windows 2003 и ограниченного выхода в интернет. Эта тема была затронута на Хабрe ранее. В описываемом мной случае, переход на ОС Windows 2008 состоялся лишь частично, но по сложности и протяженности процесса сопоставим, пожалуй, с миссией на Марс.

Постановка задачи:

При создании нового пользователя в крупной организации заводится документ, который описывает все привилегии данной учетной записи, в том числе AD-группы в которых он состоит.

Существует СХД, используемый как файловое хранилище пользователей с большим количеством общих ресурсов. Каждый общий ресурс (или просто шара) на СХД содержит список ACL (Access Control List), включающий как минимум две группы доступа AD — пользовательскую (с разрешениями чтения и выполнения) и административную (редактирование и удаление). Название обеих групп в AD включает в себя название самого ресурса для удобства поиска. Таким образом, для полного доступа к ресурсу пользователю необходимо членство в обеих группах.

На СХД также существует каталог с ярлыками-ссылками на ресурсы в общем доступе. При логине новой записи в домене отрабатывает групповая политика, содержащая Startup.script. Скрипт копирует все необходимые ярлыки на рабочий стол пользователя. Пользователь ничего не ищет и сразу получает доступ ко всем нужным ему документам.

В нашу задачу входит:

  1. Создать пользователя.
  2. Определить список каталогов, к которым должен иметь доступ пользователь.
  3. Создать группы с именем, содержащим имя каталога.
  4. Добавить группы в ACL-каталог. Назначить соответствующие NTFS-права для каждой группы.
  5. Включить пользователя в созданные группы.
  6. Создать ярлыки с именем каталога в названии.
  7. Обновить Startup.script, если пользователь присутствует в одной из групп, скопировать соответствующий ярлык ему на десктоп.
  8. Использовать доступные технические средства.

Существует минимум четыре способа сделать вышеописанные действия в системах Windows. Стоит ли говорить, что выполняя эти действия через штатные оснастки даже для одного нового пользователя, вы не уложитесь и в сто кликов мышью. Если пользователей полсотни и привилегий доступа у них много, за день точно не управитесь. Попытаемся автоматизировать каждый пункт отдельно. Не будем подробно описывать создание пользователя, эта легкодоступная информация.

Пункт 7 тоже выходит за рамки статьи, по сути это административный шаблон в политике GPO. Содержимое скрипта следующее: если пользователь состоит в какой-то группе, необходимо скопировать соответствующие ярлыки из некого каталога на рабочий стол. Все остальное тоже неплохо автоматизируется в PowerShell.

Напишем пробный скрипт без проверки ошибок и прочих нюансов.

Вручную определяем переменные для теста. ФИО пользователя и списки доступных ему ресурсов получим из документа о создании учетной записи:

$server_name = read-host -prompt "Enter fileserver"
$share_name = read-host -prompt "Enter share_name"
$UNC="\\$server_name"+"\$share_name"+"$"

Если все ввели верно, сначала создаем каталог и ярлык, который на него ссылается:

if ($server_name -eq "S182froc152"){
$path = "\\$server_name" +"\vol1$\projetspec2\"
    #Check if the directory exists. Skip if true.
    if(!(Test-Path($UNC))) {
        #Create directories
        Write-Host "Creating $share_name"
                New-Item -path $path -name $share_name -Type directory

Ярлык создадим через COM-объект:

Write-Host "Creating shortcut"
	New-Item -path $path\E182_P_GroupWare\Projets_Specifiques\$share_name -Type directory
		$wsh = New-Object -com 'WScript.Shell'
$dir = "$path\E182_P_GroupWare\Projets_Specifiques\$share_name"
$sct = $wsh.CreateShortcut("$dir" +"\$share_name.lnk")
$sct.TargetPath =$UNC
$sct.Save()

Создадим группу безопасности.

Для начала немного теории:

В AD cуществуют группы безопасности и распространения. Группы распространения используются для почтовых рассылок, по большей части для MS Exchange.

Также группы подразделяются на локальные, глобальные и универсальные.

  • Локальные группы — управляют разрешениями в домене. Могут включать в себя объекты из других доменов.
  • Глобальные — дают доступ к объекту в любом домене, но включают в себя только пользователей из одного домена.
  • Универсальные — используются в лесах для множества доменов и сильно все путают. Мне не приходилось их использовать.

Покопавшись в атрибутах, можно найти, что локальные группы имеют идентификатор groupType -2147483644, а глобальные -2147483646.

Похоже, назначение самой группы определяется каким-то битом в числе. Если лень искать, можно посмотреть идентификатор на TechNet.

Указываем и создаем локальную группу в нашем домене – указываем дополнительную информацию в комментарии: путь к ресурсу группы, и какие права дает сама группа.

Добавляем пользователя:

#Create security_group
$ADS_GROUP_TYPE_LOCAL_GROUP = -2147483644
$objOU = [ADSI]"LDAP: //OU=Groups,OU=MPC,OU=E182,DC=emea,DC=corpdir,DC=net"
$GroupName = "$share_name"
$objGroup = $objOU.Create("group", "CN=" + $GroupName)
$objGroup.Put("groupType", $ADS_GROUP_TYPE_LOCAL_GROUP )
$objGroup.Put("description", $UNC )
$objGroup.Put("sAMAccountName", $GroupName )
$objGroup.SetInfo()
}}

Права на ресурс подразделяются на SMB-разрешения и NTFS. Это, соответственно, доступ на уровне папки и доступ на уровне файловой системы. По сути, они независимы. Если вы используете FAT, то придется оперировать только SMB-разрешениями. Доступ к ресурсу окончательно складывается из суммы разрешений SMB+NTFS.

Во избежание путаницы с правами на ресурсы оперируем только NTFS-правами. В SMB-правах выставляем общий доступ для всех пользователей. Вспомним теорию:

Каждый пользователь в системе имеет маркер доступа с информацией о безопасности для данного сеанса входа в систему. Система сама создает маркер доступа при входе. Каждый процесс, который выполняется от имени пользователя, имеет копию этого маркера доступа. Маркер идентифицирует пользователя, группы пользователя и привилегии. Маркер также содержит SID входа (идентификатор безопасности), который идентифицирует текущий сеанс входа в систему. Когда пользователь пытается получить доступ к защищаемому объекту, происходит авторизация в системе и, в результате, он получает разрешение или отказ в доступе. В данном случае авторизация основана на поиске в ACL (списке управления доступом).

Каждый элемент-запись (или ACE – Access Control Entry) в ACL объекта определяет права доступа. Запись содержит три элемента:

  • SID – идентификатор пользователя или группы к которой применима запись.
  • Вид доступа — чтение, запись и т.п.
  • Тип записи — разрешить или запретить.

Если владелец объекта не создал ни одной записи в ACL объекта, система предоставляет доступ сразу. Таким образом, сравниваются все SID записей в маркере доступа. Порядок записей тоже важен.

Система перестает проверять записи АСЕ, когда запрошенный доступ явно разрешен или запрещен. Например, явный запрет доступа имеет приоритет перед наследованным разрешением от родительского каталога. На втором месте — унаследованные разрешения от каталогов родителей, далее — все разрешения вверх по дереву каталогов. Это также означает, что владелец объекта может определить собственные разрешения на объект, которые позволяют дать доступ группе пользователей и запретить доступ к подгруппе группы. Параметры наследования для объекта могут принимать следующие значения:
Значение Описание
«None»,«None» Права применяются только для этой папки
«ContainerInherit»,«None» Права применяются для этой папки и её подпапок
«ObjectInherit»,«None» Права применяются для этой папки и её файлов
«ContainerInherit,ObjectInherit»,«None» Права применяются для этой папки её подпапок и файлов
«ContainerInherit», «InheritOnly» Права применяются только для подпапок
«ObjectInherit», «InheritOnly» Права применяются только для файлов
«ContainerInherit,ObjectInherit», «InheritOnly» Права применяются только для подпапок и файлов

В ходе теста выяснилось, что группа не всегда создается в домене раньше, чем выполняется следующий шаг. Проверку я еще не сделал, поэтому просто выставляем достаточную паузу в 5 секунд. Далее получаем ACL каталога. Создаем в листе доступа ACL новую запись и сохраняем ее:

start-sleep 5
$dirpath=$path+$share_name
$acl = get-acl $dirpath
				
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("$share_name","ReadAndExecute", "ContainerInherit, ObjectInherit", "None", "Allow")
                $acl.SetAccessRuleProtection($True, $True)
				$acl.AddAccessRule($rule)
					                
                   
        Set-Acl $dirpath $acl

Повторим то же самое для второй группы, административной, с другими правами доступа:

start-sleep 5
#$objOU = [ADSI]"LDAP://OU=Groups,OU=MPC,OU=E182,DC=emea,DC=corpdir,DC=net"
$GroupName = "$share_name"+"_ADM"
$objGroup = $objOU.Create("group", "CN=" + $GroupName)
$objGroup.Put("groupType", $ADS_GROUP_TYPE_LOCAL_GROUP )
$objGroup.Put("description", $UNC )
$objGroup.Put("sAMAccountName", $GroupName )
$objGroup.SetInfo()	

start-sleep 20
$dirpath=$path+$share_name
$acl = get-acl $dirpath	
                $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("$GroupName","Modify", "ContainerInherit, ObjectInherit", "None", "Allow")
                $acl.SetAccessRuleProtection($True, $True)
				$acl.AddAccessRule($rule)	
	
	Set-Acl $dirpath $acl
Write-Host " $share_name created"

Остается просто «расшарить» каталог:

$dirpath=$path+"\$sharename"
		$Shares=[WMICLASS]”WIN32_Share” 
		If (!(GET-WMIOBJECT Win32_Share -filter “name=’$share_name’”) {
                $Shares.Create(“$dirpath”,”$share_name”,0)
}

Заключение

В PowerShell существуют дополнительные удобные модули Active Directory и File System Security PowerShell Module. Нормальный администратор, возможно, и не подумает связываться с дебрями классов-объектов при назначении прав в PowerShell, иначе был бы он не админом, а программистом. Список локальных групп с помощью AD-модуля можно получить, например, так:

get-qadgroup -GroupScope DomainLocal | Get-QADGroupMember -Type group | Where{$_.GroupScope -eq "Local"}

С другой стороны, использование ADSI является более универсальным подходом. Существует большое количество консервативных заказчиков, которых, к слову, и от Windows XP не убедишь отказаться.

Клонирование всех разрешений одного пользователя другому, в таком случае, можно сделать из командной строки с помощью штатных утилит:

dsquery user -samid Person |dsget user -memberof |dsmod group -addmbr "CN=Some Other Person(222),OU=Users,OU=_GlobalResources,OU=222,OU=E777,DC=emea,DC=corpdir,DC=net" –c

Удачной автоматизации!
Поделиться с друзьями
-->

Комментарии (2)


  1. Leoningener1
    24.03.2017 09:31

    Задача перейти на ОС Windows 2008 с сохранением привилегий пользователей или вновь создается структура? Список пользователей берется из листа Excel например? Сколько кликов мыши понадобится для регистрации 100 пользователей? почему бы не написать программу с GUI с чек боксами и импортом. Отличная статья, есть что применить на практике.


  1. GTRch
    24.03.2017 10:42

    Не совсем. С миграцией контроллеров на Win 2008 появляются дополнительные возможности решения этой задачи.
    Тот же DFS можно использовать так, что пользователи не смогут видеть ресурсы к которым у них нет доступа.
    Список пользователей пока предоставляется в виде документа, но в произвольном формате — word, скане pdf, в jpg вложении в письме, в режиме жаренного петуха по телефону…
    По поводу кликов:
    Как минимум нужно найти или завести каждого пользователя в домене, найти группу безопасности, обеспечивающую доступ к ресурсу и добавить каждого из 100 пользователей.
    Если ресурсов 10, нужно создать 10 + 10 (административную и нет) групп безопасности, найти и расшарить каждый ресурс, дать каждой группе NTFS права для доступа и потом уже вносить пользователей в группы и раскидывать каждому ярлыки-ссылки. По моему проще скалу расковырять вилкой.

    Вопрос с GUI интересный, но надо предусматривать импорт списков пользователей и списков ресурсов. Возможно в следующей статье