Contents of this directory is archived and no longer updated.

Примечание: данный пост перепечатан в связи с закрытием бложиков на 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 этапа:

  1. чтение текущих SharePermissions (и прочей информации) в переменную;
  2. изменение необходимых параметров внутри переменной;
  3. запись новой переменной с обновлёнными Share Permissions обратно в ACL сетевой папки.

Кстати говоря, для изменения одного конкретного 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 и в качестве итогового резюме мы приведём в порядок весь материал, который изучили, чтобы его можно было удобно использовать в производственной среде. Так что продолжение следует.


Share this article:

Comments:

www.google.com/accounts/o8/id?id=AItOawmiXEa9faoEs3MWx9CFmJBZTbXH-si8LtM

Добрый день! А не могли подсказать как получить информацию - является ли объект аудируемым или нет?

Vadims Podāns

Например, через Get-Acl и свойство Access. Там будут все права, и DACL и SACL (альтернативно можно посмотреть свойство AuditToString).

Comments are closed.