Vadims 的个人资料Vadims Podans's former b...照片日志列表更多 工具 帮助

日志


2008/7/8

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

В предыдущей части мы рассмотрели чтение Share Permissions, их редактирование и удаление ACE из полного списка ACL. Здесь осталось рассмотреть вопрос добавления участников безопасности в DACL сетевой шары. Этот процесс, к сожалению, не такой и простой, как может показаться, но тем не менее его тоже нужно решать. Для решения этой задачи нам нужно создать такой же объект с такими же свойствами как и содержимое $ShareInfo. Давайте посмотрим, какими свойствами обладают элементы массива $ShareInfo:

[C:\] $shareinfo | Get-Member

   TypeName: System.Management.Automation.PSCustomObject

Name           MemberType   Definition
----              ----------         ----------
Equals           Method          System.Boolean Equals(Object obj)
GetHashCode Method          System.Int32 GetHashCode()
GetType         Method         System.Type GetType()
ToString         Method         System.String ToString()
AccessMask  NoteProperty   System.UInt32 AccessMask=1245631
AceFlags       NoteProperty   System.UInt32 AceFlags=0
AceType       NoteProperty   System.UInt32 AceType=0
Description   NoteProperty   System.Management.Automation.PSObject
Domain        NoteProperty   System.Management.Automation.PSObject
Name           NoteProperty   System.Management.Automation.PSObject
Path             NoteProperty   System.Management.Automation.PSObject
SID              NoteProperty   System.Management.Automation.PSObject
User             NoteProperty   System.Management.Automation.PSObject

Нас тут будут интересовать только NoteProperty. Давайте теперь исходя из этих данных создадим свой объект, который будет обладать вот этими свойствами. Тип объекта будет такой же - System.Management.Automation.PSObject  (без Custom). Новый объект создаётся командной New-Object, а члены объекта создаются командой Add-Member:

# создаём новый объект с типом System.Management.Automation.PSObject
$AddInfo = new-object System.Management.Automation.PSObject
# добавляем по очереди членов NoteProperty объекта как и в исходном варианте
$AddInfo | add-member NoteProperty Name  ([PSObject])
$AddInfo | add-member NoteProperty Path  ([PSObject])
$AddInfo | add-member NoteProperty Description  ([PSObject])
$AddInfo | add-member NoteProperty AccessMask  ([uint32])
$AddInfo | add-member NoteProperty AceFlags  ([uint32])
$AddInfo | add-member NoteProperty AceType  ([uint32])
$AddInfo | add-member NoteProperty User  ([PSObject])
$AddInfo | add-member NoteProperty Domain  ([PSObject])
$AddInfo | add-member NoteProperty SID  ([PSObject])

Теперь можно посмотреть на результаты нашей работы:

[C:\] $AddInfo

Name           :
Path             :
Description   :
AccessMask  : 0
AceFlags       : 0
AceType       : 0
User             :
Domain        :
SID              :

Ну что ж, уже лучше, теперь можно заполнять эти поля в соответствии с нашими требованиями. Но чтобы не заполнять все поля вручную, предполагается, что для добавления нового участника безопасности в Share Permissions пользователь укажет только имя сетевой шары, имя пользователя, маску доступа и тип доступа (Allow/Deny). Поэтому нам потребуется вытащить информацию о текущей шаре (которая общая для всей шары, как имя, путь, описание и т.д.) и передать эти значения в новую переменную $AddInfo. Остальную часть информации мы обработаем на основании уже переданных параметров и запишем оставшиеся поля переменной $AddInfo, которая в конечном итоге будет содержать всю необходимую информацию. Т.к. уже неоднократно говорилось в предыдущих частях, что метод SetShareInfo перезаписывает полностью информацию о сетевой шаре, поэтому для сохранения существующих ACE мы произведём уже известным способом чтение существующих DACL и сделаем инкремент (добавим к существующим DACL нами созданный DACL). Когда все данные будут скомпонованы мы произведём запись обновлённого списка DACL в ACL шары. Итак, поехали:

# принимаем вводные параметры от пользователя из командной строки
param ($share, $user, $AccessMask, $AceType)
# предполагается, что данный скрипт выполняет только добавление участников безопасности
# поэтому сразу создаём новый объект с необходимыми членами и указанием типа принимаемых
# данных
$AddInfo = New-Object System.Management.Automation.PSObject
$AddInfo | Add-Member NoteProperty Name  ([PSObject])
$AddInfo | Add-Member NoteProperty Path  ([PSObject])
$AddInfo | Add-Member NoteProperty Description  ([PSObject])
$AddInfo | Add-Member NoteProperty AccessMask  ([uint32])
$AddInfo | Add-Member NoteProperty AceFlags  ([uint32])
$AddInfo | Add-Member NoteProperty AceType  ([uint32])
$AddInfo | Add-Member NoteProperty User  ([PSObject])
$AddInfo | Add-Member NoteProperty Domain  ([PSObject])
$AddInfo | Add-Member NoteProperty SID  ([PSObject])
# зная имя сетевой шары делаем её поиск и копируем информацию о имени, пути
# и описании (поле Description) и выставим прочие параметры
$CustomShare = Get-WmiObject Win32_Share -filter "name = '$share'"
$AddInfo.Name = $share
$AddInfo.Path = $CustomShare.Path
$AddInfo.Description = $CustomShare.Description
$AddInfo.Domain = $null
$AddInfo.AceFlags = 3
# далее заполняется информация о пользователе и его доступе, поэтому
# дальше мы ничего не копируем, а обрабатываем уже переданные параметры:

$AddInfo.User = $user
# преобразовываем маску доступа из текстовой в численный формат с использованием
# конструкции Switch.

switch ($AccessMask) {
  "Full"   {$AddInfo.AccessMask = 2032127}
  "Change" {$AddInfo.AccessMask = 1245631}
  "Read"   {$AddInfo.AccessMask = 1179817}
}
# таким же образом обрабатываем и переменную $AceType:
switch ($AceType) {
  "Allow"   {$AddInfo.AceType = 0}
  "Deny" {$AddInfo.AceType = 1}
}
# заполняем последнее поле SID путём трансляции имени пользователя/группы в его SID
$AddInfo.SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])
# теперь считываем текущий список DACL с указанной сетевой шары в переменную $ShareInfo
$shares = Get-WmiObject Win32_Share -filter "name='$share'"
$Shareinfo = @()
foreach ($share in $shares) {
  $shareSec = Get-WmiObject Win32_LogicalShareSecuritySetting  -filter "name='$($share.name)'"
  if($shareSec) {
    $sd = $sharesec.GetSecurityDescriptor()
    $ShareInfo += $sd.Descriptor.DACL | ForEach-Object {
      $_ | 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

$ShareInfo += $AddInfo
# Можно для верности убедиться, что $ShareInfo обладает всей необходимой информацией, которую
# теперь можно записать в шару. В принципе, эта строчка несёт в себе лишь отладочную информацию
# и когда отладка будет завершена эту строчку можно будет удалить или закомментировать для
# отладки скрипта в будущем.

$ShareInfo
# Если всё в порядке, то можно перезаписывать эти данные в DACL указанной шары:
$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
  }
$inParams = $CustomShare.psbase.GetMethodParameters("SetShareInfo")
$inParams.Access = $SD
$CustomShare.psbase.invokemethod("setshareinfo", $inParams, $null)
}

Формат запуска данного скрипта из командной строки CMD или меню Run будет следующим:

powershell %path%\AddUser.ps1 -share "Имя сетевой шары" -user "имя добавляемой группы" -mask "маска доступа, Full/Change/Read" -type "тип доступа, Allow/Deny"

эту команду следует выполнять в одну строчку. В качестве переменной %path% нужно указать путь к папке со скриптом, если он заранее не добавлен в системную переменную %path%. В качестве маски доступа нужно указать одно из 3-х значений, которое может быть Full, Change или Read. Более одного параметра указывать нельзя. Ну и в качестве типа доступа указать либо Allow, что даст доступ, либо Deny, что явно запретит доступ.

Ну вот как бы и всё на данном этапе. Здесь я много чего не пояснял, т.к. достаточно (в моём понимании) разобрал в предыдущих 3-х частях о работе с сетевыми шарами в PowerShell. Но это ещё не всё. Главный девиз PowerShell - быть удобным для использования и кратким для написания (это я сам придумал :) ), однако при работе с сетевыми шарами это совершенно не прослеживается и даже может создаться впечатление громоздкости (хотя тот, кто считает этот код громоздким может написать скрипт короче на VBS с использованием только WMI/.NET :) ), поэтому в следующей части я постараюсь исправить сей момент путём написания единого (относительно компактного по возможности) и представить его как готовое решение, которое в работе будет действительно удобным. Не отключайтесь, продолжение обязательно будет :)

p.s. Данный скрипт не обязательно является самым простым решением, т.к. возможно, что данную операцию можно провести более удобным и изящным способом (хотя, после чтения документации на MSDN мне так не кажется, что это возможно), но в любом случае адекватные замечания/поправки/дополнения к этому скрипту всячески приветствуются.

评论

请稍候...
很抱歉,您输入的评论太长。请缩短您的评论。
您没有输入任何内容,请重试。
很抱歉,我们当前无法添加您的评论。请稍后重试。
若要添加评论,需要您的家长授予您相应权限。请求权限
您的家长禁用了评论功能。
很抱歉,我们当前无法删除您的评论。请稍后重试。
您已超过了一天之内允许提供的评论数上限。请在 24 小时后重试。
因为我们的系统表明您可能在向其他用户提供垃圾评论,您的帐户已禁用了评论功能。如果您认为我们错误地禁用了您的帐户,请联系 Windows Live 支持部门
完成下面的安全检查,您提供评论的过程才能完成。
您在安全检查中键入的字符必须与图片或音频中的字符一致。
PodānsVadi​ms 在此页禁用了评论功能。

引用通告

此日志的引用通告 URL 是:
http://vpodans.spaces.live.com/blog/cns!BB1419A2CFC1E008!186.trak
引用此项的网络日志