使用 powershell 更改权限不会传播给孩子

Posted

技术标签:

【中文标题】使用 powershell 更改权限不会传播给孩子【英文标题】:Changing permissions with powershell doesn't propogate to children 【发布时间】:2012-06-10 17:54:09 【问题描述】:

当我使用 powershell 和 set-acl 设置新的文件系统访问规则时,我设置了继承标志以传播到子对象和叶对象

$acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule(
    "username","FullControl", "ContainerInherit, ObjectInherit", "None", "Allow")))
Set-Acl -path $filename -aclObject $acl

当我在安全选项卡中查看资源管理器中的权限时.. 高级.. 传播设置正确。但如果我看看孩子们自己,他们并没有显示新的安全规则。

如果在资源管理器中,我添加另一个具有不同 SID 的规则.. 并保存它(不强制选择“替换所有子对象权限...”)。然后手册和 powershell 规则都会出现在孩子身上。好像需要某种启动来让孩子们接受新的传播规则。为了让子对象显示添加的新规则,我缺少什么?

【问题讨论】:

什么是 $acl ?您是否尝试将 $filename 的安全描述符复制到 $acl 【参考方案1】:

我也遇到过同样的逻辑问题……

$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

【讨论】:

【参考方案2】:

这很奇怪。我有类似的代码以相同的方式设置权限。我从来没有检查过孩子的权限是否被设置。这可能只是 Windows Explorer UI 中的一些奇怪之处。您是否使用 PowerShell 获取其中一个孩子的 ACL 以检查权限是否被应用?

供参考,这里是the code I use to grant permissions:

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

【讨论】:

【参考方案3】:

我一直在搜索互联网和几个 *** 问题,试图解决这个问题。我可能没有最好的解决方案,但我认为它满足了这个问题。根据我的研究,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 AUTHORITY\SYSTEM","CREATOR OWNER","BUILTIN\Administrators"
    $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)
  

【讨论】:

以上是关于使用 powershell 更改权限不会传播给孩子的主要内容,如果未能解决你的问题,请参考以下文章

通过 PowerShell 更改 DCOM 对象权限后要重新启动啥?

使用 set-acl 和 powershell 设置继承和传播标志

ReactJS setState 更改不会从父组件传播到子组件[重复]

如何在 ssms 中更改用户通过 powershell 连接到数据库引擎的权限?

BrowserSync 文件更改不会随 Vagrant 传播

通过 Powershell 脚本将权限角色分配给服务主体