Click here to Skip to main content
15,885,874 members
Articles / Programming Languages / Visual Basic

File Server Audit

Rate me:
Please Sign up or sign in to vote.
4.33/5 (4 votes)
25 Jun 2015GPL36 min read 42K   1.5K   20   5
Audit NTFS ACL permissions on Windows Volumes.

Introduction

File Server Audit solves the problem of getting raw data to find what a user can access on a large file server by enumerating all NTFS (New Technology File System) ACLs (Access Control Lists) for all folders. With text utilities or SQL queries, the raw data can be turned into useful reports to find what a user has access to. The File Server View also can be used to help look at the output. File Server Audit will help someone else by allowing them to quickly create their own auditing process for their file servers. The code snippet is a sub to read Reads Discretionary Access Control Lists (ACLs). This helps when looking for who has access to folders.

Screenshot

Image 1

 

Background

 

I wrote this as part of a file server migration and cleanup project, to tell me all who had access to files and folders. This program was really helpfully at showing all the different people that had access to folders.

Using the Code

The code works by enumerating every folder on a volume and then enumerating each user and group that has access to each folder. The program will then take the groups and enumerate all users in that group and all users in nested groups. By doing this, it will give you a full list of users that have access to a file or folder. In the code snippet is the sub to enumerate all ACLs (Access Control Lists) for a folder. This code needs to be run within a Domain account so that the proper enumeration can be done. There is another sub called RecursiveGroupSub that enumerates nested groups in the program source. Call the sub and give it a valid path to a folder. This program does output a lot of data which is hard to sort and analyze.

Global variables; uses Dictionaries as local cache to speed up AD records.

VB
Dim blnShowOutput As Boolean = True 'Used to show output
Dim blnInherited As Boolean = False 'Used to remove inherited ACLs
Dim strDate As String = TodayFileDate() 'Holds Date in string format
'Hold Cache for AD Users/Groups (AD sAMAccountName, AD Object Type)
Dim dicADUserType As New Dictionary(Of String, String)
'Holds Group sAMAccountName and Array of Users sAMAccountName
Dim dicADGroup As New Dictionary(Of String, Array)
'Holds Group sAMAccountName and Managed By name
Dim dicADGroupManager As New Dictionary(Of String, String)
'Holds Group sAMAccountName and Sub-Group sAMAccountName
Dim dicADGroupSubGroup As New Dictionary(Of String, Array)

Setup for the ReadACLs sub that reads the actual ACLs. In the setup, DirInfo binds to the input directory so that DirSec can get a list of ACLs. This list is then set in the object ACLs.

VB
Public Sub ReadACLs(ByVal strInput As String, _
           Optional ByVal blnRemoveInherited As Boolean = True)
    'strInput is the full path to a folder
    'blnRemoveInherited is used to remove inherited ACLs to reduce output

    'Bindings:

    'Binds to the Directory using the string provided 
    Dim DirInfo As System.IO.DirectoryInfo = _
      New System.IO.DirectoryInfo(strInput) 'Directory is already binded
    'Binds to Directory Security
    'This allows user to read ACLs
    Dim DirSec As System.Security.AccessControl.DirectorySecurity = _
               DirInfo.GetAccessControl()
    'Gets Directory Access Control Lists
    'Collection is returned with ACLs so we can enumerate later
    Dim ACLs As System.Security.AccessControl.AuthorizationRuleCollection = _
        DirSec.GetAccessRules(True, True, _
        GetType(System.Security.Principal.NTAccount))
    'Access Contol List Entry
    'Varible to hold a ACL
    Dim ACL As System.Security.AccessControl.FileSystemAccessRule
    'Gets Folder owner ID
    Dim Owner As System.Security.Principal.IdentityReference = _
        DirSec.GetOwner(GetType(System.Security.Principal.NTAccount))
    'Binds to the default domain
    'For this to work this will have to run under a domain account
    Dim DomainContext As New _
        System.DirectoryServices.ActiveDirectory.DirectoryContext(_
        System.DirectoryServices.ActiveDirectory.DirectoryContextType.Domain)
    'Binds to AD to get account and group info
    Dim objMember As New System.DirectoryServices.DirectoryEntry

    'Declarations:

    'Used to hold domain and user ex domain\user
    Dim arrDUSplit(1) As String
    Dim strTemp As String = "" 'Holds working String
    Dim strSAMA As String = "" 'Users Username ("sAMAccountName")
    Dim strClass As String = "" ' AD Object type Group or User
    Dim strGroupSAMA As String = "" 'The Group Users is in
    Dim strManagedBy As String = "" 'Person that manages that AD Group.
    'Holds Owners name as string. Converts folders Owners Object to String
    Dim strOwner As String = Owner.ToString
    'Holds ACL.IdentityReference.ToString Properties 
    Dim StrACLIdentityReference As String = ""
    'Holds ACL.InheritanceFlags.ToString Properties
    Dim StrInheritanceFlags As String = ""
    'Holds ACL.FileSystemRights.ToString Properties
    Dim StrFileSystemRights As String = ""
    'Holds ACL.IsInherited.ToString Properties
    Dim StrIsInherited As String = ""
    Dim StrArrayLoopSubGroup As String 'Allows Looping thru all sub-group
    Dim StrArrayLoopUser As String 'Allows Looping thru all Users

    On Error GoTo ErrorHandle

    'Main Section of sub

Now we loop though all the ACLs, since each folder can have many ACLs. We also have to deal with all local user, machine, and deleted accounts. Deleted accounts show up as just the SID (S-1-5-21-...). Once we have an ACL, we write out all the properties we want to a LogWrite that will write out the record to log, SQL, or screen.

VB.NET
'Loops through all the Access Control Lists For the Folder
    For Each ACL In ACLs
        'Setup Most Used ACL Properties
        StrACLIdentityReference = ACL.IdentityReference.ToString
        StrInheritanceFlags = ACL.InheritanceFlags.ToString
        StrFileSystemRights = ACL.FileSystemRights.ToString
        StrIsInherited = ACL.IsInherited.ToString

        If Str.Left(StrACLIdentityReference, 2) = "S-" Then
            'Used to catch Deleted Accounts.
            strSAMA = "Unknown"
            strGroupSAMA = StrACLIdentityReference
            strManagedBy = "Unknown"
            strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
            If blnRemoveInherited Then
                If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
            Else
                LogWrite(strTemp)
            End If
        Else
            'Splits Domain and User or Group a part.
            'This cleans up the output alittle.
            arrDUSplit = Split(StrACLIdentityReference, "\")
            'Formats the output differently depending on the domain.
            Select Case arrDUSplit(0)
                'Built-in security principals need special treatment   
                Case "BUILTIN"
                    strSAMA = arrDUSplit(1)
                    strGroupSAMA = "System"
                    strManagedBy = "Systems Administrators"
                    strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                        strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                    If blnRemoveInherited Then
                        If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                    Else
                        LogWrite(strTemp)
                    End If
                Case "NT AUTHORITY"
                    strSAMA = arrDUSplit(1)
                    strGroupSAMA = "System"
                    strManagedBy = "Systems Administrators"
                    strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                        strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                    If blnRemoveInherited Then
                        If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                    Else
                        LogWrite(strTemp)
                    End If
                Case "CREATOR OWNER"
                    strSAMA = arrDUSplit(0)
                    strGroupSAMA = "System"
                    strManagedBy = "Systems Administrators"
                    strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                        strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                    If blnRemoveInherited Then
                        If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                    Else
                        LogWrite(strTemp)
                    End If
                Case "Everyone"
                    strSAMA = arrDUSplit(0)
                    strGroupSAMA = "Everyone"
                    strManagedBy = "Systems Administrators"
                    strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                        strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                    If blnRemoveInherited Then
                        If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                    Else
                        LogWrite(strTemp)
                    End If

                Case Environment.MachineName.ToString
                    'Used for Local Users that have the Domain of the computer name.
                    strSAMA = arrDUSplit(1)
                    strGroupSAMA = "Local"
                    strManagedBy = "Systems Administrators"
                    strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                        strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                    If blnRemoveInherited Then
                        If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                    Else
                        LogWrite(strTemp)
                    End If

Below is how we deal with domain accounts. First we check to see if the record is in cache; if not, we query AD and add it to the cache. After we find out what type the account is, we then can call LogWrite if it is a user or computer account, otherwise we enumerate the group. Now we check if the group is in the cache; if it is, we use the cache. However, if a sub-group is not in the cache, we call RecursiveGroupSub to get all the members of that group and any sub-groups; then we add those to the cache.

VB.NET
Case Environment.UserDomainName.ToString
    'Uses Currently login domain to enumerate groups
    'Checks to see if the account type is is in the Cache
    If dicADUserType.ContainsKey(arrDUSplit(1)) Then
        strSAMA = arrDUSplit(1)
        strClass = dicADUserType(arrDUSplit(1)).ToString
    Else
        'If AD Users are not in the Cache Dictionary Check AD and Put them in the Cache
        objMember = GetUser(arrDUSplit(1))
        If objMember Is Nothing Then
            CurrentRecord_Event("Error Number: " & Err.Number & " " & Err.Description & vbCrLf _
                & " Sub GetUser: " & vbCrLf _
                & vbTab & "DirInfo.FullName: " & DirInfo.FullName & vbCrLf _
                & vbTab & "NTFS ACL: " & StrACLIdentityReference & vbCrLf _
                & vbTab & "Domain: " & arrDUSplit(0) & vbCrLf _
                & vbTab & "User: " & arrDUSplit(1) & vbCrLf)
        Else
            strClass = objMember.SchemaClassName.ToString 'Get Record AD Type User or Group
            strSAMA = objMember.Properties("sAMAccountName").Value.ToString 'Get AD UserName
            dicADUserType.Add(strSAMA, strClass) 'sets username in Dictionary,'sets class in Dictionary
        End If
    End If

    'Do different actions based on AD Class
    Select Case strClass
        'Write out Each User
        'Each of this Users has explicit permissions
        Case "user", "computer"
            strGroupSAMA = "Direct"
            strManagedBy = "Systems Administrators " & Environment.UserDomainName.ToString & " Domain Accounts"
            strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
            If blnRemoveInherited Then
                If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
            Else
                LogWrite(strTemp)
            End If

        Case "group"
            'For Groups do a recursive search for all sub groups and users
            'Check to see of Group is in Dictionary.
            If dicADGroup.ContainsKey(arrDUSplit(1)) Then
                'Set Manager Of Group
                strManagedBy = ""
                If dicADGroupManager.ContainsKey(arrDUSplit(1)) Then strManagedBy = dicADGroupManager(arrDUSplit(1))
                'Loop thru all users in that group.
                For Each StrArrayLoopUser In dicADGroup(arrDUSplit(1)) 'Loops thru all user in a group
                    'AD Group was Found in Cache.
                    strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                        strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                    If blnRemoveInherited Then
                        If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                    Else
                        LogWrite(strTemp)
                    End If
                Next
                'Loop thru all sub Groups
                If dicADGroupSubGroup.ContainsKey(arrDUSplit(1)) Then
                    For Each StrArrayLoopSubGroup In dicADGroupSubGroup(arrDUSplit(1)) 'Loops thru all sub-group
                        strManagedBy = ""
                        If dicADGroupManager.ContainsKey(StrArrayLoopSubGroup) Then strManagedBy = dicADGroupManager(arrDUSplit(1))
                        'Test SubGroup to see if the are in cache
                        If Not dicADGroup.ContainsKey(StrArrayLoopSubGroup) Then
                            If Not RecursiveGroupSub(objMember) = StrArrayLoopSubGroup Then GoTo ErrorHandle
                        End If
                        For Each StrArrayLoopUser In dicADGroup(StrArrayLoopSubGroup) 'Loops thru all user in a group
                            'AD Group was Found in Cache.
                            strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                                strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                            If blnRemoveInherited Then
                                If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                            Else
                                LogWrite(strTemp)
                            End If
                        Next
                    Next
                Else

                End If

If the group is not in the cache, we add it by calling RecursiveGroupSub. This will also put all sub-groups and AD users in the cache. The RecursiveGroupSub sub has logic to break circular dependencies. This can happen if you have two groups that have each other as members. Lastly, just write out any unresolved records; this could be an account or group from a trusted domain.

VB.NET
Else
                    'Group is not is Cache so start RecursiveGroupSub to put it in Cache
                    'RecursiveGroupSub should return the group it is worked on
                    If RecursiveGroupSub(objMember) = arrDUSplit(1) Then
                        If Not dicADGroup.ContainsKey(arrDUSplit(1)) Then GoTo ErrorHandle
                    Else
                        If Not dicADGroup.ContainsKey(RecursiveGroupSub(objMember)) Then GoTo ErrorHandle
                    End If
                    'Set the Manager of the group
                    If dicADGroupManager.ContainsKey(arrDUSplit(1)) Then strManagedBy = dicADGroupManager(objMember.Properties("sAMAccountName").Value.ToString)
                    'Loop thru all user on the Group
                    For Each StrArrayLoopUser In dicADGroup(arrDUSplit(1)) 'Loops thru all user in a group
                        'AD Group was Found in Cache.
                        strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                            strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                        If blnRemoveInherited Then
                            If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                        Else
                            LogWrite(strTemp)
                        End If
                    Next
                    'Loop thru all sub Groups
                    If dicADGroupSubGroup.ContainsKey(arrDUSplit(1)) Then
                        For Each StrArrayLoopSubGroup In dicADGroupSubGroup(arrDUSplit(1)) 'Loops thru all sub-group
                            strManagedBy = ""
                            If dicADGroupManager.ContainsKey(StrArrayLoopSubGroup) Then strManagedBy = dicADGroupManager(StrArrayLoopSubGroup)
                            For Each StrArrayLoopUser In dicADGroup(StrArrayLoopSubGroup) 'Loops thru all user in a group
                                'AD Group was Found in Cache.
                                strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                                                    strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
                                If blnRemoveInherited Then
                                    If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
                                Else
                                    LogWrite(strTemp)
                                End If
                            Next
                        Next
                    Else

                    End If
                End If
            Case "contact"

            Case Else
                MsgBox("Unexpected strClass: " & strClass)
        End Select
    Case Else
        'Catch all just Write out Entries without group enumeration
        'If you have multiple domains in your forest the domain you are not logon on too will show up here.
        strSAMA = arrDUSplit(1)
        strGroupSAMA = arrDUSplit(0)
        strManagedBy = arrDUSplit(1) & " Administrators"
        strTemp = String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8};{9}", Str.Replace(DirInfo.FullName, ";", ","), strSAMA, strGroupSAMA, _
                            strManagedBy, StrInheritanceFlags, StrFileSystemRights, strOwner, strDate, Environment.MachineName.ToString, StrIsInherited)
        If blnRemoveInherited Then
            If ACL.IsInherited = False Or Str.Len(strInput) >= 3 Then LogWrite(strTemp)
        Else
            LogWrite(strTemp)
        End If
End Select

Ending of the sub with the error handler.

VB
        End If
    Next
    Exit Sub
ErrorHandle:
    Select Case Err.Number
        Case 0
            strTemp = "Error Number:" & Err.Number & " " & Err.Description & vbCrLf _
                & " Sub ReadACLs: " & vbCrLf _
                & vbTab & "DirInfo.FullName: " & strInput & vbCrLf _
                & vbTab & "NTFS ACL:" & StrACLIdentityReference & vbCrLf _
                & vbTab & "User:" & strSAMA & vbCrLf _
                & vbTab & "arrDUSplit(0): " & arrDUSplit(0) & vbCrLf _
                & vbTab & "arrDUSplit(1): " & arrDUSplit(1) & vbCrLf
            CurrentRecord_Event(strTemp)
            Threading.Thread.Sleep(0)
            Err.Clear()
        Case 5 'The given key was not present in the dictionary.
            'Log error in the GUI
            strTemp = "Error Number:" & Err.Number & " " & Err.Description & vbCrLf _
                & " Sub ReadACLs: " & vbCrLf _
                & vbTab & "DirInfo.FullName: " & strInput & vbCrLf _
                & vbTab & "NTFS ACL:" & StrACLIdentityReference & vbCrLf _
                & vbTab & "User:" & strSAMA & vbCrLf _
                & vbTab & "arrDUSplit(0): " & arrDUSplit(0) & vbCrLf _
                & vbTab & "arrDUSplit(1): " & arrDUSplit(1) & vbCrLf
            CurrentRecord_Event(strTemp)
            Threading.Thread.Sleep(0)
            Err.Clear()
            Resume Next
        Case 91 'Object reference not set to an instance of an object
            'Log error in the GUI
            strTemp = "Error Number:" & Err.Number & " " & Err.Description & vbCrLf _
                & " Sub ReadACLs: " & vbCrLf _
                & vbTab & "DirInfo.FullName: " & strInput & vbCrLf _
                & vbTab & "NTFS ACL:" & StrACLIdentityReference & vbCrLf _
                & vbTab & "User:" & strSAMA & vbCrLf _
                & vbTab & "arrDUSplit(0): " & arrDUSplit(0) & vbCrLf _
                & vbTab & "arrDUSplit(1): " & arrDUSplit(1) & vbCrLf
            CurrentRecord_Event(strTemp)
            Threading.Thread.Sleep(0)
            Err.Clear()
            Resume Next
        Case Else
            'Log error in the GUI
            strTemp = "Error Number:" & Err.Number & " " & Err.Description & vbCrLf _
                & " Sub ReadACLs: " & vbCrLf _
                & vbTab & "DirInfo.FullName: " & strInput & vbCrLf _
                & vbTab & "NTFS ACL:" & StrACLIdentityReference & vbCrLf _
                & vbTab & "User:" & strSAMA & vbCrLf _
                & vbTab & "arrDUSplit(0): " & arrDUSplit(0) & vbCrLf _
                & vbTab & "arrDUSplit(1): " & arrDUSplit(1) & vbCrLf
            CurrentRecord_Event(strTemp)
            Threading.Thread.Sleep(0)
            'Message Box about the error click ok to quit or X to continue
            If MsgBox("Error Number:" & Err.Number & " " & Err.Description & vbCrLf _
                & " Sub ReadACLs: " & vbCrLf _
                & vbTab & "Input Directory: " & strInput & vbCrLf _
                & vbTab & "NTFS ACL:" & StrACLIdentityReference & vbCrLf _
                & vbTab & "User:" & strSAMA & vbCrLf _
                & vbTab & "arrDUSplit(0): " & arrDUSplit(0) & vbCrLf _
                & vbTab & "arrDUSplit(1): " & arrDUSplit(1) & vbCrLf _
                , MsgBoxStyle.Critical, "Critical Error File Server Audit 2 Quitting") Then
                Err.Clear()
                Main.Close()
            Else
                Err.Clear()
                Exit Sub
            End If
    End Select
End Sub

Points of Interest

There are always bugs in code and input and you can never code around them all; but you can get it to work for what you want to do. Thanks for everyone that helped me learn.

History

  • Version 2.2.1 (2015-06-24)
    • Added Computer name field for database. This allows for better reporting
    • Updated MySQL drivers
    • Added SQL Caching so 500 records are batched and ented at one time reducing load on SQL server and local machine.
    • Other bug fixes
    • Updated to use .Net 4.5 (Needed for MySQL drivers)

MSSQL Table Name: FileAudit

Column Name Data Type
ID int
FolderPath nvarchar(MAX)
AccountSAMAccountName nvarchar(MAX)
GroupSAMAccountName nvarchar(MAX)
ManagedBy nvarchar(MAX)
Inheritance nvarchar(MAX)
IsInherited nvarchar(MAX)
Rights nvarchar(MAX)
Owner nvarchar(MAX)
Computer nvarchar(MAX)
RunDate bigint

MySQL Table Name: FileAudit

Column Name Data Type
ID int
FolderPath LONGTEXT
AccountSAMAccountName LONGTEXT
GroupSAMAccountName LONGTEXT
ManagedBy LONGTEXT
Inheritance LONGTEXT
IsInherited LONGTEXT
Rights LONGTEXT
Owner LONGTEXT
Computer LONGTEXT
RunDate bigint
  • Version 2.2.0 (2011-10-28)
    • Removed hardcoded database names.
    • Added support for MySQL.
    • Removed all log file output.
    • Cleaned up interface.
  • Version 2.1.1 (2011-05-02)
    • Fixed error: Circular group dependency message.
    • Changed grouping so less accounts are marked as Direct and system accounts are marked as System.
  • Version 2.1.0
    dicADUserType 'Hold cache for AD Users/Groups (AD sAMAccountName, AD Object Type)
    dicADGroup 'Holds group sAMAccountName and array of users sAMAccountName
    dicADGroupManager 'Holds group sAMAccountName and managed by name
    dicADGroupSubGroup 'Holds group sAMAccountName and sub-group sAMAccountName
    • Added checks for circular dependency. This avoids infinite loops; also logs as an error.
    • Lumped Computer with User class. This means that computers ACLs are treated as User ACLs.
    • Added Exception for Contact class.
    • Switched out arrays for Dictionarys. This makes caching easier to understand and less looping.
  • Version 2.0.9
    • Fixed issue with deleted accounts.
    • Fixed issue with AD caching.
    • Fixed issue with Start button.
    • Added a Delete all SQL records.
  • Version 2.0.8
    • Updated SQL Server.
  • Version 2.0.7
    • Fixed issue where program would skip over folder if there was only one sub-folder.
    • Changed it so that all errors would be printed in the Output tab.
    • Fixed issue where inserting in to SQL Server could cause array out of bounds.
    • Fixed issue about reporting errors to GUI.
    • Changed update directory to \\ucpg-files.uchicago.edu\Installs\CustomTools\File Server Audit.
    • Added a feature to remove old SQL records from the current day.
    • Trying to fix Cancel button.
  • Version 2.0.6
    • Added Total Execution Time to notify on end.
  • Version 2.0.5
    • Added field IsInherited to text output.
    • Added table field: IsInherited varchar(50).
  • Version 2.0.4

    Table name: FileAudit

    Column Name Data Type
    ID int
    FolderPath nvarchar(MAX)
    AccountSAMAccountName nvarchar(MAX)
    GroupSAMAccountName nvarchar(MAX)
    ManagedBy nvarchar(MAX)
    Inheritance nvarchar(MAX)
    Rights nvarchar(MAX)
    Owner nvarchar(MAX)
    RunDate bigint
    • Fixed an array issue where zero sub-directories created an error.
    • Unknown Domains get no group enumeration.
    • Added Managed By for group membership.
    • Added inserting data directly into SQL database.
  • Version 2.0.3
    • Added Remove Inherited feature that only shows permissions that are not inherited.
  • Version 2.0.2
    • Commented most of the code.
    • Updated separate file log classes.
  • Version 2.0.1
    • Added a cache for AD groups to speed up enumeration.
    • Added a cache for AD users to speed up enumeration.
    • Fixed logic problem with RecursiveSearch sub.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Systems / Hardware Administrator
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionError during opening and compinling Pin
Rommelke20-Jun-11 7:59
Rommelke20-Jun-11 7:59 
hi,

there are issues during opening and compiling.

at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.EnsureDocument(IDesignerSerializationManager manager)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at System.ComponentModel.Design.Serialization.BasicDesignerLoader.BeginLoad(IDesignerLoaderHost host)

Error 5 Unable to get MD5 checksum for the key file "Paul Fuller.pfx". Could not find file 'C:\File Server Audit 2\Paul Fuller.pfx'. File Server Audit 2

AnswerRe: Error during opening and compinling Pin
Gentoouser27-Jul-11 10:32
Gentoouser27-Jul-11 10:32 
GeneralCompile Error - Paul F....PFX Pin
mntc4-Jun-11 16:48
mntc4-Jun-11 16:48 
GeneralGood stuff. Pin
Warrick Procter4-Jun-11 13:56
Warrick Procter4-Jun-11 13:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.