If I'm not asking this in the correct forum, please point me in the right direction.

I am using System.DirectoryServices.AccountManagement.GroupPrincipal FindByIdentity in C# to create an object containing the group members (user IDs and names) for the target group. My goal is to iterate through the resulting list of UserPrincipals and print the SamAccountName and DisplayName for each. For some target groups, this is working fine; for others it fails on a user (or perhaps more than one) that throws the following error:

System.DirectoryServices.AccountManagement.PrincipalOperationException HResult=0x80131501 Message=The specified directory service attribute or value does not exist.

When I use PowerShell’s Get-ADGroup to get the group object for one of the failing targets and iterate through it, there is no problem.

I’ve looked into the AD Group memberships and I believe the problem is that in some groups (those failing), some members may have been disabled, or may be part of a cross-domain trust. However, their status is of no consequence to me; I just want to list everything so the group owner can decide which members get migrated to new groups.

The method I am using is:

private static ArrayList EnumerateGroupMembers()
{
    ArrayList gmObjects = new ArrayList();
    string ldapVal = "DC=dc1,DC=dc2,DC=dcMain,DC=dcSecondary";
    string ldapDom = "dc1.dc2.dcMain.dcSecondary:389";

    PrincipalContext ctx = new PrincipalContext(ContextType.Domain, ldapDom, ldapVal);

    GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "AD-GROUPNAME");

    if (group != null)
    {
        var users = group.GetMembers(true);

        //*** PrincipalOperationException occurs here ***
        foreach (UserPrincipal p in users)
        {
            Console.WriteLine(p.SamAccountName + ", " + p.DisplayName);
        }
        Console.WriteLine("Done");
        Console.ReadKey();
    }
    //*** Please note: I know I am returning an empty list here. I'm writing to Console during development
    return gmObjects;
}

Can anyone suggest how I can iterate through the list of UserPrincipals without throwing a PrincipalOperationException? Or, at least a way to bypass the UserPrincipal occurrences that are causing these errors? Even if I cannot list the failing users I will survive.

Dani AI

Generated

A few practical observations that tie the replies together and point to a reliable fix.

As found, the AccountManagement layer will eagerly bind and try to load attributes for each member it resolves; when a member is a foreign security principal (cross-domain) or when the caller cannot read certain attributes, that binding can raise the PrincipalOperationException you saw. The high-level GetMembers/GetAuthorizationGroups flows hide those LDAP bind details, so an AD object that PowerShell can read directly may still cause AccountManagement to fail. (stackoverflow.com)

A robust workaround is to read the group’s LDAP member values yourself (System.DirectoryServices) and then bind each member entry only for the specific attributes you need. Refresh only objectClass, sAMAccountName, displayName, msDS-PrincipalName, and check property existence before indexing — that prevents the ADSI bind/attribute error from bubbling up as an unhandled PrincipalOperationException. Example pattern (trimmed):

using (var group = new DirectoryEntry("LDAP://<groupDN>"))
{
    group.RefreshCache(new[] { "member" });
    foreach (string memberDn in group.Properties["member"])
    {
        using (var m = new DirectoryEntry("LDAP://" + memberDn))
        {
            m.RefreshCache(new[] { "objectClass", "sAMAccountName", "displayName" });
            if (m.Properties["sAMAccountName"].Count > 0)
                Console.WriteLine(m.Properties["sAMAccountName"][0] + ", " +
                                  (m.Properties["displayName"].Count > 0 ? m.Properties["displayName"][0] : ""));
        }
    }
}

This gives explicit control (and lets you skip/record entries that cannot be read). You can also call Principal.GetUnderlyingObject() when you already have a Principal and want its DirectoryEntry. (learn.microsoft.com)

Notes for cross-domain and large groups: handle foreignSecurityPrincipal entries by mapping the SID prefix to the trusted domain DNS name and binding with the LDAP SID syntax (<SID=...>), and use ranged retrieval for the member attribute when groups exceed the DC’s page-size limits. Those exact techniques and examples are documented in community guidance. (stackoverflow.com)

Combining the above (directory-level enumeration + property existence checks + SID resolution for foreign principals) is the least fragile path; it avoids the hidden binding behavior inside AccountManagement and makes failures explicit and easy to log for the group owner.

I am in no way an expert on this but there was a time this was buggy in .NET 4.0. Also it would be somewhat useful to know what code the call threw at you. My bet is it was some "denied" code like 80005000 or such. You can find the bug in the old .NET with a google on just the word PrincipalOperationException.

As far as an (ugly?) workaround, this may be the time to use try and catch.

The second idea to try is run the app and command line with an elevated permission.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.