4
votes

I'm using System.DirectoryServices.AccountManagement to query for a user and then find the groups for that user.

var _principalContext = new PrincipalContext(ContextType.Domain, domainAddress, adContainer, adQueryAccount, adQueryAccountPassword);
var user = UserPrincipal.FindByIdentity(_principalContext, IdentityType.SamAccountName, account);
var userGroups = user.GetGroups(); 

foreach (var group in userGroups.Cast<GroupPrincipal>())
{
    //////////////////////////////////////////////////////
    // getting the underlying DirectoryEntry shown
    // to demonstrate that I can retrieve the underlying
    // properties without the exception being thrown
    DirectoryEntry directoryEntry = group.GetUnderlyingObject() as DirectoryEntry;

    var displayName = directoryEntry.Properties["displayName"];

    if (displayName != null && displayName.Value != null)
        Console.WriteLine(displayName.Value);
    //////////////////////////////////////////////////////

    Console.WriteLine(group.DisplayName);// exception thrown here...
}

I can grab the underlying DirectoryEntry object and dump its properties and values but as soon as the GroupPrincipal.DisplayName property (or any property for that matter) is accessed, it throws the following exception:

"System.Runtime.InteropServices.COMException (0x8007200A): The specified directory service attribute or value does not exist.\r\n\r\n at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)\r\n at System.DirectoryServices.DirectoryEntry.Bind()\r\n at System.DirectoryServices.DirectoryEntry.get_SchemaEntry()\r\n at System.DirectoryServices.AccountManagement.ADStoreCtx.IsContainer(DirectoryEntry de)\r\n at System.DirectoryServices.AccountManagement.ADStoreCtx..ctor(DirectoryEntry ctxBase, Boolean ownCtxBase, String username, String password, ContextOptions options)\r\n at System.DirectoryServices.AccountManagement.PrincipalContext.CreateContextFromDirectoryEntry(DirectoryEntry entry)\r\n at System.DirectoryServices.AccountManagement.PrincipalContext.DoLDAPDirectoryInitNoContainer()\r\n at System.DirectoryServices.AccountManagement.PrincipalContext.DoDomainInit()\r\n at System.DirectoryServices.AccountManagement.PrincipalContext.Initialize()\r\n at System.DirectoryServices.Account Management.PrincipalContext.get_QueryCtx()\r\n at System.DirectoryServices.AccountManagement.Principal.HandleGet[T](T& currentValue, String name, LoadState& state)\r\n at System.DirectoryServices.AccountManagement.Principal.get_DisplayName()\r\n at ConsoleApplication9.Program.Main(String[] args)"

Why would I be able to dump the raw properties of the underlying DirectoryEntry but not be able to call any of the properties directly on the GroupPrincipal? What would cause this exception? Note that this does not happen on the "Domain Users" group but the subsequent groups, it does...

2
Can't reproduce that behavior - when I directly access the group properties I get the expected results back ... could it be a permissions issues with the user that you use for querying AD ??marc_s
@marc_s, it could be permissions but I'm trying to narrow down the issue because working with IT is slow and painful so I want to get as much information about the problem as possible,Jim

2 Answers

6
votes

I found the solution. If I pass the context to the GetGroups method, it works.

var user = UserPrincipal.FindByIdentity(_principalContext, IdentityType.SamAccountName, account);
var userGroups = user.GetGroups(_principalContext);

Apparently, this limits the groups retrieved to the domain associated with the context. Although this is not intuitive because the context was used to retrieve the user in the first place!!!

This leads me to believe there must be groups from other domains being returned previously and permissions were as such to prevent accessing that information.

0
votes

Why are you using the .GetUnderlyingObject() call? Seems totally superfluous... just use the .SamAccountName property of the GroupPrincipal directly...

Try this:

foreach (var group in userGroups.Cast<GroupPrincipal>())
{
    Console.WriteLine(group.SamAccountName);
    Console.WriteLine(group.DisplayName);
    Console.WriteLine(group.IsSecurityGroup);
}

Seems a lot easier - no?