Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.
В первой части мы рассмотрели использование PowerShell для добавления DACL (Discretionary Access Control List) к сетевой шаре как для создания списка ACL и получения возможности в дальнейшем работать с этим списком из PowerShell. Данный метод полностью заменяет текущий список DACL сетевой папки, т.е. все текущие участники безопасности будут удалены и заменены теми, которые были указаны в теле скрипта. Теперь стоит поговорить об извлечении и чтении DACL для сетевых папок как для анализа, так и для выборочного добавления/удаления участников безопасности в списке ACL. Класс Win32_Share имеет лишь один метод для добавления ACL списка - SetShareInfo, который полностью заменяет текущий список DACL и не имеет нативного метода добавления частичного DACL к имеющемуся списку DACL. Поэтому для добавления или удаления участников безопасности из этого списка нам потребуется сначала считать этот список, проанализировать, внести необходимые изменения и записать этот список с внесёнными изменениями в ACL сетевой папки.
Процесс извлечения DACL из ACL сетевой шары будет происходить примерно в обратном порядке записи. В предыдущей части я говорил про процесс упаковывания ("инкапсуляции") массива в массив, и сейчас нам придётся обратно расшивать (извлекать) массивы из массивов. Как уже говорилось в первой части, для чтения DACL сетевой папки используется класс Win32_LogicalShareSecuritySettings:
Get-WmiObject Win32_LogicalShareSecuritySetting
Так мы получим все ShareSecuritySettnigs для всех расшаренных папок. Давайте отфильтруем только ту, конкретно с которой будем работать и выберем её в переменную:
$ShareSec = Get-WmiObject Win32_LogicalShareSecuritySetting -filter "name='UserShare'"
Если теперь теперь посмотреть содержимое переменной, то ничего интересного там мы не увидим:
[C:\] Get-WmiObject Win32_LogicalShareSecuritySetting -filter "name='UserShare'" | Format-List [a-z]* Caption : Security settings of UserShare ControlFlags : 32772 Description : Security settings of UserShare Name : UserShare SettingID :
Давайте покопаем поглубже. В процессе создания DACL для шары мы записывали уже готовый SecurityDescriptor, в котором хранится DACL и внутри которого уже хранятся ACE и Trustee - вот эти объекты нам и нужны. Для извлечения этого класс Win32_LogicalShareSecuritySettings имеет метод GetSecurityDescriptor
$SD = $ShareSec.GetSecurityDescriptor()
И мы увидим две строчки (я специально отфильтровал вывод ненужной для нас в данный момент информации, которая начинается с символа подчёркивания "_"):
[C:\] $SD Descriptor : System.Management.ManagementBaseObject ReturnValue : 0
Вот здесь нас будет интересовать параметр Descriptor:
[C:\] $SD.Descriptor | Format-List [a-z]* ControlFlags : 32772 DACL : {System.Management.ManagementBaseObject} Group : System.Management.ManagementBaseObject Owner : System.Management.ManagementBaseObject SACL :
Вот мы уже добрались до DACL:
[C:\] $SD.Descriptor.DACL | Format-List [a-z]* AccessMask : 1179817 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : Trustee : System.Management.ManagementBaseObject AccessMask : 1245631 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : Trustee : System.Management.ManagementBaseObject AccessMask : 2032127 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : Trustee : System.Management.ManagementBaseObject
Вот здесь мы видим 3 ACE с разными AccessMask. Но имён почему-то не видно..а не видно, потому что имена участников безопасности запрятаны ещё глубже, а именно в Trustee (вы помните, как мы записывали имя участника безопасности в класс Trustee). Давайте посмотрим первый элемент:
[C:\] $SD.Descriptor.DACL[0].Trustee | Format-List [a-z]* Domain : Name : Everyone SID : {1, 1, 0, 0...} SidLength : 12 SIDString : S-1-1-0
И команда нам вернёт имя пользователя. У меня это Everyone. AccessMask = 1179817 означает Read&Execute + Synchronize. Узнать это очень легко, достаточно набрать в консоли:
[C:\] [System.Security.AccessControl.FileSystemRights]1179817 ReadAndExecute, Synchronize [C:\] [System.Security.AccessControl.FileSystemRights]1245631 Modify, Synchronize [C:\] [System.Security.AccessControl.FileSystemRights]2032127 FullControl
Теперь посмотрим имя второго участника безопасности, который имеет маску доступа 1245631 (Change):
[C:\] $SD.Descriptor.DACL[1].Trustee | Format-List [a-z]* Domain : CONTOSO Name : Domain Users SID : {1, 5, 0, 0...} SidLength : 28 SIDString : S-1-5-21-3709200118-438321133-4282490648-513
И т.д. можно перебирать все элементы массива. Давайте для начала выведем весь этот список в CSV. Здесь я не буду изобретать велосипед, а уже буду использовать готовое решение от /\/\o\/\/:
$filename = 'C:\ShareInfo.csv' $shares = Get-WmiObject Win32_Share -filter 'type=0' $Shareinfo = @() foreach ($share in $shares) { $shareSec = gwmi Win32_LogicalShareSecuritySetting -filter "name='$($share.name)'" if($shareSec) { $sd = $sharesec.GetSecurityDescriptor() $ShareInfo += $SD.Descriptor.DACL |% { $_ | select @{e={$share.name};n='Name'}, @{e={$share.Path};n='Path'}, @{e={$share.Description};n='Description'}, AccessMask, AceFlags, AceType, @{e={$_.trustee.Name};n='User'}, @{e={$_.trustee.Domain};n='Domain'}, @{e={$_.trustee.SIDString};n='SID'} } } } $ShareInfo | select Name,Path,Description,User,Domain,SID, AccessMask,AceFlags,AceType | export-csv -noType $filename
На выходе мы получим CSV файл, где в простеньком (но вполне удобочитаемом) формате есть вся информация о имеющихся сетевых шарах на локальном компьютере. К слову говоря, этот CSV файл потом можно будет импортировать обратно для восстановления Share Permissions и другой информации о шарах. Давайте посмотрим на содержимое переменной $ShareInfo:
[C:\] $Shareinfo Name : UserShare Path : C:\Test Description : AccessMask : 1179817 AceFlags : 0 AceType : 0 User : Everyone Domain : SID : S-1-1-0 Name : UserShare Path : C:\Test Description : AccessMask : 1245631 AceFlags : 0 AceType : 0 User : Domain Users Domain : CONTOSO SID : S-1-5-21-3709200118-438321133-4282490648-513 Name : UserShare Path : C:\Test Description : AccessMask : 2032127 AceFlags : 0 AceType : 0 User : Administrators Domain : BUILTIN SID : S-1-5-32-544 Name : CertEnroll Path : C:\WINDOWS\system32\certsrv\CertEnroll Description : AccessMask : 2032127 AceFlags : 0 AceType : 0 User : Everyone Domain : SID : S-1-1-0 <...>
Остальное я не стал показывать, т.к. будет содержать идентичную информацию для остальных ресурсов. Обладая этой информацией мы можем гибко изменять наши настройки, например добавлять или удалять выборочно единичных участников безопасности. Давайте начнём с удаления. К примеру, удалим из ACL шары UserShare группу Everyone. Не уверен, что этот метод является самым правильным, но мы сделаем переприсвоение массива с фильтрацией по имени шары и имени пользователя, которого будем удалять:
$ShareInfo = $shareInfo | where {$_.name -eq "UserShare" -and $_.user -ne "Everyone"}
Теперь можем посмотреть содержимое переменной $ShareInfo:
[C:\] $ShareInfo = $shareInfo | where {$_.name -eq "UserShare" -and $_.user -ne "Everyone"}
[C:\] $Shareinfo
Name : UserShare
Path : C:\Test
Description :
AccessMask : 1245631
AceFlags : 0
AceType : 0
User : Domain Users
Domain : CONTOSO
SID : S-1-5-21-3709200118-438321133-4282490648-513
Name : UserShare
Path : C:\Test
Description :
AccessMask : 2032127
AceFlags : 0
AceType : 0
User : Administrators
Domain : BUILTIN
SID : S-1-5-32-544
Как мы видим, переменная $ShareInfo уже не содержит ACE группы Everyone. Таким образом можно фильтровать нужные элементы массива по любым критериям, как группа пользователей, имя сетевой шары, тип доступа и т.д. Теперь можно импортировать эту переменную в нашу шару. Для импорта этой информации воспользуемся тем же методом, каким мы создавали Share Permissions с нуля. Разница будет лишь в том, что для создания нужных объектов (как User, SID, AccessMask) мы будем использовать значения из переменной $ShareInfo:
$ShareInfo | select -unique name, Path, Description | ForEach-Object { $name = $_.name $path = $_.Path $description = $_.Description "Processing : $name $path $description" $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() $ace = ([WMIClass] "Win32_Ace").CreateInstance() $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() $SD.DACL = @() $ShareInfo | where {$_.name -eq $name} | Foreach-Object { $SID = new-object security.principal.securityidentifier($_.SID) [byte[]] $SIDArray = ,0 * $SID.BinaryLength $SID.GetBinaryForm($SIDArray,0) $Trustee.Name = $_.user $Trustee.SID = $SIDArray $ace.AccessMask = $_.AccessMask $ace.AceType = $_.AceType $ace.AceFlags = $_.AceFlags $ace.trustee = $Trustee $SD.DACL += $ACE.psObject.baseobject } $Share = Get-WmiObject win32_share -filter "name='UserShare'" $inParams = $share.psbase.GetMethodParameters("SetShareInfo") $inParams.Access = $SD $share.psbase.invokemethod("SetShareInfo", $inParams, $null) }
Если посмотреть на скрипт из предыдущей статьи, то можно проследить практически идентичную процедуру записи новых SharePermissions. Вот так мы получили готовый шаблон для изменения SharePermissions, который включает 3 этапа:
Кстати говоря, для изменения одного конкретного ACE (без удаления) можно использовать следующий метод. Он заключается в определении местоположения необходимого элмента в массиве и редактировании конкретно этого элемента. Делается это следующим образом, пишем функцию (за функцию отдельное спасибо Васе Гусеву):
function findinarr ($array, $value) {for ($i=0; $i -lt $array.count;$i++){if($array[$i].user -eq $value){$i}}}
Теперь определяем порядковый номер элемента в массиве, который содержит группу Domain Users и вместо Change дадим этой группе право только Read:
[C:\] function findinarr ($array, $value) {for ($i=0; $i -lt $array.count;$i++){if($array[$i].user -eq $value){$i}}}
[C:\] $count = findinarr $shareInfo "Domain Users"
[C:\] $ShareInfo[$count].AccessMask = 1179817
[C:\] $ShareInfo
Name : UserShare
Path : C:\Test
Description :
AccessMask : 1179817
AceFlags : 0
AceType : 0
User : Domain Users
Domain : CONTOSO
SID : S-1-5-21-3709200118-438321133-4282490648-513
Name : UserShare
Path : C:\Test
Description :
AccessMask : 2032127
AceFlags : 0
AceType : 0
User : Administrators
Domain : BUILTIN
SID : S-1-5-32-544
Вот теперь Группа Domain Users имеет маску доступа не Change, а Read. Теперь осталось только записать изменённые данные в ACL шары по вышеприведённому примеру, где мы удаляли группу Everyone из ACL.
В этой части мы рассмотрели чтение информации о сетевых шарах, в частности чтение Share Permissions, экспорт этих данных в CSV файл, а так же рассмотрели вопросы удаления единичных ACE из списка ACL и их редактирования. В следующей части я расскажу, как добавлять участников безопасности к существующему списку ACL и в качестве итогового резюме мы приведём в порядок весь материал, который изучили, чтобы его можно было удобно использовать в производственной среде. Так что продолжение следует.
Добрый день! А не могли подсказать как получить информацию - является ли объект аудируемым или нет?
Например, через Get-Acl и свойство Access. Там будут все права, и DACL и SACL (альтернативно можно посмотреть свойство AuditToString).
Comments: