views:

1698

answers:

2

I am working on an application that manages user accounts in Active Directory. I am using the System.DirectoryServices.AccountManagement namespace whereever possible, but I can't figure out how to determine a user's primary group. When I try to remove a group that is the user's primary group I get an exception. Here is my current code:

private void removeFromGroup(UserPrincipal userPrincipal, GroupPrincipal groupPrincipal) {
    TODO: Check to see if this Group is the user's primary group.
    groupPrincipal.Members.Remove(userPrincipal);
    groupPrincipal.Save();
}

Is there a way to get the name of the user's primary group so I can do some validation before trying to remove the user from this group?

A: 

The RID of the user's primary group is stored in the 'primaryGroupID' attribute on the user object. You'd have to get the DirectoryEntry for the given user (or user other API's) in order to retrieve this value. After getting that value, you'd have to translate it into a SID for the primary group, and then get the group from that.

There is a KB article that has more detail on this, as well as VB code with how to find the primary group, here: http://support.microsoft.com/kb/297951

Michael Morton
+2  A: 

It's quite a messy and involved business - but this code snippet is from my BeaverTail ADSI Browser which I wrote completely in C# (in the .NET 1.1 days) and is known to work - not pretty, but functional:

private string GetPrimaryGroup(DirectoryEntry aEntry, DirectoryEntry aDomainEntry)
{
   int primaryGroupID = (int)aEntry.Properties["primaryGroupID"].Value;
   byte[] objectSid = (byte[])aEntry.Properties["objectSid"].Value;

   StringBuilder escapedGroupSid = new StringBuilder();

   // Copy over everything but the last four bytes(sub-authority)
   // Doing so gives us the RID of the domain
   for(uint i = 0; i < objectSid.Length - 4; i++)
   {
      escapedGroupSid.AppendFormat("\\{0:x2}", objectSid[i]);
   }

   //Add the primaryGroupID to the escape string to build the SID of the primaryGroup
   for(uint i = 0; i < 4; i++)
   {
      escapedGroupSid.AppendFormat("\\{0:x2}", (primaryGroupID & 0xFF));
      primaryGroupID >>= 8;
   }

   //Search the directory for a group with this SID
   DirectorySearcher searcher = new DirectorySearcher();
   if(aDomainEntry != null)
   {
       searcher.SearchRoot = aDomainEntry;
   }

   searcher.Filter = "(&(objectCategory=Group)(objectSID=" + escapedGroupSid.ToString() + "))";
   searcher.PropertiesToLoad.Add("distinguishedName");

   return searcher.FindOne().Properties["distinguishedName"][0].ToString();
}

Hope this helps.

Marc

marc_s
wow. ugly but it works :) +1
Simon