VB.NET – List active directory users – Re-write

Please note: This is a rewrite of an article I wrote way back in 2007. The original article has been updated with a link to this one.

As per usual I had a situation where I had to do some Active Directory stuff with VB.NET. I had to grab a list of all the users in our AD so that people could select a user and perform functions on them from within a webpage.
Another note: This article is VB.NET-specific. If you’d like to know how to do this using C# please see this post’s “partner” entitled “Follow Up – List active directory users – This time in C#”

Carrying on though, there are a number of ways you can do this but in the .NET Framework they all involve using the System.DirectoryServices namespace. A couple of quick things to be aware of before you try this yourself:

  • Before messing with your Active Directory make sure you know what you’re doing and have the permissions of your AD Administrators (if it’s not you!)
  • If you are going to use any of the following code from a .NET console application you’ll need to add a reference to System.DirectoryServices in addition to importing the namespace. I wrote a post a while ago about this entitled “Developer Dumbness” – it has the steps you need to add a reference to a .NET console application.

Anyway, the code below is a simple function that queries your Active Directory domain and retrieves all the user objects. This particular example filters out any user account whose “DisplayName” attribute meets the following criteria (the requirements for the app I had to write):

  • Has an email address
  • Does not contain the “$” symbol
  • Does not contain the words “Admin” or “admin”
  • Does not contain the words “Test” or “test”
  • Does not contain the words “Service” or “service”
  • Does not contain the word “System” or “system”

The example code below is a complete Windows console application that does all of the above. It’s important to note that if you’re using this in a production environment you’ll need to make sure the application containing the code has access to the Active Directory, usually using .NET impersonation – this is beyond the scope of this post.

List Active Directory Users in VB.NET:

Imports System
Imports System.Collections.Generic
Imports System.DirectoryServices

Module ListAdUsers

    Sub Main(ByVal ParamArray Args() As String)

        Console.Clear()
        Dim userList As List(Of String) = New List(Of String)

        Dim badEntries As Integer = 0
        Dim domainName As String = String.Empty

        If (Args.Length > 0) Then
            domainName = Args(0)
        Else
            Console.Write(String.Format("{0}Please enter your Active Directory domain name: ", vbCrLf))
            domainName = Console.ReadLine()
        End If

        Console.Write(String.Format("{0}Attempting to build user list for {1} ...{0}{0}", vbCrLf, domainName))

        Try
            If Not String.IsNullOrEmpty(domainName) Then
                Dim myDirectoryEntry As DirectoryEntry = New DirectoryEntry(String.Format("LDAP://{0}", domainName))
                Dim mySearcher As DirectorySearcher = New DirectorySearcher(myDirectoryEntry)
                Dim mySort As SortOption = New SortOption("sn", SortDirection.Ascending)
                mySearcher.Filter = ("(objectClass=user)")
                mySearcher.Sort = mySort
                For Each resEnt As SearchResult In mySearcher.FindAll()
                    Try
                        If Not String.IsNullOrEmpty(resEnt.Properties("Mail")(0).ToString()) _
                            AndAlso System.Text.RegularExpressions.Regex.IsMatch(resEnt.Properties("DisplayName")(0).ToString(), " |admin|test|service|system|[$]", System.Text.RegularExpressions.RegexOptions.IgnoreCase) Then
                            Dim space As Integer = resEnt.Properties("DisplayName")(0).ToString().IndexOf(" ")
                            Dim formattedName As String = String.Format("{0}{1}{2}", _
                                                                        resEnt.Properties("DisplayName")(0).ToString().Substring(space).PadRight(25), _
                                                                        resEnt.Properties("DisplayName")(0).ToString().Substring(0, space).PadRight(15), _
                                                                        resEnt.Properties("Mail")(0).ToString() _
                                                                        )
                            userList.Add(formattedName)
                        End If
                    Catch
                        badEntries = badEntries + 1
                    End Try
                Next
                If (userList.Count > 0) Then
                    Console.WriteLine(String.Format("=========== Listing of users in the {0} domain{1}", domainName, vbCrLf))
                    Console.WriteLine(String.Format("{0}{1}{2}{3}", "Surname".PadRight(25), "First Name".PadRight(15), "Email Address", vbCrLf))
                    For i = 0 To userList.Count - 1
                        Console.WriteLine(userList(i).ToString())
                    Next
                    Console.WriteLine(String.Format("{0}=========== {1} users found in the {2} domain", vbCrLf, userList.Count.ToString(), domainName))
                Else
                    Console.WriteLine(String.Format("{0}=========== 0 users found in the {1} domain", vbCrLf, userList.Count.ToString()))
                End If
                Console.WriteLine(String.Format("=========== {0} objects could not be read", badEntries.ToString()))
                Console.WriteLine("=========== End of Listing")
            Else
                Console.WriteLine("Please enter a domain name next time!")
            End If
        Catch ex As Exception
            ' in a production app you wouldn't show the user the exception details
            Console.Write(String.Format("A critical error occurred.{0}Details: {1}", vbCrLf, ex.Message.ToString()))
        End Try
    End Sub

End Module

There are a HEAP of attributes you can use instead of “sn” in the sample above. Personally I use ADSIEDIT.MSC to look at all the possible attributes but you’ll need domain administrative access to run that. Here are a couple of useful ones though …

  • company
  • department
  • description
  • displayName
  • mail
  • manager
  • name
  • givenName
  • sAMAccountName

Hope that helps someone! 🙂