7

I'am back with my Active Directory tool...

I'am trying to list the groups in the "member of" attribute of a user. Below is the function I use:

public static DataTable ListGroupsByUser(string selectedOu)
{
    DataTable groupListByUser = new DataTable();
    String dom = "OU=" + selectedOu + ",OU=XXX,DC=XXX,DCXXX,DC=XXX,DC=XXX";
    DirectoryEntry directoryObject = new DirectoryEntry("LDAP://" + dom);

    DataColumn column;
    DataRow row;

    column = new DataColumn();
    column.ColumnName = "ID";
    groupListByUser.Columns.Add(column);

    column = new DataColumn();
    column.ColumnName = "User";
    groupListByUser.Columns.Add(column);

    column = new DataColumn();
    column.ColumnName = "Groups";
    groupListByUser.Columns.Add(column);
    int i = 1;

    foreach (DirectoryEntry child in directoryObject.Children)
    {                
        row = groupListByUser.NewRow();
        groupListByUser.Rows.Add(row);
        row["ID"] = i++;

        if (child.Properties["memberOf"].Value != null)
        {                    
            row["User"] = child.Properties["sAMAccountName"].Value.ToString();
            row["Groups"] = child.Properties["memberOf"].Value.ToString();
        }
        else
        {
            row["Groups"] = "blabla";
        }
    }
    return groupListByUser;
}

It returns the right group for users belonging to only one group. As soon as There's more than one group, it returns System.Object[].

How can I do to see all groups ?

JPBlanc
  • 70,406
  • 17
  • 130
  • 175
Henry Meyer
  • 265
  • 1
  • 5
  • 12

2 Answers2

6

The problem is your Properties["memberOf"].Value.ToString().

I made a little investigation and this code worked for me:

var memberGroups = child.Properties["memberOf"].Value;

if (memberGroups.GetType() == typeof(string))
{
    row["Groups"] = (String)memberGroups;
}
else if (memberGroups.GetType().IsArray)
{
    var memberGroupsEnumerable = memberGroups as IEnumerable;

    if (memberGroupsEnumerable != null)
    {
        var asStringEnumerable = memberGroupsEnumerable.OfType<object>().Select(obj => obj.ToString());
        row["Groups"] = String.Join(", ", asStringEnumerable);
    }
}
else
{
    row["Groups"] = "No group found.";
}

It's not very cute but it works and gives room for further improvements. ;-)

Oliver
  • 43,366
  • 8
  • 94
  • 151
  • Thanks Oliver, I tried your solution but seems a bit tricky. I don't really understand what I'm doing with this: var groups = objArray.Cast().Select(elem => elem.Values.ToString()); It returns me an error : Value cannot be null. Parameter name: source – Henry Meyer Feb 29 '12 at 08:10
  • @HenryMeyer: I reworked my code, but i think that marc_s approach is really better in the long run, cause you don't have to hassle with these bunch of strings and object arrays. They are type specific classes making it veeerry easy to access all this stuff much more convenient. – Oliver Feb 29 '12 at 09:53
4

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)
{
   var groups = user.GetGroups();
   // or there's also:
   //var authGroups = userByEmail.GetAuthorizationGroups()
}

The calls to GetGroups() or GetAuthorizationGroups() will return nested group membership, too - so no need for you to hunt those nested memberships anymore!

The new S.DS.AM makes it really easy to play around with users and groups in AD!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Thanks Marc, I managed to deal with users and groups, what I can't do is loop through the list of user's memberships. Is it worth for me to rebuild the tool with the accountManagement namespace instead of directoryServices ? – Henry Meyer Feb 28 '12 at 12:52
  • @Oliver: Thanks guys. Despite your advices, i found a solution, following: 'code' if (child.Properties["memberOf"].Value != null) { foreach (Object memberof in child.Properties["memberOf"]) { //row["User"] = child.Properties["sAMAccountName"].Value.ToString(); row["Member Of"] += memberof.ToString() + " /// "; } } else { row["Member Of"] = "No Group Defined"; } – Henry Meyer Feb 29 '12 at 14:02
  • `GetGroups()` vs `GetAuthorizationGroups()` differences ? – Kiquenet Jun 05 '19 at 09:35
  • What if you don't want to get all of the (nested) groups, but only want the names? – Sangman Oct 03 '19 at 15:06
  • To answer my own question: call GetUnderlyingObject on Principal and via Properties array get "memberOf" – Sangman Oct 03 '19 at 15:25
  • is `memberOf` an array? Thanks. – Si8 Dec 15 '20 at 14:03