[Resolved] Removing orphaned SIDs from directories

Welcome Forums General PowerShell Q&A [Resolved] Removing orphaned SIDs from directories

This topic contains 4 replies, has 3 voices, and was last updated by

 
Participant
6 months, 3 weeks ago.

  • Author
    Posts
  • #101131

    Participant
    Points: 26
    Rank: Member

    I am working with a customer to do some cleanup of their process for setting NTFS permissions on DFS shares. Currently, many of their shared folders have orphaned SIDs when looking at the security tab. I thought something quick like this would clean it up:

    $Path = "P:"
    
        $aFolders = Get-ChildItem -Path $Path -Directory
            foreach ($folder in $aFolders) {
                $acl = Get-Acl -Path "$($Path)\$($folder.Name)"
                    foreach($acc in $acl.access ) { 
                        $value = $acc.IdentityReference.Value 
                            if($value -match "S-1-5-*") { 
                                $ACL.RemoveAccessRule($acc) | Out-Null 
                                Set-Acl -Path "$($Path)\$($folder.Name)" -AclObject $acl -ErrorAction Stop 
                                Write-Host "Removed Orphans from $($Path)\$($folder.Name)" 
                            }
                    }
            }
    

    But it does not remove any of them. If I pipe the Get-Acl line out to a grid-view, I see all of the ACLs except the S-1-5* orphans. Just curious why that would be, as I thought get-acl would show me everything. And has anyone else resolved this kind of issue in another way?

    P.S. I also tried the NTFSSecurity module and get the same behavior, none of the orphans are shown

  • #101145

    Participant
    Points: 5
    Rank: Member

    I don't have any orphan SIDs to test, but I think if you change your conditional operator -match to -like you might have better results. -Match is for regex and -like is for wildcards. I don't think "S-1-5-*" would be the regular expression for what you are looking for. Also on line 5 and 11 of your script if you use the FullName property you wouldn't have to do the "$($Path)\$($folder.Name)"

  • #101148

    Participant
    Points: 0
    Rank: Member

    The code you have *should* remove any explicitly defined ACEs that have principals that can't be resolved. Note that just because the computer you're currently on can't resolve a principal's SID to a user or group object doesn't necessarily mean that it's orphaned. True orhpaned ACEs do exhibit the same behavior, though, so I don't have the perfect answer for detecting truly orphaned ACEs. I'd just recommend making a backup of any ACEs before you remove them just in case.

    Back to your specific problem: is there any chance the ACEs you can't remove are inherited? You should be able to tell that by looking at the $acc.IsInherited property. If it's inherited, you can remove it (you have to go higher up and remove it from the parent that has it explicitly defined).

    Next, you said Get-Acl doesn't show it when you pipe it to Out-GridView? Do you mean you can see it from the terminal, but not in the OGV window? Or do you mean you can't see it in the terminal, either, but only see it in the Explorer GUI?

    Finally, while your code looks like it should work, a few suggestions:
    1. Set-Acl only needs to be called once for each folder. The whole security descriptor should be stored in the $acl variable, and you can call RemoveAccessRule() (and any other ACL modification method) multiple times, then call Set-Acl once when you're done. So I'd move Set-Acl outside of the foreach() block (it shouldn't hurt anything the way it's done, but it would save some time if you try to do this on a lot of folders at once if you move it)
    2. Mike already mentioned this, but $folder is an object and should have access to the entire path of the folder. Try $folder.FullName instead of "$($Path)\$($folder.Name)
    3. This code could remove non orphaned ACEs if you ever had a user whose name started with 'S-1-5-'. That almost definitely wouldn't happen, but it might be cleaner to test the $acc.IdentityReference type instead of the value of it's string contents. Either of these might work (I say might because I haven't tested them):

    if ($acc.IdentityReference -is [System.Security.Principal.SecurityIdentifier]) {
        # It should have been turned into an [NtAccount] object if it could have been, so
        # this might be an orphaned ACE
    }
    
    ## or ##
    
    $CantTranslate = try {
        $NtAccount = $acc.IdentityReference.Translate([System.Security.Principal.NTAccount])
        $false
    }
    catch {
        $true
    }
    if ($CantTranslate) {
        # This computer couldn't translate the principal, so it might be orphaned
    }
    
  • #101181

    Participant
    Points: 26
    Rank: Member

    Thanks for the suggestions. I did some further testing on some of the folders, assigning groups and then deleting the groups from A.D. (working with a copy of prod), and my original code identified those orphans just fine. In talking to the on-site team for this customer, they had some issues in the past with the old script; techs would often realize they'd typed in the wrong group name and hit cancel, causing the script to barf after permissions had already been set on x number of folders, then delete the group. I think it may have led to some instability which contributed to what I was seeing (or not seeing, rather). I spent an hour going through the tedious task of removing these orphaned orphans manually, and have confirmed in subsequent tests that things are working as they should.

    Rohn, I will definitely look at your code for how I can reduce and simplify. Thanks!

  • #101185

    Participant
    Points: 0
    Rank: Member

    Glad you got it working. By the way, you can create orphaned ACEs without having to create temporary user/group accounts and delete them:

    $SD = Get-Acl C:\path\to\folder\
    $SD.AddAccessRule((
        New-Object System.Security.AccessControl.FileSystemAccessRule (
            [System.Security.Principal.SecurityIdentifier] 'S-1-5-100-1-2-3-4',  # Dummy SID
            'Read',
            'Deny'
        )
    ))
    $SD | Set-Acl
    

    That might make it a little easier to set up test cases to see how your code is working.

The topic ‘[Resolved] Removing orphaned SIDs from directories’ is closed to new replies.