Wednesday, March 02, 2005

Get AD objects by GUID using System.DirectoryServices

All objects in ActiveDirectory are uniquely identified by their distinguishedName or objectGuid attributes. One of these identifiers are typically used to store references to an AD object and to retrieve it. The strenght of the GUID is that it stays the same even when an object is moved and thus gets a new distinguishedName. We typically stores an AD object GUID in a SQL Server database in the standard .NET GUID format (DirectoryEntry.Guid) in uniqueidentifier columns.

Searching for an object by a standard .NET GUID using the DirectorySearcher class is not as straightforward as you may think. A GUID must be formatted as an "octet string" (ActiveDirectory native format) to be able to use it in a DirectorySearcher filter as a filter clause. I have used this function to convert a standard GUID string to an octet string:

public static string Guid2OctetString(string objectGuid)
{
System.Guid guid = new Guid(objectGuid);
byte[] byteGuid = guid.ToByteArray();
string queryGuid = "";
foreach(byte b in byteGuid)
{
queryGuid += @"\" + b.ToString("x2");
}
return queryGuid;
}

Note that if you have a DirectoryEntry object instead of just a standard GUID string, then the .NativeGuid will give you the octet string.

All AD objects have a specific class such as "user", "contact" or "group", which helps on narrowing the number of entries to search through. Always apply an objectClass filter in your AD searches. With the GUID, octet string method and the objectClass at hand, looking up the AD object is done like this:

. . .
string adPath = "LDAP://DC=myco,DC=local"
DirectoryEntry adRoot = new DirectoryEntry(adPath);
Object adsiObj = adRoot.NativeObject; //Bind to the native AdsObject to force authentication


DirectorySearcher adSearch = new DirectorySearcher(adRoot);
string queryGuid = Guid2OctetString(objectGuid);
adSearch.Filter = "(&(objectClass=" + objectClass + ")(objectGUID=" + queryGuid + "))";


SearchResult adResults = adSearch.FindOne();
adObject = adResults.GetDirectoryEntry();
. . .


Applying a GUID filter clause to the objectGUID attribute in this example is just for illustration purposes.

To lookup the AD object identified by the GUID simply use the octet string (.NativeGuid) in the DirectoryEntry constructor (see Binding Using GUID in the DirectoryService SDK):

DirectoryEntry adObject= new DirectoryEntry("LDAP://<" + "GUID=" + nativeGuid + ">")

Please let me know if the .NET Guid .ToString() has a format argument I have missed that produces the octet string format.

9 comments:

beone said...

It's exactly I was looking for.

Thanks !

Anonymous said...

This article helped me and saved my time. Thanks.

Anonymous said...

Thank you!

Harlan Crystal said...

Question:

When you are binding to a guid directly (e.g., new DirectoryEntry("LDAP://<GUID="+nativeguidstr+">"))
how does this directory entry know which AD-server & authentication to use?

Andrew said...

I have tried DirectoryEntry("LDAP://" + domainName + "/<GUID=" + nativeguidstr + ">")), but it does not work as well. So the only way to specify AD domain is to use DirectorySearcher as described. Many thanks to author!

Dannygibor said...

Well done. Works great!

Anonymous said...

Joe Kaplan has a good solution to this Problem. And a solution with the GUI to Octet String Problem.
http://www.dotnetmonster.com/Uwe/Forum.aspx/asp-net-security/1595/Binding-DirectoryEntry-to-AD-object-via-GUID

Anonymous said...

Thanks!

Anonymous said...

Works great!

Thanks