LDAP queries

A recent project of mine required querying Active Directory for all the groups in which a given user is a member, or if there isn’t a domain then searching the local machine. It also had to return all groups defined in a given domain. In the course of putting the code together, I created a library for future projects that needed to perform such queries. I recently made a major improvement to the code that retrieves a user’s AD groups and thought it would be good to share what I have so far.

It’s based on some bits of code I found on the web. Initially GetADGroupMembership would only return the first-level Active Directory groups the user was in, but that’s no good if the user is in a group that is in another group that is in yet another group that’s the one you really care about. So I added some recursion to bring up the entire group chain. It seems to perform well enough with our domain, which admittedly doesn’t have a great deal of nesting.

Imports System.DirectoryServices

Public Class LDAP
    Public Shared Function GetADGroupMembership(ByVal sPath As String, ByVal sUserID As String) As List(Of String)
        Dim lstResults As List(Of String)
        Dim lstGroups As List(Of String)
        Dim lstSubGroups As List(Of String)
        Dim sFilter As String

        GetADGroupMembership = Nothing

        sFilter = "(&(objectClass=user)(samAccountName=" & sUserID & "))"
        lstResults = RunSearch(sPath, sFilter, "MemberOf")
        lstGroups = New List(Of String)

        If lstResults IsNot Nothing Then
            For Each result As String In lstResults
                lstGroups.Add(result)
                lstSubGroups = GetADGroupMembershipByGroup(sPath, result)

                For Each sSubGroup As String In lstSubGroups
                    If Not lstGroups.Contains(sSubGroup) Then
                        lstGroups.Add(sSubGroup)
                    End If
                Next sSubGroup
            Next result
        End If

        Return lstGroups
    End Function

    Public Shared Function GetLocalGroupMembership(ByVal sPath As String, ByVal sUserName As String, ByVal sPassword As String) As List(Of String)
        Dim de As DirectoryEntry = Nothing
        Dim colGroups As Object
        Dim lstGroups As List(Of String)

        GetLocalGroupMembership = Nothing

        Try
            de = New DirectoryEntry(sPath, sUserName, sPassword, AuthenticationTypes.Secure)
            colGroups = de.Invoke("Groups")
            lstGroups = New List(Of String)

            For Each o As Object In colGroups
                lstGroups.Add(o.Name)
            Next o

            Return lstGroups
        Catch
            Throw
        Finally
            If de IsNot Nothing Then
                de.Dispose()
            End If
        End Try
    End Function

    Public Shared Function GetADGroups(ByVal sPath As String) As List(Of String)
        Dim lstGroups As List(Of String)
        Dim sFilter As String

        GetADGroups = Nothing

        sFilter = "(&(objectClass=group))"
        lstGroups = RunSearch(sPath, sFilter)
        lstGroups.Sort()

        Return lstGroups
    End Function

    Private Shared Function GetADGroupMembershipByGroup(ByVal sPath As String, ByVal sGroupName As String) As List(Of String)
        Dim lstResults As List(Of String)
        Dim lstGroups As List(Of String)
        Dim lstSubGroups As List(Of String)
        Dim sFilter As String

        GetADGroupMembershipByGroup = Nothing

        sFilter = "(&(objectCategory=group)(cn=" & sGroupName & "))"
        lstResults = RunSearch(sPath, sFilter, "MemberOf")
        lstGroups = New List(Of String)

        If lstResults IsNot Nothing Then
            For Each result As String In lstResults
                lstGroups.Add(result)

                'Retrieve all groups that the current group is a member of
                lstSubGroups = GetADGroupMembershipByGroup(sPath, result)
                For Each sSubGroup As String In lstSubGroups
                    If Not lstGroups.Contains(sSubGroup) Then
                        lstGroups.Add(sSubGroup)
                    End If
                Next sSubGroup
            Next result
        End If

        Return lstGroups
    End Function

    Private Shared Function RunSearch(ByVal sPath As String, ByVal sFilter As String, Optional ByVal sProperty As String = "") As List(Of String)
        Dim lstResults As List(Of String)
        Dim de As System.DirectoryServices.DirectoryEntry = Nothing
        Dim deSearcher As System.DirectoryServices.DirectorySearcher = Nothing
        Dim results As System.DirectoryServices.SearchResultCollection
        Dim res As System.DirectoryServices.SearchResult

        RunSearch = Nothing

        Try
            de = New System.DirectoryServices.DirectoryEntry(sPath)
            deSearcher = New System.DirectoryServices.DirectorySearcher(de)
            deSearcher.Filter = sFilter
            deSearcher.SearchScope = SearchScope.Subtree
            results = deSearcher.FindAll

            lstResults = New List(Of String)

            For Each res In results
                If sProperty = "" Then
                    'If no specific property is being sought, simply return the common name
                    lstResults.Add(TrimToName(res.GetDirectoryEntry.Name))
                Else
                    For Each o As Object In res.Properties(sProperty)
                        lstResults.Add(TrimToName(o))
                    Next o
                End If
            Next res

            Return lstResults
        Catch
            Throw
        Finally
            If deSearcher IsNot Nothing Then
                deSearcher.Dispose()
            End If

            If de IsNot Nothing Then
                de.Dispose()
            End If
        End Try
    End Function

    Private Shared Function TrimToName(ByVal path As String) As String
        Dim parts() As String

        parts = path.Split(",")
        Return parts(0).Replace("CN=", String.Empty)
    End Function
End Class
This entry was posted in Coding and tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>