当我使用 powershell 和 set-acl 设置新的文件系统访问规则时,我将继承标志设置为传播到子对象和叶对象
$acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule(
"username","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")))
Set-Acl -path $filename -aclObject $acl
当我在资源管理器中查看权限时..在安全选项卡中..高级..传播设置正确。 但是,如果我看看孩子们自己,他们并没有表现出新的安全规则。
如果在资源管理器中,我添加另一个具有不同 SID 的规则.. 并保存它(不强制选择"替换所有子对象权限...")。 然后,手动和电源外壳规则都显示在子节点上。 就好像需要某种启动来让孩子们接受新的传播规则。 我缺少什么才能使子对象显示添加的新规则?
我遇到了同样的逻辑问题......
$acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule(
"username","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")))
用最后一个"没有",你说:不要传播...更改为:
$acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule(
"username","FullControl", "ContainerInherit, ObjectInherit", "InheritOnly", "Allow")))
它将传播您的设置。在此处查看访问规则选项:http://msdn.microsoft.com/en-us/library/ms147785.aspx
这些是传播标志: http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.propagationflags.aspx
这很奇怪。 我有类似的代码,以相同的方式设置权限。 不过,我从未检查过孩子的权限是否被设置。 这可能只是Windows资源管理器UI中的一些奇怪之处。 是否已使用 PowerShell 获取其中一个子项上的 ACL,以检查权限是否应用?
作为参考,以下是我用于授予权限的代码:
foreach( $permission in $Permissions )
{
$right = ($permission -as "Security.AccessControl.FileSystemRights")
if( -not $right )
{
throw "Invalid FileSystemRights: $permission. Must be one of $([Enum]::GetNames("Security.AccessControl.FileSystemRights"))."
}
$rights = $rights -bor $right
}
Write-Host "Granting $Identity $Permissions on $Path."
# We don't use Get-Acl because it returns the whole security descriptor, which includes owner information.
# When passed to Set-Acl, this causes intermittent errors. So, we just grab the ACL portion of the security descriptor.
# See http://www.bilalaslam.com/2010/12/14/powershell-workaround-for-the-security-identifier-is-not-allowed-to-be-the-owner-of-this-object-with-set-acl/
$currentAcl = (Get-Item $Path).GetAccessControl("Access")
$inheritanceFlags = [Security.AccessControl.InheritanceFlags]::None
if( Test-Path $Path -PathType Container )
{
$inheritanceFlags = ([Security.AccessControl.InheritanceFlags]::ContainerInherit -bor `
[Security.AccessControl.InheritanceFlags]::ObjectInherit)
}
$propagationFlags = [Security.AccessControl.PropagationFlags]::None
$accessRule = New-Object "Security.AccessControl.FileSystemAccessRule" $identity,$rights,$inheritanceFlags,$propagationFlags,"Allow"
$currentAcl.SetAccessRule( $accessRule )
Set-Acl $Path $currentAcl
我一直在互联网上搜索和几个 StackOverflow 问题,试图解决这个问题。 我可能没有最好的解决方案,但我认为它满足了这个问题。 根据我的研究,Powershell的Set-Acl
只是没有正确处理继承。 以下代码的关键是两件事:System.Security.AccessControl.DirectorySecurity
对象和使用替代方法来设置 ACL $dir.SetAccessControl()
目标文件夹(文件夹和文件)的子文件夹将成功继承附加到目标文件夹的权限。
调用示例:
$newACL=@()
$newACL+=New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList @("MyLocalGroup1","ReadAndExecute,Synchronize","ContainerInherit,ObjectInherit","None","Allow")
$newACL+=New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList @("MyLocalGroup2","FullControl","ContainerInherit,ObjectInherit","None","Allow")
Set-FolderPermissions -Path $Path -KeepDefault -ResetOwner -AccessRuleList $newACL
功能:
function Set-FolderPermissions {
# The whole point of this script is because Set-Acl bungles inheritance
[CmdletBinding(SupportsShouldProcess=$false)]
Param ([Parameter(Mandatory=$true, ValueFromPipeline=$false)] [ValidateNotNullOrEmpty()] [string]$Path,
[Parameter(Mandatory=$false, ValueFromPipeline=$false)] [switch]$KeepExisting,
[Parameter(Mandatory=$false, ValueFromPipeline=$false)] [switch]$KeepDefault,
[Parameter(Mandatory=$false, ValueFromPipeline=$false)] [switch]$ResetOwner,
[Parameter(Mandatory=$true, ValueFromPipeline=$false)] [System.Security.AccessControl.FileSystemAccessRule[]]$AccessRuleList)
Process {
$aryDefaultACL="NT AUTHORITYSYSTEM","CREATOR OWNER","BUILTINAdministrators"
$tempACL=@()
$owner=New-Object System.Security.Principal.NTAccount("BUILTIN","Administrators")
$acl=Get-Acl -Path $Path
# Save only needed individual rules.
if ($KeepExisting.IsPresent) {
if ($KeepDefault.IsPresent) {
# Keep everything
$acl.Access | ForEach-Object { $tempACL+=$_ }
}
else {
# Remove the defaults, keep everything else
for ($i=0; $i -lt $acl.Access.Count; $i++) {
if (!$aryDefaultACL.Contains($acl.Access[$i].IdentityReference.Value)) { $tempACL+=$acl.Access[$i] }
}
}
}
else {
if ($KeepDefault.IsPresent) {
# Keep only the default, drop everything else
for ($i=0; $i -lt $acl.Access.Count; $i++) {
if ($aryDefaultACL.Contains($acl.Access[$i].IdentityReference.Value)) { $tempACL+=$acl.Access[$i] }
}
}
#else { # Do nothing, because $TempACL is already empty. }
}
# Add the new rules
# I could have been modifying $acl this whole time, but it turns out $tempACL=$acl doesn't work so well.
# As the rules are removed from $acl, they are also removed from $tempACL
for ($i=0; $i -lt $AccessRuleList.Count; $i++) { $tempACL+=$AccessRuleList[$i] }
# This is the object that you're looking for...
$aclDS=New-Object System.Security.AccessControl.DirectorySecurity -ArgumentList @($Path,[System.Security.AccessControl.AccessControlSections]::None)
# The object, apparently, comes with a bonus rule...
$aclDS.RemoveAccessRuleSpecific($aclDS.Access[0])
# Add the rules to our new object
for ($i=0; $i -lt $tempACL.Count; $i++) {
# I tried adding the rules directly but they didn't work. I have to re-create them.
$tempRule=New-Object System.Security.AccessControl.FileSystemAccessRule -ArgumentList @($tempACL[$i].IdentityReference,$tempACL[$i].FileSystemRights,$tempACL[$i].InheritanceFlags,$tempACL[$i].PropagationFlags,$tempACL[$i].AccessControlType)
$aclDS.AddAccessRule($tempRule)
}
# This has to be done after all the rules are added, otherwise it doesn't work
$aclDS.SetAccessRuleProtection($true,$false)
if ($ResetOwner.IsPresent) {
# Often, the default owner is SYSTEM. This ownership will prevent you from making any changes.
# So, we change owner to the local Administrator
$acl.SetOwner($owner)
# We have to apply it now because we are applying our ACLs in two stages. We won't be using Set-Acl again.
Set-Acl -Path $Path -AclObject $acl
}
# Lastly, apply our ACls
$dir=Get-Item -Path $Path
$dir.SetAccessControl($aclDS)
}
}