Click here to Skip to main content
15,885,914 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to create a program to delete orphaned SIDs from user folders. What I have can enumerate the orphaned SIDs and list them in a listbox but doesn't purge them from the ACL. Here is what I have so far:

VB
Imports System.ComponentModel
Imports System.IO
Imports System.Security.AccessControl
Imports System.Security.Principal
Imports System.Threading

Public Class Form1
    Dim bw As BackgroundWorker = New BackgroundWorker
    Public Delegate Sub PictureVisibilityDelegate(ByVal visibility As Boolean)
    Dim ChangePictureVisibility As PictureVisibilityDelegate

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        AddHandler bw.DoWork, AddressOf bw_DoWork
        AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
        ChangePictureVisibility = AddressOf ChangeVisibility
        TextBox1.Focus()
    End Sub
    '-----------------------------------------------Go Button Click--------------------------------------------------
    Private Sub BtnGo_Click(sender As Object, e As EventArgs) Handles BtnGo.Click
        Me.Invoke(ChangePictureVisibility, True)
        Me.BtnGo.Enabled = False
        Me.BtnClear.Enabled = False
        Me.BtnExit.Enabled = True
        If Not bw.IsBusy = True Then
            bw.RunWorkerAsync()
        End If
    End Sub
    '-----------------------------------------------Folder Browser Selection-----------------------------------------
    Private Sub FoldBrowse_Click(sender As Object, e As EventArgs) Handles FoldBrowse.Click
        If FolderBrowserDialog1.ShowDialog() = DialogResult.OK Then
            Me.TextBox1.Text = FolderBrowserDialog1.SelectedPath
        End If
    End Sub

    Private Sub BtnClear_Click(sender As Object, e As EventArgs) Handles BtnClear.Click
        TextBox1.Text = ""
    End Sub
    '-----------------------------------------------Exit Button Click--------------------------------------------------
    Private Sub BtnExit_Click(sender As Object, e As EventArgs) Handles BtnExit.Click
        If bw.IsBusy Then
            'If it supports cancellation, Cancel It  
            If bw.WorkerSupportsCancellation Then
                ' Tell the Background Worker to stop working.  
                bw.CancelAsync()
            End If
        End If

        ' Disable Buttons  
        Me.BtnExit.Enabled = False
        Me.Close()
    End Sub
    '-----------------------------------------------Background Worker--------------------------------------------------
    Private Sub bw_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
        CheckForIllegalCrossThreadCalls = False
        Dim setFolder As String = TextBox1.Text
        HandleDir(setFolder)
    End Sub


    '-----------------------------------------------Background Work Completed------------------------------------------
    Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        ' Enable Buttons 
        WaitStatus.Close()
        Me.BtnGo.Enabled = True
        Me.BtnClear.Enabled = True
        Me.Refresh()
        MessageBox.Show("Orphaned SID Cleaner has finished cleaning your selection.", "Orphaned SID Cleaner", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification, False)
    End Sub
    '-----------------------------------------------Check if log file is in use----------------------------------------
    Public Function FileInUse(ByVal sFile As String) As Boolean
        If System.IO.File.Exists(sFile) Then
            Try
                Dim F As Short = FreeFile()
                FileOpen(F, sFile, OpenMode.Binary, OpenAccess.ReadWrite, OpenShare.LockReadWrite)
                FileClose(F)
            Catch
                Return True
            End Try
        End If
    End Function
    '-----------------------------------------------Recursion---------------------------------------------------------
    Sub HandleDir(Path As String)
        Dim dinfo As New DirectoryInfo(TextBox1.Text)
        Dim dSecurity As DirectorySecurity = dinfo.GetAccessControl(AccessControlSections.All)
        Try
            If FileInUse("c:\orphansid.txt") = True Then
                Thread.Sleep(2)
                My.Computer.FileSystem.WriteAllText("c:\orphansid.txt", "Scanning:" & Path & vbCrLf, True)
            Else
                My.Computer.FileSystem.WriteAllText("c:\orphansid.txt", "Scanning:" & Path & vbCrLf, True)
                Thread.Sleep(2)
            End If

            Dim security As DirectorySecurity = Directory.GetAccessControl(Path)
            Dim rules = security.GetAccessRules(True, False, GetType(SecurityIdentifier))

            'Tracks the SIDs to remove
            Dim removeList = New List(Of IdentityReference)()
            For Each rule In rules.OfType(Of FileSystemAccessRule)()
                Try
                    Dim account = rule.IdentityReference.Translate(GetType(NTAccount))
                Catch generatedExceptionName As IdentityNotMappedException
                    'Assume invalid so remove it
                    If Not removeList.Any(Function(sid) sid.Value = rule.IdentityReference.Value) Then
                        removeList.Add(rule.IdentityReference)

                    End If
                End Try
            Next
            'Remove all rules associated with the given SID
            For Each id In removeList
                'Remove all permissions
                If FileInUse("c:\orphansid.txt") = True Then
                    Thread.Sleep(2)
                    ListBox1.Items.Add("Removed the following SID:" & id.ToString & " From " & Path & vbCrLf)
                    My.Computer.FileSystem.WriteAllText("c:\orphansid.txt", "Removed the following SID:" & id.ToString & " From " & Path & vbCrLf, True)
                Else
                    ListBox1.Items.Add("Removed the following SID:" & id.ToString & " From " & Path & vbCrLf)
                    My.Computer.FileSystem.WriteAllText("c:\orphansid.txt", "Removed the following SID:" & id.ToString & " From " & Path & vbCrLf, True)
                    Thread.Sleep(2)
                End If
                Dim DirACLs As New Security.AccessControl.DirectorySecurity(Path, AccessControlSections.All)

                DirACLs.PurgeAccessRules(id)
                'dSecurity.PurgeAccessRules(id)
                dinfo.SetAccessControl(dSecurity)
            Next

            For Each subdir As String In System.IO.Directory.GetDirectories(Path)
                HandleDir(subdir)
            Next subdir
        Catch ex As System.Exception

        End Try
    End Sub

    Public Sub ChangeVisibility(ByVal visibility As Boolean)
        WaitStatus.Show()
    End Sub
End Class 


The part that is not purging the SID is:

VB
'Remove all rules associated with the given SID
            For Each id In removeList
                'Remove all permissions
                If FileInUse("c:\orphansid.txt") = True Then
                    Thread.Sleep(2)
                    ListBox1.Items.Add("Removed the following SID:" & id.ToString & " From " & Path & vbCrLf)
                    My.Computer.FileSystem.WriteAllText("c:\orphansid.txt", "Removed the following SID:" & id.ToString & " From " & Path & vbCrLf, True)
                Else
                    ListBox1.Items.Add("Removed the following SID:" & id.ToString & " From " & Path & vbCrLf)
                    My.Computer.FileSystem.WriteAllText("c:\orphansid.txt", "Removed the following SID:" & id.ToString & " From " & Path & vbCrLf, True)
                    Thread.Sleep(2)
                End If
                Dim DirACLs As New Security.AccessControl.DirectorySecurity(Path, AccessControlSections.All)

                DirACLs.PurgeAccessRules(id)
                'dSecurity.PurgeAccessRules(id)
                dinfo.SetAccessControl(dSecurity)
            Next


I want the program to purge the orphaned SID and then list it in the listbox and have the ability to copy the list of orphaned SIDs to the clipboard.

Can someone help me find out why this isn't working the way I want it to work and/or find an alternate solution?

What I have tried:

I have tried the code listed above and it successfully enumerates the orphaned SIDs and adds them to the listbox in the format I want but it does not purge the orphaned SIDs.
Posted
Updated 16-Dec-16 2:31am

You have two different DirectorySecurity objects looking at the same path - dSecurity and DirACLs.

You purge the ACLs from the DirACLs instance. You then apply the rules from dSecurity to the directory. But, since you haven't changed the dSecurity instance, there will be no changes to apply.

Either purge the rules from the dSecurity instance, or set the ACL to the DirACLs instance.

You should probably also apply the changes outside of the loop, to avoid constantly modifying the rules for the same directory over and over again.

You can also avoid opening and closing the log file every time you write to it.
VB.NET
If removeList.Count <> 0 Then
    Dim DirACLs As New Security.AccessControl.DirectorySecurity(Path, AccessControlSections.All)
    
    Using logWriter As New StreamWriter("c:\orphansid.txt", true)
        For Each id In removeList
            logWriter.WriteLine("Removed the following SID: {0} From {1}", id, Path)
            DirACLs.PurgeAccessRules(id)
        Next
    End Using
    
    dinfo.SetAccessControl(DirACLs)
End If
 
Share this answer
 
Comments
Member 11866893 14-Dec-16 13:56pm    
I tried the code you posted with both dsecurity and diracls. I also tried with the dinfo.setaccesscontrol(desecurity) the way you posted it and also inside the loop. It is still just finding the orphaned sid and properly displaying it in the listbox as well as logging it but not removing it.

If removeList.Count <> 0 Then
'Dim DirACLs As New Security.AccessControl.DirectorySecurity(Path, AccessControlSections.All)
Using logWriter As New StreamWriter("c:\orphansid.txt", True)
For Each id In removeList
ListBox1.Items.Add("Removed the following SID: " & id.ToString & " From " & Path & vbCrLf)
logWriter.WriteLine("Removed the following SID: {0} From {1}", id, Path)
dSecurity.PurgeAccessRules(id)
dinfo.SetAccessControl(dSecurity)
Next
End Using
End If

I am a domain admin and I am running the program with elevated privileges. Any ideas what else I may be doing wrong?
Richard Deeming 14-Dec-16 14:01pm    
This StackOverflow thread[^] has almost the same code in C#, and the OP claims that it works.

Are you sure that the rules aren't being inherited from a parent folder?
Member 11866893 14-Dec-16 14:15pm    
I will run it again on one user folder and then manually check it to see if the inheritance is the issue. I don't think it is because I select the parent folder which is f:\user1 with FolderBrowserDialog and each user has a folder under user1. It is correctly finding and displaying the user folders. I have all subfolders and files inheriting under the user folder inheriting permissions from the user folder that is displayed correctly not from user1. I will let you know. I have only been programming so it is possible I might overlook something like that.
Member 11866893 14-Dec-16 14:41pm    
I looked at the advanced properties of one the user folders not being processed properly and it definitely shows the orphaned SID not inheriting.
Member 11866893 14-Dec-16 15:00pm    
You may have been onto something with inheritance. I looked up GetAccessRules this is Microsoft's explanation said:
Public Function GetAccessRules (includeExplicit As Boolean, includeInherited As Boolean, targetType As Type)


So I changed this line of the code: Dim rules = security.GetAccessRules(True, False, GetType(SecurityIdentifier))
to: Dim rules = security.GetAccessRules(True, True, GetType(SecurityIdentifier))

So far I can see that is wasn't displaying the results correctly. It was only finding the orphaned SID on each top directory. It is still running but now it is displaying all subdirectories under each top directory. So hopefully the reason it was not removing it was because inheritance was set on each user folder and the flag that was set to false was causing it to not perform the way I wanted it too. When it finishes I will let you know if that was the issue.
This tool finds orphaned SID's on the top directories of the given path, takes ownership, and purges the ACL then adds 2 admin groups to ACL. It removes inheritance before adding the admin groups. Once the admin groups are added it fixes desktop.ini (an issue we have in our environment) then resets the ownership to administrator. I had to put long breaks between changing the ACL because it wouldn't propagate inheritance to subdirectories for some reason, so I just put long breaks between to give each one time to finish work on the ACL and that seemed to do the trick. It doesn't add that much run time because there aren't that many orphaned user directories and the work is only being executed on orphaned SIDs.

VB
Try
            Dim security As DirectorySecurity = Directory.GetAccessControl(Path)
            Dim rules = security.GetAccessRules(True, False, GetType(SecurityIdentifier))
            'Add SIDs to be removed to a list
            Dim removeList = New List(Of IdentityReference)()
            For Each rule In rules.OfType(Of FileSystemAccessRule)()
                Try
                    'Attempt to resolve SID
                    Dim account = rule.IdentityReference.Translate(GetType(NTAccount))
                Catch generatedExceptionName As IdentityNotMappedException
                    'If the exception is thrown then add SID to the list
                    If Not removeList.Any(Function(sid) sid.Value = rule.IdentityReference.Value) Then
                        ChangeOwner(Path)
                        removeList.Add(rule.IdentityReference)
                        Dim dinfo1 As New DirectoryInfo(Path)
                        Dim DirACLs As New Security.AccessControl.DirectorySecurity(Path, AccessControlSections.All)
                        For Each oAccessRule As System.Security.AccessControl.FileSystemAccessRule In DirACLs.GetAccessRules(True, False, GetType(SecurityIdentifier))
                            DirACLs.PurgeAccessRules(oAccessRule.IdentityReference)
                            dinfo1.SetAccessControl(DirACLs)
                        Next
                        Threading.Thread.Sleep(1000)
                        removeinherit(Path)
                        Threading.Thread.Sleep(10000)
                        SetNetWorkerPerms(Path)
                        Threading.Thread.Sleep(10000)
                        SetAdmin1Perms(Path)
                        Threading.Thread.Sleep(10000)
                        removeINI(Path)
                        Threading.Thread.Sleep(1000)
                        resetadmin(Path)
                    End If
                End Try
            Next
            'Display and log entries on the list then remove them from the ACL
            Using logWriter As New StreamWriter("c:\orphansid.txt", True)
                For Each id In removeList
                    ListBox1.Items.Add("Removed the following SID:  " & id.ToString & " From " & Path & vbCrLf)
                    logWriter.WriteLine("Removed the following SID: {0} From {1}", id, Path)
                Next
            End Using
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900