Reputation: 207
I've written some code that gets all users of groups and nested groups. I also wanted to make sure that looping did not happen if the group membership caused a loop by having the first group a member of the last group.
The code I wrote works OK but is a little slow.
This is the first time I've tried to do AD look-ups.
Could someone take a look and tell me if the code looks OK or bad-coding (or worse), or I've gone about it the wrong way?
using System;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices;
using System.IO;
namespace Tester3
{
class Program3
{
public static List<string> appGroupList = new List<string>();
public static List<string> userList = new List<string>();
public static List<string> groupList = new List<string>();
public static List<string> groupChecked = new List<string>();
static void Main(string[] args)
{
// Create Output File
StreamWriter outputfile = new StreamWriter("output.txt", false);
appGroupList.Add("GLB-SBCCitrixHelpdesk-DL");
appGroupList.Add("SBC_UKBSAVIA001_PROD_ROL_Siebel");
foreach (string appGroup in appGroupList)
{
string appGroupCN = GetCN(appGroup);
GetMembers(appGroupCN);
groupChecked.Clear();
}
foreach (string item in userList)
{
Console.WriteLine(item);
outputfile.WriteLine(item);
}
outputfile.Flush();
outputfile.Close();
Console.ReadLine();
}
private static string GetCN(string group)
{
string groupCN = string.Empty;
try
{
using (DirectorySearcher search = new DirectorySearcher())
{
search.Filter = "(&(cn=" + group + ")(objectClass=group))";
search.PropertiesToLoad.Add("CN");
SearchResult result = search.FindOne();
if (result != null)
{
groupCN = result.Properties["adsPath"][0].ToString();
groupCN = groupCN.Replace("LDAP://", "");
}
return groupCN;
}
}
catch (Exception)
{
return groupCN;
}
}
public static void GetMembers(string group) // get members using the groups full cn
{
// Check if group has already been checked
if (groupChecked.Contains(group))
{
return;
}
// Add group to groupChecked list
groupChecked.Add(group);
try
{
// Connect to group object
using (DirectoryEntry groupObject = new DirectoryEntry("LDAP://" + group))
{
// Get member of group object
PropertyValueCollection col = groupObject.Properties["member"] as PropertyValueCollection;
// Loop through each member
foreach (object member in col)
{
// Connect to member object
using (DirectoryEntry memberObject = new DirectoryEntry("LDAP://" + member))
{
// Get class of member object
string memberClass = memberObject.Properties["objectClass"][1].ToString();
string memberCN = memberObject.Properties["Name"][0].ToString();
if (!groupChecked.Contains(member.ToString()))
{
if (memberClass.ToLower() == "group")
{
GetMembers(member.ToString());
}
else
{
userList.Add(memberCN);
}
}
else
{
if (memberClass.ToLower() != "group")
{
userList.Add(memberCN);
}
}
}
}
}
}
catch (Exception)
{
}
}
}
}
Upvotes: 4
Views: 5218
Reputation: 754318
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement
(S.DS.AM) namespace. Read all about it here:
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
// get a user's group memberships
foreach(Principal principal in me.GetGroups())
{
GroupPrincipal gp = (principal as GroupPrincipal);
if(gp != null)
{
// do something with the group
}
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD. The call to .GetGroups()
also handles all the problems of nested group memberships and so forth for you - no need to deal with that hassle anymore!
Upvotes: 1