Changing permissions with PowerShell does not apply to children

When I set a new file system rule with powershell and set-acl, I set inheritance flags to propagate to child and leaf objects

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

When I look at the resolution in Explorer .. on the security .. advanced .. tab, the distribution is set correctly. But if I look at the children themselves, they DO NOT show the new safety rule.

If in Explorer I add another rule with a different SID .. and save it (without forcibly choosing "replace all permissions of child objects ..."). Then the children, and the manual, and the powershell rule appear on the children. It’s as if there is some kind of kickstart needed to get the kids to pick up the new common rule. What am I missing for children to display the new rule?

+5
source share
3 answers

I had the same logical problem ...

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

With this last “no,” you say: don't preach ... Change to:

$acl.AddAccessRule((New-Object System.Security.AccessControl.FileSystemAccessRule(
"username","FullControl", "ContainerInherit, ObjectInherit", "InheritOnly", "Allow")))

and it will distribute your settings. Check out the access rule settings here: http://msdn.microsoft.com/en-us/library/ms147785.aspx

: http://msdn.microsoft.com/en-us/library/system.security.accesscontrol.propagationflags.aspx

+5

. , . , . - Windows Explorer. 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
+1

I am combing the Internet and a few StackOverflow questions trying to figure this out. I may not have a better solution, but I think this satisfies the question. According to my research, Powershell Set-Acljust doesn't handle inheritance properly. The key to the code below is two things: an object System.Security.AccessControl.DirectorySecurityand using an alternative method to set the ACL $dir.SetAccessControl(). Children of the target folder (both folders and files) will successfully inherit the permissions attached to your target folder.

Call example:

$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

Functions:

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)
  }
}
0
source

All Articles