1

I want to locate the Primary Group from the code below

I can get all the Groups for a user, but which one is the primary group?

        string primaryGroupName = String.Empty;
        using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
        {
            using (UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "userName"))
            {
                foreach (Principal p in user.GetGroups())
                {
                    WriteLog("PrimaryGroup Name(s)???:");
                    WriteLog(p.Name);
                    primaryGroupName = p.Name;
                }
            }
        }

Whats returned from the code above is...

Domain Users
Administrators
Schema Admins
Enterprise Admins
Domain Admins
..and a few more

What is the Primary Group?

nlstack01
  • 789
  • 2
  • 7
  • 30
  • You can get the primary group id, but I don't know how to get from there to the name of the group. `var userEntry = user.GetUnderlyingObject() as DirectoryEntry; var primaryGroupId = userEntry.Properties["primaryGroupID"].Value;` –  Jul 11 '19 at 17:23
  • @Amy Thanks that seems to give me an id (i.e. 513) now how to I use the id to grab the group name? – nlstack01 Jul 11 '19 at 18:04
  • I said I don't know how to do that, sorry. –  Jul 11 '19 at 18:05
  • Is it possible the last numbers of the SID is the "id"? Sid=S-1-5-21-xxxxxxxxxx-xxxxxxxxx-xxxxxxxxx-513 – nlstack01 Jul 11 '19 at 19:46

1 Answers1

1

You have the right idea: The primaryGroupID holds the RID (Relative Identifier) of the group that is the primary group. The RID is the last set of numbers in the SID. The rest of the SID identifies the domain. So you can figure out the SID of the group using the SID of the user and the primaryGroupID.

I wrote a couple articles about this. One called What makes a member a member?, with a section describing the primary group. But also an article called Finding all of a user’s groups where I shared some code to find the primary group. I have found that using DirectoryEntry directly is always faster than using UserPrincipal/GroupPrincipal, so that's what my examples use:

Here is the method:

private static string GetUserPrimaryGroup(DirectoryEntry de) {
    de.RefreshCache(new[] {"primaryGroupID", "objectSid"});

    //Get the user's SID as a string
    var sid = new SecurityIdentifier((byte[])de.Properties["objectSid"].Value, 0).ToString();

    //Replace the RID portion of the user's SID with the primaryGroupId
    //so we're left with the group's SID
    sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
    sid = sid + de.Properties["primaryGroupId"].Value;

    //Find the group by its SID
    var group = new DirectoryEntry($"LDAP://<SID={sid}>");
    group.RefreshCache(new [] {"cn"});

    return group.Properties["cn"].Value as string;
}

To use that from your code, you would do this:

var primaryGroupName = GetUserPrimaryGroup((DirectoryEntry) user.GetUnderlyingObject());

That method just returns the name of the group, but you can modify it as you need.

All that said, 513 is always the RID of the built-in Domain Users group.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84