Vadims's profileVadims Podans's former b...PhotosBlogListsMore Tools Help

Blog


    7/7/2008

    Управление безопасностью общих папок (сетевых шар) в PowerShell (часть 2)

    В первой части мы рассмотрели использование 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 | Format-List [a-z]*

    Так мы получим все ShareSecuritySettnigs для всех расшаренных папок. Давайте отфильтруем только ту, конкретно с которой будем работать и выберем её в переменную:

    $ShareSec = 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() | Format-List [a-z]*

    И мы увидим две строчки (я специально отфильтровал вывод ненужной для нас в данный момент информации, которая начинается с символа подчёркивания "_"):

    Descriptor       : System.Management.ManagementBaseObject
    ReturnValue      : 0

    Вот здесь нас будет интересовать параметр Descriptor:

    [C:\]$SD.Descriptor


    ControlFlags : 32772
    DACL         : {System.Management.ManagementBaseObject, System.Management.ManagementBaseObject, 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

    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

    Domain    : CONTOSO
    Name      : Domain Users
    SID       : {1, 5, 0, 0...}
    SidLength : 28
    SIDString : S-1-5-21-3321262099-2632712065-3158606685-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:

    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-3321262099-2632712065-3158606685-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   : Certificate Services share
    AccessMask  : 1179817
    AceFlags       : 3
    AceType       : 0
    User            : Everyone
    Domain        :
    SID              : S-1-1-0

    <...>

    Остальное я не стал показывать, т.к. будет содержать идентичную информацию для остальных ресурсов. Обладая этой информацией мы можем гибко изменять наши настройки, например добавлять или удалять выборочно единичных участников безопасности. Давайте начнём с удаления. К примеру, удалим из ACL шары UserShare группу Everyone. Не уверен, что этот метод является самым правильным, но мы сделаем переприсвоение массива с фильтрацией по имени шары и имени пользователя, которого будем удалять:

    $ShareInfo = $shareInfo | where {$_.name -eq "UserShare" -and $_.user -ne "Everyone"}

    Теперь можем посмотреть содержимое переменной $ShareInfo:

    Name           : UserShare
    Path             : C:\Test
    Description   :
    AccessMask  : 1245631
    AceFlags       : 0
    AceType       : 0
    User             : Domain Users
    Domain        : CONTOSO
    SID              : S-1-5-21-3321262099-2632712065-3158606685-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} | Froeach-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:\] $ShareInfo = $ShareInfo | where {$_.name -eq "UserShare"}
    [C:\] $ShareInfo

    Name           : UserShare
    Path             : C:\Test
    Description   :
    AccessMask  : 1245631
    AceFlags       : 0
    AceType       : 0
    User             : Domain Users
    Domain        : CONTOSO
    SID              : S-1-5-21-3321262099-2632712065-3158606685-513

    Name           : UserShare
    Path             : C:\Test
    Description   :
    AccessMask  : 1245631
    AceFlags       : 0
    AceType       : 0
    User             : Administrators
    Domain        : BUILTIN
    SID              : S-1-5-32-544

    [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-3321262099-2632712065-3158606685-513

    Name           : UserShare
    Path             : C:\Test
    Description   :
    AccessMask  : 1245631
    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 и в качестве итогового резюме мы приведём в порядок весь материал, который изучили, чтобы его можно было удобно использовать в производственной среде. Так что продолжение следует.

    Comments

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.
    Vadims Podāns has turned off comments on this page.

    Trackbacks

    The trackback URL for this entry is:
    http://vpodans.spaces.live.com/blog/cns!BB1419A2CFC1E008!177.trak
    Weblogs that reference this entry
    • None