Наткнулся на него когда готовил ответ для ньюсгрупп. Как известно, владелец объекта может спокойно изменять списки ACL объектов минуя все их ограничения пользуясь неоткланяемым правом владения объектом. Поэтому, если из ACL объекта удалить все ACE и сохранить, то мы из проводника можем в любой момент вызвать вкладку Security объекта и задать требуемые ACE. Однако, это возможно только из графического интерфейса проводника сделать. При использовании скрипта и командлета Set-Acl мы этого сделать не сможем. Продемонстрирую проблему:
[C:\] whoami
contoso\administrator
[C:\] Get-Acl C:\Test | fl
Path : Microsoft.PowerShell.Core\FileSystem::C:\Test
Owner : CONTOSO\administrator
Group : CONTOSO\Domain Users
Access :
Audit :
Sddl : O:LAG:DUD:PAI
[C:\] $acl = Get-Acl C:\Test
[C:\] $accessrule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrator","FullControl", "Allow"
)
[C:\] $acl.AddAccessRule($accessRule)
[C:\] $acl | Set-Acl C:\Test
Set-Acl : Attempted to perform an unauthorized operation.
At line:1 char:15
+ $acl | Set-Acl <<<< C:\Test
+ CategoryInfo : PermissionDenied: (C:\Test:String) [Set-Acl], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetAclCommand
[C:\]
Как видите, текущий пользователь (администратор) является владельцем папки. Но все ACE в ACL пустые (секция Access). Пользуясь правами владельца, всё же, я не могу ничего сделать с этим списком. Как выяснилось в процессе исследования, пользователю-владельцу, который собирается менять ACL необходимо иметь явно назначенное или унаследованное разрешение TakeOwnership. Никаких Read/ChangePermissions и прочих не надо. Теперь я из проводника добавлю себе право TakeOwnership и попробую снова исполнить код:
[C:\] Get-Acl C:\Test | fl
Path : Microsoft.PowerShell.Core\FileSystem::C:\Test
Owner : CONTOSO\administrator
Group : CONTOSO\Domain Users
Access : CONTOSO\administrator Allow TakeOwnership, Synchronize
Audit :
Sddl : O:LAG:DUD:PAI(A;OICI;0x180000;;;LA)
[C:\] $acl = Get-Acl C:\Test
[C:\] $accessrule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrator","FullControl", "Allow"
)
[C:\] $acl.AddAccessRule($accessRule)
[C:\] $acl | Set-Acl C:\Test
[C:\] Get-Acl C:\Test | fl
Path : Microsoft.PowerShell.Core\FileSystem::C:\Test
Owner : CONTOSO\administrator
Group : CONTOSO\Domain Users
Access : CONTOSO\Administrator Allow TakeOwnership, Synchronize
CONTOSO\Administrator Allow FullControl
Audit :
Sddl : O:LAG:DUD:PAI(A;OICI;0x180000;;;LA)(A;;FA;;;LA)
[C:\]
Как видите, теперь всё получилось. Я не понимаю, зачем мне нужно иметь право TakeOwnership, чтобы изменить ACL, если я являюсь владельцем. В реальной среде это может вызвать определённые трудности, как неадекватное поведение скрипта, который будет сыпать ошибками (в связи с чем появился вопрос на ньюсгруппах).
Зато мною не очень любимый WMI справился с задачей на ура, израсходовав кода при этом во много раз больше, чем с использованием командлетов. И в итоге получилось вот:
$path = "C:\Test"
$user = "Administrator"
$path = $path.replace("\", "\\")
$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]"FullControl"
$ace.AceFlags = "0x3"
$ace.AceType = 0
$ace.Trustee = $trustee
# читаем текущий ACL с объекта
$oldDACL = (gwmi Win32_LogicalFileSecuritySetting -filter "path='$path'").GetSecurityDescriptor().Descriptor.DACL
# добавляем его к пустому объекту DACL
$SD.DACL = $oldDACL
# и добавляем новый ACE
$SD.DACL += @($ace.psobject.baseobject)
# устанавливаем флаг SE_DACL_PRESENT
$SD.ControlFlags = "0x4"
$folder = gwmi Win32_LogicalFileSecuritySetting -filter "path='$path'"
$folder.setsecuritydescriptor($SD)
Я больше склонен доверять WMI и констатировать факт, что он работает честно – даёт мне делать с объектом что угодно и как угодно признавая мои права владения.
Я считаю, что Set-Acl был сильно не прав, отказав мне в изменении пустых ACE, поэтому отрепортил это дело на connect:
https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=418906&SiteID=99