If you have ever tried to enumerate all groups that a user is a member of in Active Directory then you have probably found that the standard way of doing this (looking at the user’s MemberOf attribute) does not get the user’s primary group. You probably then found out that the user is ‘joined’ to their primary group by simply having the Relative ID (RID) of the group in their PrimaryGroupID attribute. That’s great and all… but how do we translate that RID into the name of the group? Well I’m sure there are a few ways to do it but here’s the code I came up with:
Please note that this function assumes that the group and user you are working with are on the same domain that your user account is a member of. Detailed explanation of the code can be found below.
As you can see, the GetPrimaryGroupName function takes 2 parameters – a DirectorySearcher object and a SearchResult object. The reason for this is that I wrote this function as part of a program that enumerates all groups a user is a member of, so I already had a DirectorySearcher instance setup and had already used it to retrieve a SearchResult for the user account. So it made sense to reuse the same DirectorySearcher instance by just passing it in as a parameter rather than creating a new one. Obviously that might not fit your needs precisely so you will probably have to modify it slightly but hopefully the actual core parts of the function are still a good example of how to get the name of the user’s primary group from the ID in their PrimaryGroupID attribute.
So what exactly is this function doing and why?
Well, firstly we bind to the current user’s domain and then we get the SID of the domain so that we can add the group’s RID (the value we get from the user’s PrimaryGroupID) to the end of it to get the group’s full SID. So now we have the full SID of the group, we need to find an object with that SID in AD – now I believe in 2003 domains you can just pass the SSDL form of the SID (that’s the form we are used to seeing, e.g S-5-21-X-X-X-X-XX-XX-X-XX) straight in to an LDAP query but in Windows 2000 domains you have to pass the hex version of the SID, so I chose to use the Hex version for compatibility’s sake. So the loop you see in the code is basically just looping through the binary form of the SID and converting it to a hex string that the LDAP filter will understand – this basically just means sticking a \ character in front of each byte once it has been converted to its hex representation (which we do with the handy built in Hex function).
So we just run the search by using the FindAll method of the DirectorySearcher and this should then bring back our group 🙂 So then its simply a case of getting the group name, which we do by using our GetGroupNameFromPath function. This function takes the full group path (e.g LDAP://CN=GroupA,OU=Groups,DC=MyDomain,DC=local) and does the following:
- Removes the LDAP:// from the start of the string and then removes the first 3 characters from the resulting string (which will be “CN=”)
- Loops through the string from start to end and looks for a comma that is not preceded by a \ character. This is because we want to remove everything after the comma that will be at the end of the group name but if the group name contains a comma then we would end up removing any part of the group name that comes after that comma. If a group name has a comma (or any other special character) in it then it will actually be stored in AD with a \ before it. So that is the reason for making sure there isnt a \ before the comma that we find.
- Now that we have the location of the first comma that is not actually part of the group name, we remove everything after that comma so that we are left with just the group name
- We return the string and use several calls to Replace to get rid of the \ character that will precede any special characters