Larry Steinle

February 27, 2011

Reading Data in Active Directory

Filed under: Active Directory,VS.Net — Larry Steinle @ 9:06 pm
Tags: , ,

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.

To avoid memory leaks and network leaks:
  • 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.
With these guidelines in mind let’s review how to query user information and get the multi-valued attribute, memberOf.
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.

Advertisement

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: