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.
There is an example that can be downloaded at the bottom of this post.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 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 atttibutes 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 …
For simplicity’s sake I have written a small sample console application that uses the functions above and just writes the user list and a user count to the screen. Use the link below to download the sample solution.
VB.NET – List Active Directory Users
Hope that helps someone!
Brilliant!
Thanks very much
Very nice, and very helpful! thanks!!
Thank you for sharing this, however, only 1000 records are retrieved, can you find out why and let me know? Thanks.
Raymond: Off the top off my head I’m not sure as I haven’t used this code for a very long time. However, I do know that in the System.Collections.Generic namespace the List class has a default capacity that *may* be causing this (unlikely). The List class documentation (http://msdn.microsoft.com/en-us/library/y52x03h2.aspx) says that a List’s capacity is automatically increased if the Count property exceeds the current Capacity property so I would hope the list’s capacity isn’t the problem. Just to make absolutely sure, you could explicity set the list’s Capacity property to a number greater than 1000 and see if you get > 1000 objects in the list. Sorry if this doesn’t work but it’s an interesting question – let me know how you get on.
Raymond: Not sure if you read the comment above but if so, please ignore it – I was wrong. I’ve done research, including setting up a domain controller on my development network here at home and have added 1010 users (using ‘dsadd’, in case you’re wondering how). When I ran my app it did indeed stop at 1000 results. Some searching revealed that this is the default size limit of a DirectorySearcher search and that it’s actually an AD setting by default, not a .NET setting. Luckily there’s a way around this – use the PageSize property of the DirectorySearcher instance. In the code for this article you’d use this:
mySearcher.PageSize = 1000
Add that after the instance is instantiated and you’re good to go – I put it under the line that says mySearcher.Sort = mySort and it worked.
Hope that helps.
[...] I received a comment on an old article of mine called “VB.NET – List Active Directory users – Re-write“. It was from a user who had tried the code and, while it worked fine, it stopped listing [...]
Hi,
Very useful post. But is there any access rights required to get a list of users on a domain? Do you have to be the domain administrator or something?
I am normal user on a domain, and when I run this code I am unable to get the desired information
Thanks.
Hi
Can any one suggest me how to get the group names for a domain using active directory in VB.Net
Thanks