This is how I list all the groups (direct and indirect) for a specific Distinguished Name:
The string 1.2.840.113556.1.4.1941 specifies LDAP_MATCHING_RULE_IN_CHAIN.
This rule is limited to filters that apply to the DN. This is a special "extended" match operator that walks the chain of ancestry in objects all the way to the root until it finds a match.
This method is 25 times faster than the UserPrincipal.GetGroups() method in my testing.
Note: The primary group (typically Domain Users) is not returned by this or GetGroups() method. To get the primary group name too, I've confirmed this method works.
Additionally, I found this list of LDAP filters extremely useful.
private IEnumerable<string> GetGroupsForDistinguishedName(DirectoryEntry domainDirectoryEntry, string distinguishedName)
{
var groups = new List<string>();
if (!string.IsNullOrEmpty(distinguishedName))
{
var getGroupsFilterForDn = $"(&(objectCategory=group)(member:1.2.840.113556.1.4.1941:={distinguishedName}))";
using (DirectorySearcher dirSearch = new DirectorySearcher(domainDirectoryEntry))
{
dirSearch.Filter = getGroupsFilterForDn;
dirSearch.PropertiesToLoad.Add("name");
using (var results = dirSearch.FindAll())
{
foreach (SearchResult result in results)
{
if (result.Properties.Contains("name"))
groups.Add((string)result.Properties["name"][0]);
}
}
}
}
return groups;
}