Fun with ADSI: Shortcuts for Binding to Active Directory Objects

Despite the ActiveDirectory PowerShell module existing since Windows Server 2008 R2, I still write a lot of scripts using the .NET classes System.DirectoryServices.DirectoryEntry and System.DirectoryServices.DirectorySearcher—otherwise known as [adsi] and [adsisearcher] in the PowerShell world.

I freely admit that part of the reason is inertia. Since I’ve been using these classes for so long, I don’t really need to think about how to accomplish most common tasks, whereas when I use the ActiveDirectory module I need to look up a lot of things.

There are some valid reasons for using these classes to build scripts rather than using the ActiveDirectory PowerShell module. A primary reason is that you remove the dependency on the ActiveDirectory module installation, which can be useful if you don’t have the ability to install the module—or the ability to require it.

An additional benefit is that converting a script that’s fundamentally a wrapper on .NET classes to a .NET language (e.g., C#) is a lot easier than converting a script that leverages PowerShell modules that don’t have direct analogs in .NET. As much as I love coding in PowerShell, you can hit performance limitations with it that can be solved by going to .NET directly. 

As a longtime user of the Active Directory Service Interfaces (ADSI) approach to Active Directory (AD) scripting, there are a couple of useful tricks I’ve learned over the years that have given me some shortcuts when writing scripts: 

  • The WinNT provider 
  • SID and GUID binding

The WinNT Provider

When ADSI was introduced, AD wasn’t widely deployed yet. Therefore, Microsoft built ADSI to be extensible and to integrate with several different systems, including NetWare and Windows NT.

When you specify an object in ADSI, such as:

LDAP://cn=Administrator,cn=Users,dc=foobarqux,dc=com
Code language: JavaScript (javascript)

the string before the colon (in this case, LDAP) indicates to ADSI the type of system you are talking to. In the past, providers existed for NetWare 4.0 (NDS) and 3.X (NWCOMPAT), but they are no longer supported. 

The Windows NT provider (WinNT) is still supported, however, and can be handy in certain situations. 

Consider the scenario in which you need to obtain some information from a user object in AD when you only know the user’s samaccountname value. The standard pattern using ADSI would be to create an [adsisearcher] object to find the user, and either retrieve the required property as part of the search or call the GetDirectoryEntry method on the search result to access the object. 

The Windows NT provider can provide a useful shortcut here by allowing you to retrieve the user object and many of its properties without having to execute the search; for example: 

[adsi] "WinNT://FBQ/Administrator,user" | fl *
Code language: JavaScript (javascript)

would retrieve the administrator account from the FBQ domain and list all the properties. 

A couple of notes here: 

  1. The ADSI provider name is case sensitive, so you can’t use “WINNT” or some other variant—just as you can’t use “Ldap” when querying AD. 
  1. The “,user” text at the end is optional but useful if you need to avoid colliding with group or computer objects (which can also be retrieved through the WinNT provider). 

This approach works great if you’re exploring AD on the command line from a workstation that doesn’t have any of the AD tools installed (let alone the ActiveDirectory PowerShell module). 

Note that the WinNT provider only returns attributes that exist in a Windows NT domain. There are a lot of attributes in AD that are inaccessible through the WinNT provider; for this reason, I recommend just searching for the user/group/computer object using [adsisearcher]. But for interactive use on the command line or “quick and dirty” solutions, WinNT is a useful shortcut. 

SID and GUID Binding

Anyone who has done scripting with ADSI is used to the distinguishedName syntax for specifying an ADSI path to an object; for example: 

LDAP://cn=Administrator,cn=Users,dc=foobarqux,dc=com
Code language: JavaScript (javascript)

ADSI also supports binding to an object using other attributes, including: 

  • The AD objectGUID 
  • Special well-known GUIDs 
  • The objectSID 

These attributes can be used to circumvent directory operations when the appropriate attribute is already known (e.g., stored in a database or a log) and have the advantage of being invariant over object renames. For example, if you have a list of objects that you need to perform some process on, you can store that list using an objectGUID or objectSID since the object DN could have changed due to a rename or move operation. 

GUID and WKGUID Binding

Every object in AD is assigned a unique GUID. This GUID can then be used to bind to the object in ADSI using the default string representation of the GUID; for example:  

[adsi] "LDAP://<GUID=6fec67e3-82e2-4490-b075-00d03f22a19b>"
Code language: JSON / JSON with Comments (json)

The GUID can either be specified in a dashed format, as above, or as a hexadecimal representation of the GUID value; for example: 

[adsi] “LDAP://<GUID=E367EC6FE2829044B07500D03F22A19B>
Code language: HTML, XML (xml)

The hex format is the raw byte data of the GUID rendered into hexadecimal. The ordering of the byte data and the normal GUID string formats are different, so the hex format isn’t simply the dashed format with the dashes removed. 

You can convert to the hex format using the following PowerShell code: 

$guid = [Guid] "6fec67e3-82e2-4490-b075-00d03f22a19b" $guid.ToByteArray() | % {$_.ToString("X")} | join-string E367EC6FE2829044B0750D03F22A19B
Code language: PHP (php)

In general, you would use the dashed format unless you were specifically getting the hex format from some other source. 

Certain objects in AD are also tracked using a “well-known” GUID; this is a separate value to the AD objectGUID attribute and provides a consistent way to access certain system objects. The format is slightly different than the GUID binding string in that the naming context needs to be specified to disambiguate against objects that may exist in multiple naming contexts with the same well-known GUID. For example, to access the Computers container in the domain foobarqux.com, you would use the following format: 

LDAP://<WKGUID=AA312825768811D1ADED00C04FD8D5CD,dc=corp,dc=foobarqux,dc=com>
Code language: HTML, XML (xml)

This technique has some advantages, since it’s possible to redirect the default location for users and computers in AD (e.g., to an OU that you can apply GPOs to). When such a redirect is done, the WKGUID binding will point to the redirected location in AD instead of the Computers or Users OUs. 

SID Binding

Every security principal (e.g., user, computer, group) in AD is also assigned a Security Identifier (SID) value that can be used to bind to the object; for example: 

[adsi] "LDAP://<SID=S-1-5-21-2705499308-1538001639-2142743037-500>"
Code language: JSON / JSON with Comments (json)

As with the GUID, either the dashed format can be used, or the raw SID value can be translated to a hex string. 

The SID format is also useful when dealing with groups that contain members from outside the domain (Domain Local or Universal). To be a member of a group, you must have a DN in the AD domain that the group is in—but external users or groups by definition do not. 

To accommodate external members of groups, AD uses placeholder objects for the external member in the domain’s ForeignSecurityPrincipals container. This allows the external member to have a representation in the domain and be added to the group. 

You can add a Foreign Security Principal (FSP) object directly to a group using the DN format for the object if it already exists. If it doesn’t exist, you would normally need to create it first and then add it. But if you use the SID format, AD will automatically create the FSP object if it doesn’t already exist, making the operation much simpler. 

Are We Having Fun Yet?

These techniques aren’t game changers, but they may provide some shortcuts when you’re building scripts to work with AD or working on servers with limited access to tools. Hopefully these tricks will improve your ability to script, administer, or diagnose AD—and maybe have some fun along the way. 

Need advice on your Active Directory installation? The experts at Ravenswood Technology Group can help. Contact us today!