Итак, как я и обещал, я вернулся к вопросу изменения ACL принтеров в PowerShell. В первой части (Странности метода SetSecurityDescriptor класса Win32_Printer) я изложил проблематику вопроса. В конечном итоге я сегодня смог найти решение, которое оказалось не совсем понятным, но относительно предсказуемым.
Вернёмся снова к документации MSDN: SetSecurityDescriptor Method of the Win32_Printer Class
Это, конечно же, было моим попустительством, что не указал флаг управления SE_DACL_PRESENT и не включил привилегии SeSecurityPrivilege ("умение читать - первое умение системного администратора" (c) Peter.G). Понимание этого факта пришло после очередного прочтения поста о смене владельца папки (Смена владельца папки или файла в PowerShell (часть 2)). Что касается флагов управления, то выложу здесь значения флагов:
Здесь я выделил жирным тот флаг, который нам нужен.
Добавим эту строчку к скрипту и добавим включение привилегий. И мы должны будем получить примерно такой скрипт:
$user = "everyone"$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 = 393224$ace.AceType = 0$ace.AceFlags = 0$ace.Trustee = $Trustee$SD.DACL = $ace$SD.ControlFlags = 0x0004$Printer = gwmi win32_printer -filter "name='CutePDF Writer'"$Printer.psbase.Scope.Options.EnablePrivileges = $true$inParams = $Printer.psbase.GetMethodParameters("SetSecurityDescriptor")$inParams.Descriptor = $SD$Printer.SetSecurityDescriptor($inParams)
Пробуем запустить его:
[System32] $user = "everyone" [System32] $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() [System32] $ace = ([WMIClass] "Win32_Ace").CreateInstance() [System32] $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() [System32] $SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier]) [System32] [byte[]] $SIDArray = ,0 * $SID.BinaryLength [System32] $SID.GetBinaryForm($SIDArray,0) [System32] $Trustee.Name = $user [System32] $Trustee.SID = $SIDArray [System32] $ace.AccessMask = 393224 [System32] $ace.AceType = 0 [System32] $ace.AceFlags = 0 [System32] $ace.Trustee = $Trustee [System32] $SD.DACL = $ace [System32] $SD.ControlFlags = 0x0004 [System32] $Printer = gwmi win32_printer -filter "name='CutePDF Writer'" [System32] $Printer.psbase.Scope.Options.EnablePrivileges = $true [System32] $inParams = $Printer.psbase.GetMethodParameters("SetSecurityDescriptor") [System32] $inParams.Descriptor = $SD [System32] $Printer.SetSecurityDescriptor($inParams) __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 1 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : ReturnValue : 2147749896 [System32]
И снова мы получаем ошибку, которая указывает, что какой-то параметр вызова неверный. Снова посмотрев предыдущую статью, я стал понимать в чём тут дело. А дело в том, что метод SetSecurityDescriptor в этом классе не принимает параметр Descriptor (хотя он есть в выдаче команды GetSecurityDescriptor) и в MSDN чётко указано:
uint32 SetSecurityDescriptor( [in] Win32_SecurityDescriptor Descriptor );
uint32 SetSecurityDescriptor(
[in] Win32_SecurityDescriptor Descriptor
);
При этом, в методе SetShareInfo класса Win32_Share параметр Access я указывал и всё проходило на "ура". Здесь мы сталкиваемся с отсутствием единого формата использования метода SetSecurityDescriptor (отсутствие единого формата параметров я уже указывал в первой части) для различных WMI классов. И если один приём работает для одного класса, то, увы, далеко не гарантия, что этот же приём сработает для другого. Поэтому выкинем 2 предпоследние строчки из скрипта и в последней строке вместо аргумента $inParams заменим на $SD:
[System32] $user = "everyone" [System32] $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() [System32] $ace = ([WMIClass] "Win32_Ace").CreateInstance() [System32] $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() [System32] $SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier]) [System32] [byte[]] $SIDArray = ,0 * $SID.BinaryLength [System32] $SID.GetBinaryForm($SIDArray,0) [System32] $Trustee.Name = $user [System32] $Trustee.SID = $SIDArray [System32] $ace.AccessMask = 393224 [System32] $ace.AceType = 0 [System32] $ace.AceFlags = 0 [System32] $ace.Trustee = $Trustee [System32] $SD.DACL = $ace [System32] $SD.ControlFlags = 0x0004 [System32] $Printer = gwmi win32_printer -filter "name='CutePDF Writer'" [System32] $Printer.psbase.Scope.Options.EnablePrivileges = $true [System32] $Printer.SetSecurityDescriptor($SD) __GENUS : 2 __CLASS : __PARAMETERS __SUPERCLASS : __DYNASTY : __PARAMETERS __RELPATH : __PROPERTY_COUNT : 1 __DERIVATION : {} __SERVER : __NAMESPACE : __PATH : ReturnValue : 0 [System32]
Вуаля! Мы получили ReturnValue=0, что означает успешное выполнение команды. Давайте убедимся, что группа Everyone имеет маску доступа 393224 (это ReadPermissions, ChangePermissions и Print). Для этого снова вызовем метод GetSecurityDescriptor для нового образца класса Win32_Printer:
[System32] $a = (gwmi win32_Printer -filter "name='cutepdf writer'").getsecuritydescriptor() [System32] $a.descriptor.dacl[0] __GENUS : 2 __CLASS : Win32_ACE __SUPERCLASS : __ACE __DYNASTY : __SecurityRelatedClass __RELPATH : __PROPERTY_COUNT : 7 __DERIVATION : {__ACE, __SecurityRelatedClass} __SERVER : __NAMESPACE : __PATH : AccessMask : 393224 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : TIME_CREATED : Trustee : System.Management.ManagementBaseObject [System32] $a.descriptor.dacl[0].trustee __GENUS : 2 __CLASS : Win32_Trustee __SUPERCLASS : __Trustee __DYNASTY : __SecurityRelatedClass __RELPATH : __PROPERTY_COUNT : 6 __DERIVATION : {__Trustee, __SecurityRelatedClass} __SERVER : __NAMESPACE : __PATH : Domain : Name : Everyone SID : {1, 1, 0, 0...} SidLength : 12 SIDString : S-1-1-0 TIME_CREATED : [System32]
Вот теперь мы видим нашу маску доступа (AccessMask=393224) в корне DACL и нашего уважаемого everyone в Trustee.
Примечание: данный скрипт удаляет все имеющиеся ACE из ACL принтера и записывает новый единственный ACE. Не забывайте об этом.
Теперь я закрываю этот вопрос. Что же дальше? А дальше будет вот что: я напишу готовый набор функций для управления ACL списками принтеров. Какой это будет набор - я пока в процессе разработки его структуры, но однозначно будут функции вида Get- Set- Add- Remove- PrinterPermission. Возможно будут добавлены функции для владельцев. Но об этом уже в следующий раз, так что продолжение следует однозначно
Remember Me