Weird issue when removing permissions...

This topic contains 3 replies, has 2 voices, and was last updated by Profile photo of Rohn Edwards Rohn Edwards 1 year ago.

  • Author
  • #31094
    Profile photo of ertuu85

    Hello, I have a script that checks files/folders for their permissions and determines if they should be allowed on that folder.

    The issue I'm running into is, say I give c:\test 2 different permissions

    full control for 'this folder only' and
    read&execute for 'This folder, subfolders and files'

    The function gets passed as

    get-generalusers $path $permissions (get-generalusers "c:\test" $regex #where regex = the regex for read and execute)

    if(((get-acl $path).access | ?{$_.identityreference -eq $user}).count -gt 1)
    								$trigger = $false
    								foreach($acl in (get-acl $path).access | ?{$_.identityreference -eq $user} |  ?{$_})
    									foreach($aclmulti in $acl | %{$_.FileSystemRights})
    										write-host "before changes!"
    										if($aclmulti -notmatch $permissions)
    											$x = (get-acl $path)
    											write-host " removing: "
    											write-host "With permissions: "
    											write-host $aclmulti
    											set-acl $path -aclobject $x -erroraction stop
    											write-host "$user has been removed from $path"
    												write-host "Failed to remove $user from $path due to " + $error[0].exception.message
    												$trigger = $true
    												$badgrab+=@("$user is a general user with improper permissions")

    I get to this line section of code, which should remove just the user that has too many permissions, and it does...but then it changes from 'this folder, subdirectoires and files' to just 'subdirectories and files only'

    Why is it changing the 'apply to' type?

    Ignore the write-host's those were just for troubleshooting purposes.

    easy way to test

    $path = "c:\test"

    #ready only or less
    $permissions = "^(read(Execute|File|Data|Extended|Attributes|Permissions|And)+|Synchronize|\s|,|-1610612736)+$"

    $user = "Builtin\Users"

    Then create a folder c:\test, with users with full control with 'this folder only' and users with read&execute on 'This folder, subdirectories and files' and run that code snippet.

    You'll see it changes the user with read&execute from 'this folder, subdirectories and files' to subdirectories and files' when I want it to keep it's original type...

    It appears it's changing it's changing it's propagationflags from 'none' to 'InheritOnly'.

    I'm not sure why, I thought I was just removing it from the list, why is it changing the propagationflags? Or is there a better way to do this?

  • #31110
    Profile photo of Rohn Edwards
    Rohn Edwards

    I think changing 'RemoveAccessRule()' to 'RemoveAccessRuleSpecific()' will fix the problem with the scenario you're describing.

    RemoveAccessRule() takes a reference ACE, and it goes through the entire DACL looking for any ACEs that match the AccessControlType (Allow or Deny) and the principal. Any ACEs that meet those criteria get their permissions and inheritance/propagation flags (I'm going to call these flags 'Applies To' from now on) looked at. If there is an overlap in permission and 'Applies To', the offending permission(s) are removed for that specific 'Applies To'. If that doesn't make sense, don't worry, I'm having a hard time understanding it myself :). An example will probably help. We'll use your scenario:

    A DACL (the access rules) contains two ACEs:
    – Allow FullControl to Users (Applies to Folder)
    – Allow ReadAndExecute to Users (Applies to Folder, SubFolders, and Files)

    If you try to remove that first ACE by calling RemoveAccessRule(), you're asking PowerShell/.NET to remove all 'Allow' permissions for 'Users' that apply to the Folder. The reference ACE being passed to the method says to remove 'FullControl', and that's all permissions. The method is going to go through the DACL, and when it encounters the first ACE, it will see that it only applies to the Folder, and the reference ACE says to remove all permissions that apply to the Folder, so the entire ACE gets removed. When it encounters the next ACE, its going to see that it applies to the Folder, SubFolders, and Files. Since the reference ACE only applies to the Folder, the method is going to remove all permissions (in this case just 'ReadAndExecute') from the ACE that apply to the Folder, leaving an ACE that applies just to SubFolders and Files.

    If you try to remove the first ACE by calling RemoveAccessRuleSpecific(), though, all of the reference ACE properties will need to match any ACEs that actually get removed. So, it will remove the first ACE when it encounters it, and it will ignore the second one.

    If your goal is to ensure that a user never has more than ReadExecute, you could make your reference ACE have the opposite of ReadAndExecute permissions, and make it apply to everything, and then it would go through an ACL and strip any non-ReadAndExecute permissions without affecting the 'Applies To' part of the ACE. Something like this, maybe:

    $Path = 'c:\test'
    $User = 'DOMAIN\SomeUser'
    $PermissionsToRemove = [System.Security.AccessControl.FileSystemRights]::FullControl -bxor ([System.Security.AccessControl.FileSystemRights] 'ReadAndExecute, Synchronize')
    $RefACE = New-Object System.Security.AccessControl.FileSystemAccessRule (
        'ContainerInherit, ObjectInherit',
    $Acl = Get-Acl $Path
    (Get-Item $Path).SetAccessControl($Acl)
  • #31111
    Profile photo of ertuu85

    Wow...that nailed it, .removeaccessrulespecific()

    Thanks so much for that...I was beating my head against the wall!

  • #31113
    Profile photo of Rohn Edwards
    Rohn Edwards

    You're welcome!

You must be logged in to reply to this topic.