There are three ways to get data from Active Directory programmatically. There is the Active Directory COM APIs, ADsDSoObject OLEDB driver, or .Net Directory Services. Both the OLEDB driver and the .Net Directory Services are wrappers around the COM APIs. In today’s post I will demonstrate how to read data using the OLEDB driver and the .Net Directory Services object model.
OLEDB Driver
The ADsDSoObject OLEDB driver is by far the easiest way to get data from Active Directory. However, it comes with a few limitations. The ADsDSoObject OLEDB driver is limited by paging. During a search the driver will return up to 1,000 objects (unless your system administrator has changed the default paging limit on the domain controllers). Additionally, the OLEDB driver can only access single-valued properties. That means you will not be able to query a group’s member or memberOf attributes.
For our example we will find all the user’s in the root organizational unit.
Imports System.Data Imports System.Diagnostics Private Sub QueryADWithOLEDB() Dim connectionString As String = "Provider=adsdsoobject;Encrypt Password=true;user id=domainName\LoginID;password=********;" Dim commandString As String = "SELECT name, displayName, sAMAccountName, userPrincipalName FROM 'LDAP://dc=larrysteinle,dc=local' WHERE objectCategory='user'" Dim oleCon As OleDb.OleDbConnection = Nothing Dim oleCmd As OleDb.OleDbCommand = Nothing Dim oleDA As OleDb.OleDbDataAdapter = Nothing Try oleCon = New OleDb.OleDbConnection(connectionString) oleCmd = New OleDb.OleDbCommand(commandString, oleCon) oleDA = New OleDb.OleDbDataAdapter(oleCmd) Dim adDataSet As New DataSet oleDA.Fill(adDataSet) If adDataSet.Tables.Count > 0 Then For Each adRow As DataRow In adDataSet.Tables(0).Rows For Each colItem As DataColumn In adRow.Table.Columns If adRow.IsNull(colItem.ColumnName) Then Debug.WriteLine(colItem.ColumnName & " = NULL") Else Debug.WriteLine(colItem.ColumnName & " = " & adRow.Item(colItem.ColumnName)) End If Next Next End If Catch ex As Exception Debug.WriteLine(ex.Message) Finally If oleDA IsNot Nothing Then oleDA.Dispose() If oleCmd IsNot Nothing Then oleCmd.Dispose() If oleCon IsNot Nothing Then oleCon.Dispose() End Try End Sub
Directory Services
For the times when you need access to multi-valued attributes or more objects than the paging limit permits use DirectoryEntry and DirectorySearcher from the DirectoryServices namespace. This requires a little more knowledge about Active Directory communication behavior to implement correctly.
- Create a DirectoryEntry object to the desired domain, refresh the cache and then leave the object open during the duration of the program but do not use the object for searches. This object establishes the shared connection. Once you use the object and dispose of it the shared connection will be gone. If you use the object and close it repeatedly you will create network leaks until all the ports on the server are in use and an error is thrown.
- Remember to call the dispose method when you have finished using a DirectoryEntry or DirectorySearcher object. As stated earlier these objects are wrappers around the COM API utilizing unmanaged code and must be disposed correctly or you will experience difficult to trace memory leaks.
- Remember to set the SearchScope attribute on the DirectorySearch object. Setting the SearchScope enables the system to return more than one page of data until all the rows have been returned.
Imports System.Diagnostics Imports System.DirectoryServices Private Sub QueryADWithDirectoryServices() Dim rootPath As String = "LDAP://larrysteinle.local/dc=larrysteinle,dc=local" Dim poolDE As DirectoryEntry = Nothing Try poolDE = New DirectoryEntry(rootPath) poolDE.RefreshCache() Dim rootDE As DirectoryEntry = Nothing Dim searchDE As DirectorySearcher = Nothing Try rootDE = New DirectoryEntry(poolDE.Path) searchDE = New DirectorySearcher(rootDE, "(objectCategory=user)", {"name", "displayName", "sAMAccountName, userPrincipalName", "memberOf"}) searchDE.SearchScope = SearchScope.Subtree searchDE.PageSize = 1000 Dim results As SearchResultCollection results = searchDE.FindAll() For Each result As SearchResult In results For Each colName As String In result.Properties.PropertyNames For Each itemValue As Object In result.Properties.Item(colName) Debug.WriteLine(colName & " = " & itemValue.ToString) Next Next Next Catch ex As Exception Throw ex Finally If rootDE IsNot Nothing Then rootDE.Dispose() If searchDE IsNot Nothing Then searchDE.Dispose() End Try Catch ex As Exception Debug.WriteLine(ex.Message) Finally If poolDE IsNot Nothing Then poolDE.Dispose() End Try End Sub
Summary
Today we learned how to query Active Directory using both the ADsDSoObject OLEDB data provider and the Directory Services .Net object model.
Leave a Reply