Previous Page Page 3 of 4 in the PowerShellACL category Next Page

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

PowerShell |  ACL |  Shares |  WMI
Monday, July 07, 2008 1:24:00 PM (FLE Daylight Time, UTC+03:00)   Comments [2]    

 

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.


В предыдущей статье я сделал вводну часть по управлению сетевыми папками в PowerShell. В ней я не рассматривал вопрос управления Share Permissions, т.к. это дело весьма непростое. Итак, что нам для этого потребуется? А потребуются нам следующие классы WMI:

Основной класс, который позволит нам извлечь параметры безопасности - Win32_LogicalShareSecuritySettings. Как я говорил в предыдущей статье, упрощённый вариант создания новой сетевой папки - не самый лучшй вариант создания для последующего управления. Сейчас я продемонстрирую вам проблему:

[C:\] ([wmiClass] 'Win32_share').Create("C:\Test", "UserShare", "0", "100", "Network share for users") __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 1 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : ReturnValue : 0 [C:\] Get-WmiObject Win32_Share Name Path Description ---- ---- ----------- C$ C:\ Default share UserShare C:\Test Network share for users CertEnroll C:\WINDOWS\system32\certsrv\CertEnroll IPC$ Remote IPC ADMIN$ C:\WINDOWS Remote Admin SYSVOL C:\WINDOWS\SYSVOL\sysvol Logon server share NETLOGON C:\WINDOWS\SYSVOL\sysvol\contoso.com... Logon server share [C:\] Get-WmiObject Win32_LogicalShareSecuritySetting | Format-List [a-z]*


Caption : Security settings of CertEnroll ControlFlags : 32772 Description : Security settings of CertEnroll Name : CertEnroll SettingID : Scope : System.Management.ManagementScope Path : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting.Name="CertEnroll" Options : System.Management.ObjectGetOptions ClassPath : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting Properties : {Caption, ControlFlags, Description, Name...} SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} Qualifiers : {dynamic, Locale, provider, UUID} Site : Container : Caption : Security settings of SYSVOL ControlFlags : 32772 Description : Security settings of SYSVOL Name : SYSVOL SettingID : Scope : System.Management.ManagementScope Path : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting.Name="SYSVOL" Options : System.Management.ObjectGetOptions ClassPath : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting Properties : {Caption, ControlFlags, Description, Name...} SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} Qualifiers : {dynamic, Locale, provider, UUID} Site : Container : Caption : Security settings of NETLOGON ControlFlags : 32772 Description : Security settings of NETLOGON Name : NETLOGON SettingID : Scope : System.Management.ManagementScope Path : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting.Name="NETLOGON" Options : System.Management.ObjectGetOptions ClassPath : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting Properties : {Caption, ControlFlags, Description, Name...} SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} Qualifiers : {dynamic, Locale, provider, UUID} Site : Container : [C:\]

Итак, первой строчкой мы создали новую шару. В выводе команды я выделил последнюю строчку ReturnValue и его значение 0. Ноль нам говорит, что шара создалась успешно. Чтобы в этом убедиться в следующей строчке я ввёл команду, которая показывает список всех расшаренных папок на локальной машине. Я так же выделил жирным строчку, которая показывает нашу шару. Третей командой я вывел параметры безопасности всех доступных сетевых ресурсов на локальной машине. И что мы видим? Точнее, чего мы не видим - а не видим мы административных шар (которые заканчиваются на знак $) и, так же, не увидели созданной нами сетевой папки UserShare. И это означает, что мы в последующем через классы WMI не сможем извлекать параметры безопасности для последующей обработки. Поэтому более правильным будет создание новой сетевой папки с явным назначением Share Permissions для неё.

Если посмотреть в описание метода Create класса Win32_Share, то там видно, что в качестве последнего параметра выступает класс Win32_SecurityDescriptor. Посмотрим, что нужно для него. Я для него нужны классы Win32_Ace и Win32_Trustee. Ну что ж, приступим к разбору. Итак, у нас есть уже шара с дефолтными правами. Чтобы создать новый набор прав нам нужно знать следующее:

  • Имя сетевой папки для которой будем изменять права сетевого доступа;
  • имя пользователя, которому будут назначены права;
  • тип доступа, который нужно назначить (FullControl, Change, Read).

Теперь нужно объявляем переменные для них:

$share="Test" 
$user = "Accounting" 
$mask = "Сhange"

Теперь объявляем вышеуказанные классы WMI:

$SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() 
$ace = ([WMIClass] "Win32_Ace").CreateInstance() 
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()

Теперь преобразовываем имя пользователя/группы в его SID. Преобразование я описывал вот в этой статье:

$SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])

В переменной $SID теперь хранится SID данного пользователя. Правда, здесь он содержится в строковом формате. Но если мы посмотрим в свойства класса Win32_Trustee, то увидим, что тип данных для свойства SID должен быть: Data type: uint8 array. Получить такой массив можно следующей конструкцией:

[byte[]] $SIDArray = ,0 * $SID.BinaryLength 
$SID.GetBinaryForm($SIDArray,0)

Здесь мы объявили переменную $SIDArray с длиной равной BinaryLength. Длину BinaryLength можно узнать выполнив преобразование имени пользователя в SID, как это рассказано в ссылке приведённой выше. Вот теперь у нас переменная $SID содержит уже байтовый массив из SID пользователя/группы, который получили из $SIDArray. С этим мы закончили. Теперь эти данные можно передать в класс Win32_Trustee, который является абстрактным классом для описания пользователя или группы. Он нам потребуется для дальнейшей передачи этих данных в класс Win32_Ace.

$Trustee.Name = $user 
$Trustee.SID = $SIDArray

Сам класс Win32_Trustee уже объявлен, поэтому мы просто добавляем значения свойств для этого класса.

Примечание: На первый взгляд это может показаться очень сложным материалом (мне он тоже дался не очень легко). По сути здесь присутствует множественная инкапсуляция данных и преобразование этих данных из одного типа в другой. Т.е. из исходных данных у нас есть разве что имя пользователя/группы и тип устанавливаемых прав. Если внимательно изучить ссылки, которые приведены в самом начале, то можно увидеть следующую последовательность преобразований:

  • имя пользователя/группы в SID;
  • SID в байтовый массив SIDArray;
  • передача SIDArray и имени в Win32_Trustee (первый этап т.н. "инкапсуляции");
  • Передача преобразованного типа прав доступа в класс Win32_Ace (второй этап инкапсуляции);
  • Передача готового Trustee в класс Win32_Ace (третий этап "инкапсуляции");
  • Передача сформированного ACE в класс Win32_SecurityIdentifier (четвёртый этап "инкапсуляции");
  • Передача уже сформированного SecurityDescriptor в метод SetShareInfo;
  • И применение самого метода SetShareInfo для записи параметров безопасности (прав доступа) в ACL самой шары.

Вот так выглядит общая схема последовательности действий, которая является шаблоном для данной операции.

А теперь продолжим. Теперь нам нужно преобразовать права доступа в класс FileSystemRights. Преобразование типа прав так же было ранее мною описано в первой части Управление ACL в PowerShell. Пара слов о том, чем отличаются права Read, Change и Full Control в контексте разрешений сетевого ресурса от контекста разрешений NTFS. Этим правам в NTFS сопоставляются Read + Execute, Modify и Full Control соответственно и плюс право Synchonize. Поэтому давайте запишем маску доступа в переменную $ace:

$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"Modify, Synchronize"

Ещё в начале мы объявили переменную $mode и вписали текстовое значение типа доступа. Здесь я его использовать не буду, а лишь преобразую его сразу в аналог FileSystemRights. Теперь в этот класс нужно передать тип доступа (Allow/Deny) в класс Win32_Ace. первой части Управление ACL в PowerShell я показывал команду, которая позволяет перечислять доступные значения свойств класса. Применим его снова, но в контексте AceType

[system.enum]::getnames([System.Security.AccessControl.AceType])

И в этом списке нас будут интересовать только первые 2

  • AccessAllowed;
  • AccessDenied.

Их можно указывать по порядковым номерам. Например, 0 будет означать AccessAllowed, а 1 - AccessDenied. Теперь заканчиваем второй этап и делаем третий этап нашей "инкапсуляции":

$ace.AceType = 0  
$ace.Trustee = $Trustee

Далее, следуя нашему шаблонному алгоритму нужно сформированную переменную $ace передать в класс Win32_SecurityDescriptor. Здесь нам нужно будет заполнить только свойство DACL, которое будет содержать массив параметров безопасности из переменной $ace:

$SD.DACL = $ace

Ну что ж, вот теперь у нас полностью готов объект SecurityDescriptor для применения его в качестве параметра для метода SetShareInfo. Для начала нам нужно указать шару, для которой будет применяться данный метод:

$share = get-WmiObject win32_share -filter "name='$share'"

Теперь нужно получить шаблон набора свойств для метода SetShareInfo:

$inParams = $share.PsBase.GetMethodParameters("SetShareInfo")

Так мы получили форму с необходимыми свойствами и типами данных, которые мы должны заполнить. Метод SetShareInfo использует следующий синтаксис (приведено из ссылки MSDN):

uint32 SetShareInfo(
  [in]            uint32 MaximumAllowed,
  [in, optional]  string Description,
  [in]            Win32_SecurityDescriptor Access
);

Это нам говорит, что требуется именно параметр Access, который нужно заполнить данными из класса Win32_SeceurityDescriptor. У нас уже есть переменная $SD, в которой заполнен параметр DACL. Вот теперь эту всю переменную запишем в качестве параметра Access в форму набора свойств:

$inParams.Access = $SD

Ну вот и всё. Теперь нам только осталось записать всё это в нашу сетевую папку:

$share.PsBase.InvokeMethod("setshareinfo", $inParams, $null)

Здесь я указал шару и использовал PsBase.InvokeMethod, чтобы вызвать метод SetShareInfo и после указания метода перечислил передаваемые прараметры Ну и конечный результат всех наших терзаний в едином целом:

$share="UserShare" 
([wmiClass] 'Win32_share').Create("C:\Test", $share, "0", "100", "Network share for users") 
$user = "Domain Users" 
$mask = "Change" 
$SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() 
$ace = ([WMIClass] "Win32_Ace").CreateInstance() 
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() 
$SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier]) 
[byte[]] $SIDArray = ,0 * $SID.BinaryLength 
$SID.GetBinaryForm($SIDArray,0) 
$Trustee.Name = $user 
$Trustee.SID = $SIDArray 
$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"Modify, Synchronize" 
$ace.AceType = 0  
$ace.Trustee = $Trustee 
$SD.DACL = $ace 
$share = get-wmiObject win32_share -filter "name='$share'" 
$inParams = $share.psbase.GetMethodParameters("SetShareInfo") 
$inParams.Access = $SD 
$share.psbase.invokemethod("setshareinfo", $inParams, $null)

Ну и, собственно, вторая цель, которой мы добивались:

[C:\] gwmi Win32_LogicalShareSecuritySetting | fl [a-z]* Caption : Security settings of UserShare ControlFlags : 32772 Description : Security settings of UserShare Name : UserShare SettingID : Scope : System.Management.ManagementScope Path : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting.Name="UserShare" Options : System.Management.ObjectGetOptions ClassPath : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting Properties : {Caption, ControlFlags, Description, Name...} SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} Qualifiers : {dynamic, Locale, provider, UUID} Site : Container : Caption : Security settings of CertEnroll ControlFlags : 32772 Description : Security settings of CertEnroll Name : CertEnroll SettingID : Scope : System.Management.ManagementScope Path : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting.Name="CertEnroll" Options : System.Management.ObjectGetOptions ClassPath : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting Properties : {Caption, ControlFlags, Description, Name...} SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} Qualifiers : {dynamic, Locale, provider, UUID} Site : Container : Caption : Security settings of SYSVOL ControlFlags : 32772 Description : Security settings of SYSVOL Name : SYSVOL SettingID : Scope : System.Management.ManagementScope Path : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting.Name="SYSVOL" Options : System.Management.ObjectGetOptions ClassPath : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting Properties : {Caption, ControlFlags, Description, Name...} SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} Qualifiers : {dynamic, Locale, provider, UUID} Site : Container : Caption : Security settings of NETLOGON ControlFlags : 32772 Description : Security settings of NETLOGON Name : NETLOGON SettingID : Scope : System.Management.ManagementScope Path : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting.Name="NETLOGON" Options : System.Management.ObjectGetOptions ClassPath : \\DC1\root\cimv2:Win32_LogicalShareSecuritySetting Properties : {Caption, ControlFlags, Description, Name...} SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...} Qualifiers : {dynamic, Locale, provider, UUID} Site : Container : [C:\]

Вот теперь мы увидели нашу шару через Win32_LogicalShareSecuritySetting и благодаря чему в последующем можно будет работать с DACL списком этого сетевого ресурса. Как говорит /\/\o\/\/ - Enjoy! :)

Кстати, хотелось бы отметить, что по этому вопросу /\/\o\/\/ в своё время проделал очень большую работу, как часть вопроса управления безопасностью объектов в Windows и значительная часть материала была написана с использованием его наработок.

Давайте, теперь поговорим о том, как добавить несколько участников безопасности. Суть процесса не изменится. Для решения данной задачи я воспользуюсь следующими приёмами:

  • циклом foreach;
  • hashtables;
  • конструкцией switch.

Если посмотреть код выше, то для добавления других пользователей/групп в Share Permissions, то нетрудно предположить, что нам нужно записать в $SD.DACL столько ACE, сколько пользователей/групп нам требуется завести. Следовательно, тут нужен цикл. Имена пользователей/групп и назначемые им права будут выбираться из hashtables. Hashtables - по сути является массивом сопоставлений. Он представляется двумя столбцами - именем параметра в первом столбце и его значением во втором. В нашем случае в качестве параметра будет выступать пользователь/группа, а его значение будет - тип предоставляемого доступа. Hashtables, на мой вгляд, хорошо описаны в книге PowerShell in Action (сегодня постараюсь не забыть прикрепить к блогу список полезной литертуры по PowerShell). Т.к. набор прав у нас будет для каждого пользователя/группы разный, поэтому я применю конструкцию Switch, которая будет сопоставлять текстовому значению типа доступа его значению в классе FileSystemRights.

Итак, давайте проведём анализ, какую часть кода нам нужно поместить в цикл для многократной обработки и получения для пользователя собственного ACE. У нас индивидуальным для каждого пользователя будет SID, Trustee, ACE. Остальное же будет универсальным (общим) для всех пользователей. Вот его и поместим в цикл foreach. Но для foreach нужно передать параметры - имя пользователя/группы и маску доступа (тип предоставляемого доступа). Для этого, как я уже говорил, нам потребуется Hashtables. Общий формат хэш-таблиц выглидт следующим образом:

<hashLiteral> = '@{' <keyExpression> '=' <pipeline> [ <separator> <keyExpression> '=' <pipeline> ] * '}'
<separator> = ';' | <newline>

Поэтому изменив предыдущий код мы заменим переменные $user и $mode на одну переменную $user с указанием имён пользователей и маски предоставляемого доступа согласно формату хэш-таблиц:

$user = @{"Everyone" = "Read"; "Administrators" = "FullControl"; "Domain Users" = "Change"}

Если после этой строки в консоли набрать $user, то мы получим нашу хэш-таблицу:

[C:\] $user Name Value ---- ----- Everyone Read Domain Users Change Administrators FullControl

Теперь готовим цикл foreach:

$user.keys | foreach {

Мы передали содержимое хэш-таблицы в цикл. Теперь нужно изменить несколько строк кода. А именно: мы передадим в цикл сперва имя пользователя/группы. Для этого нужно изменить строчку преобразования аккаунта, чтобы туда при каждой итерации цикла попадало новое имя пользователя:

$SID = (new-object security.principal.ntaccount $_ ).translate([security.principal.securityidentifier])

В комбинацию "$_" будут попадать только значения столбца Name из нашей хэш-таблицы (если указать, как и раньше $user, то туда попадёт вся хэш-таблица и скрипт даст ошибку преобразования аккаунта). Далее, у нас будет передаваться индивидуальная маска доступа. В предыдущем примере мы использовали всего лишь одну строчку, которая начиналась с $ace.AccessMask. В том примере было всё просто - один пользователь = одна маска. Теперь пользователей/групп уже 3 и маски тоже 3. Здесь мы воспользуемся конструкцией Switch, которая будет принимать наше текстовое значение искать ему сопоставление внутри конструкции и выполнять только одно действие:

switch ($($user[$_])) { 
    "FullControl"   {$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"FullControl, Synchronize"}
    "Change" {$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"Modify, Synchronize"}
    "Read"   {$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"ReadAndExecute, Synchronize"}
}

Я выделил $($user[$_]), для того, чтобы показать, как выбирать только значения из столбца Value нашей хэш-таблицы. Т.к. эта часть кода находится в теле цикла foreach, то сюда будет подставляться новое значение с каждой итерацией. Ну и последний, завершающий штрих - запись нескольких ACE в массив DACL. Если в предыдущем примере мы делали просто

$SD.DACL = $ace

То теперь такой вариант не подойдёт. А почему? А потому, что операция присвоения каждый раз будет заменять значение DACL последним ACE. Т.к. DACL у нас является массивом данных Win32_Ace, то для добавления новых ACE воспользуемся оператором добавления - "+="

$SD.DACL += $ace

Вот теперь в SD.DACL каждый новый ACE будет добавляться как новый элемент массива. Кстати, говоря, именно этой строчкой мы завершаем цикл foreach, т.к. SecurityDescriptor у нас уже готов и его уже можно как обычно отправлять дальше в код.

Подытожив всю полученную информацию мы в конечном итоге получим вот такой код:

$share="UserShare" 
([wmiClass] 'Win32_share').Create("C:\Test", $share, "0", "100", "Network share for users") 
$user = @{"Everyone" = "Read"; "Administrators" = "FullControl"; "Domain Users" = "Change"} 
$SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() 
$ace = ([WMIClass] "Win32_Ace").CreateInstance() 
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() 
$user.keys | foreach { 
$SID = (new-object security.principal.ntaccount $_ ).translate([security.principal.securityidentifier]) 
[byte[]] $SIDArray = ,0 * $SID.BinaryLength 
$SID.GetBinaryForm($SIDArray,0) 
$Trustee.Name = $_ 
$Trustee.SID = $SIDArray 
switch ($($user[$_])) { 
  "FullControl"   {$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"FullControl, Synchronize"} 
  "Change" {$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"Modify, Synchronize"} 
  "Read"   {$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"ReadAndExecute, Synchronize"} 
  } 
$ace.AceType = 0 
$ace.Trustee = $Trustee 
$SD.DACL += $ace.psobject.baseobject} 
$share = Get-WmiObject win32_share -filter "name='$share'" 
$inparams = $share.psbase.GetMethodParameters("SetShareInfo") 
$inParams.Access = $SD 
$share.psbase.invokemethod("setshareinfo", $inParams, $null)

Вот так немного модифицировав код мы добились более широкого функционала, а именно - возможность добавления множества ACE в едином теле скрипта.

Здесь я переступил логику. По логике следовало сначала разобрать чтение Share Permissions, а потом уже запись, но ввиду одного момента, о котором я рассказал в начале пришлось сначала изучить возможность установки DACL, а потом уже чтение их из Share Permissions. Об этом я уже расскажу следующий раз. Ждите продолжения :)

PowerShell |  ACL |  Shares |  WMI
Friday, July 04, 2008 1:14:00 PM (FLE Daylight Time, UTC+03:00)   Comments [0]    

 

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.


В предыдущих постах я рассказывал про управление списками ACL для объектов файловой системы и реестра. Для этих целей использовались встроенные команддеты Get-Acl и Set-Acl. Весьма тесно с этой темой выступает тема управления правами доступа общего ресурса (т.н. Share Permissions). PowerShell не имеет встроенного механизма управления сетевыми ресусрами, только средствами классов WMI. Управление шарами достаточно очень простое в PowerShell до тех пор, пока это не коснётся вопроса управления Share Permissions. Но начнём с самого простого - создание и удаление сетевого ресурса, а так же маппингом сетевых дисков. Для этого используется WMI класс Win32_Share. По ссылке можно узнать какими свойствами и методами обладает этот класс, поэтому здесь перечислять всё это не буду. Для создания нового сетевого ресурса (шары) нам потребуется метод Create с указанием необходимых параметров (которые так же перечислены по ссылке). Попробуем:

$share = [wmiClass] 'Win32_share'
$share.create("C:\Test", "UserShare", "0", "100", "Network share for users")

В первой строчке я вызвал класс Win32_Share и второй строчкой использовал метод Create, чтобы создать новый сетевой ресурс из папки C:\Test с именем UserShare, тип сетевого ресура - Disk Drive, максимальным количеством подключений равным 100 и описанием (поле Descritpion) Network share for users. В Windows Server 2003 и выше при создании нового общего ресурса права на ресурс назначаются только группе Everyone - Allow Read. Этот код можно записать и одной строчкой вообще без переменных:

([wmiClass] 'Win32_share').Create("C:\Test", "UserShare", "0", "100", "Network share for users")

Эта строка выдаст результат в виде таблицы. Последняя строчка ReturnValue будет содержать код возврата, который содержит информацию об операции. Если это 0, то значит, что команда исполнилась успешно и сетевая шара создалась (таблица сопоставления кода возврата текстовому значению находится в описании метода Create). Чтобы посмотреть список сетевых ресурсов на локальном компьютере достаточно выполнить команду Get-WmiObject Win32_Share. Используя метод Delete можно удалять сетевые ресурсы:

$share = Get-WmiObject Win32_Share | where {$_.name -eq "usershare"}
$share.Delete()

или одной строчкой:

(Get-WmiObject Win32_Share | where {$_.name -eq "usershare"}).Delete()

Здесь вместо параметра Name можно указать любой другой, который содержится к классе Win32_Share. Диски так же можно мапить, причём сделать это можно двумя путями. Первый вариант создаст новый диск PowerShell с именем User и который будет доступен только из PowerShell (из Explorer'а и других приложений он не будет доступен. Иногда это очень удобно) и классический маппинг дисков, который будет доступен из проводника:

New-PSDrive User FileSystem \\DC1\UserShare
(new-object -com WScript.Network).MapNetworkDrive("z:","\\dc1\UserShare")

Как же отмапить диски обратно? С точностью до наоборот:

Remove-PSDrive User
(new-object -com WScript.Network).RemoveNetworkDrive("z:")

В принципе, этот материал достаточно обширно расписан в интернете на англоязычных ресурсах и я опубликовал этот пост в качестве вводной статьи для использования метода SetShareInfo, который является достаточно полезным, интересным и, в то же время, достаточно сложным. Так же в следующей статье расскажу о некоторых недостатках упрощённого создания сетевых папок, как показано в примерах этой статьи. Вобщем, ждите продолжения :)

PowerShell |  ACL |  Shares |  WMI
Thursday, July 03, 2008 12:48:00 PM (FLE Daylight Time, UTC+03:00)   Comments [2]    

 

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.


В 3-й части стати Управление ACL в PowerShell я говорил, что не представляется возможным нативно через метод SetOwner изменить владельца объекта на кого-нибудь, кроме себя или группы Administrators (Администраторы). Эту операцию невозможно было сделать и в GUI в Windows 2000/XP. Но в Windows Server 2003 появилась возможность изменять владельца объекта на любого пользователя или группу из GUI. Для этой операции требуется лишь право Se_Restore - Restore directories and files в локальной политике безопасности, разделе User Rights Assignment. По умолчанию данное право дано администраторам (Administrators) и операторам архива (Backup Operators). Однако, данное право не включено по умолчанию. К сожалению .NET пока что не имеет "родного" метода, чтобы включить данное право, в результате чего используя скрипты PowerShell мы не сможем полноценно использовать новую в Windows Server 2003 функцию. Но не всё так плохо, как может показаться - есть обходное решение данной проблемы. Данную проблему решили в проекте PowerShell Community Extensions.

Для использования этой привилегии необходимо установить пакет PowerShell Community Extensions 1.1.1 (там же и описание возможностей, которые включены в эти расширения). После установки пакета можно начинать использовать данное расширение:

# считываем в переменную список ACL объекта
$ACL = Get-Acl C:\Test
# Переводим имя нового владельца в SID
$Account = new-object System.Security.Principal.NTAccount("TestUser")
# создаём необходимую привилегию для использования и записываем её в переменную
$SeRestore = new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true
# здесь уже записываем созданную привилегию командой SetPrivilege
Set-Privilege $SeRestore
# запись нового владельца объекта стандартным методом SetOwner
$ACL.SetOwner($Account)
# запись нового ACL в папку
$ACL | Set-Acl C:\Test

Это было в расширенном варианте. Данный скрипт можно смело упростить до:

$ACL = Get-Acl C:\Windows
Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true)
$ACL.SetOwner((new-object System.Security.Principal.NTAccount("TestUser")))
$ACL | Set-Acl C:\Test

Решение в виде установки дополнительных расширений не является самым идеальным, но тем не менее позволяет использовать чистый PowerShell для операции (а ведь можно было из PowerShell запустить SubInacl и им уже сменить владельца).

Monday, June 23, 2008 12:30:00 PM (FLE Daylight Time, UTC+03:00)   Comments [0]    

 

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.


При написании скриптов, которые автоматически назначают права NTFS или права доступа к реестру (ну и в других ситуациях) иногда требуется конвертация имени пользователя в его SID и наоборот, у нас есть SID пользователя и нужно узнать его имя в базе SAM или базе Active Directory. Для этих преобразований используется 2 класса - SecurityIdentifier и класс NTAccount. Делается каждая операция в 2 строчки:

$NameToSID = new-object security.principal.ntaccount "User Name"
$NameToSID.translate([security.principal.securityidentifier])

или ванлайнер:

(new-object security.principal.ntaccount "User Name").translate([security.principal.securityidentifier])

Здесь я в первой строке передал в класс NTAccount имя пользователя (выделено жирным) и второй строкой перевёл (дословно Translate) это имя в SID. Разумеется, что если данного имени не будет обнаружено в базе учётных записей, то скрипт вернёт ошибку. Обратная операция выполняется точно так же, только меняются местами классы:

$SIDToName = new-object security.principal.securityidentifier "S-1-5-32-544"
$SIDToName.translate([security.principal.ntaccount])

или вайнлайнер:

(new-object security.principal.securityidentifier "S-1-5-32-544").translate([security.principal.ntaccount])

Здесь я указал один из well-known SID'ов, т.к. реальный SID грозился не влезть в одну строчку. Зато вы можете выполнить эти 2 строчки и узнать, какому аккаунту приналдежит данный SID. Вроде бы очень простенькие операции, но порой очень нужные.

Wednesday, June 18, 2008 12:25:00 PM (FLE Daylight Time, UTC+03:00)   Comments [0]    

 

Previous Page Page 3 of 4 in the PowerShellACL category Next Page
 · 

All content © 2008 - 2012, Vadims Podāns
"Spaces" Theme provided by: Vadims Podāns
About


E-mail - Send mail to the author(s)
Live Messenger -
For english language visitors
Библиотека
Календарик
<May 2012>
SunMonTueWedThuFriSat
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

Карта расположения посетителей
Favorites





Fan list



Disclaimer
Вся информация на сайте предоставляется на условиях «как есть», без предоставления каких-либо гарантий и прав.

При использовании материалов c данного сайта ссылка на оригинальный источник обязательна.
Protected by Copyscape Online Plagiarism Scanner