Hello, Randy Evans here. I am a principal developer on the Information Security Tools team.
In a recent project, we found it necessary to get collections of users from security groups defined in Active Directory (AD). It is common practice for security administrators to create hierarchies of security groups, which allows for easier membership management. The requirement we faced was that whatever privileges were granted to members of a security group, those privileges apply to any members of security groups found downstream in the hierarchy. This is also a commonly used concept. It was necessary for use to find the security group in AD (represented as a single directory entry) and then drill down into each level of the group hierarchy and find all user members of all associated security groups.
If you’re at all familiar with AD you’ll know that the members of a group (be it a security group or a distribution group) are contained in a property collection called “members”. It is a simple process to query AD for the group and retrieve the collection of members for that group. The difficulty comes in when the security group contains one or members that are security groups. AD does not store properties in the member collection that indicate the member’s type in the member collection. Thus, it becomes necessary to query AD on every member to get their directory entry. The directory entry contains the metadata required to determine the type of the member.
I’ve provided some simplified sample code that demonstrates our solution. The first object (GetAllUsers) gathers the members into a collection that is passed back to the client. The second is a static object (CISFLDAP) that makes the call to AD to retrieve a specific directory entry and return the entry’s collection of properties to the first object. GetAllUsers has two methods. The client calls the GetADSEcurityGroupUsers method passing in the top of hierarchy security group. This method calls the CISFLDAP object to get the top level security group’s directory entry. It then calls a method that loops through the members calling CISFLDAP for each member. If the type of the member is a user, it saves the user in a collection. If the type of the member is a security group, the method will recurse and get the members for this new security group.