views:

82

answers:

2

I'm trying to get a list of users and some properties about the user from within an active directory group.

Update:

Here are the two methods I currently have:

    Dim adGroup As New DirectoryEntry("LDAP://CN=MyGroup,OU=Groups,OU=Accounts,OU=All,DC=domain,DC=com")
    Dim adMembers As Object
    Dim objUser As ActiveDirectoryUser
    Dim objUserList As New List(Of ActiveDirectoryUser)
    Dim directoryEntry As DirectoryEntry

    adMembers = adGroup.Invoke("Members", Nothing)

    For Each adMember As Object In CType(adMembers, IEnumerable)
        directoryEntry = New DirectoryEntry(adMember)
        objUser = New ActiveDirectoryUser

        objUser.UserId = directoryEntry.Properties.Item("sAMAccountName").Value.ToString()
        objUser.Contract = directoryEntry.Properties.Item("ou").Value.ToString()
        objUser.LastName = directoryEntry.Properties.Item("sn").Value.ToString()
        objUser.FirstName = directoryEntry.Properties.Item("givenName").Value.ToString()
        objUser.Email = directoryEntry.Properties.Item("mail").Value.ToString()

        objUserList.Add(objUser)
    Next

The first piece works, though it seems quite inefficient. My memory usage climbs and climbs as it's executing and I was getting this error, though it looks like that can be fixed. The second method:

    Dim results As SearchResultCollection
    Dim directoryEntry2 As New DirectoryEntry("LDAP://DC=domain,DC=com")
    Dim directorySearcher As New DirectorySearcher(directoryEntry2)
    directorySearcher.PageSize = 1000

    directorySearcher.Filter = "(&(objectCategory=person)" & _
                           "(objectClass=user)" & _
                           "(memberOf=CN=MyGroup,OU=Groups,OU=Accounts,OU=All,DC=domain,DC=com))"


    directorySearcher.PropertiesToLoad.Add("ou")
    directorySearcher.PropertiesToLoad.Add("sn")
    directorySearcher.PropertiesToLoad.Add("givenName")
    directorySearcher.PropertiesToLoad.Add("sAMAccountName")
    directorySearcher.PropertiesToLoad.Add("mail")

    results = directorySearcher.FindAll

The result count seems to vary from each execution of the application which I find odd. I'm not sure if this is a reliable way of getting the users back or if I need to modify something on my search?

+1  A: 

Scope your search wider, wherever the members may be:

Dim directoryEntry As New DirectoryEntry("LDAP://OU=All,DC=Domain,DC=com")

Filter based on group membership:

directorySearcher.Filter = "(&(objectCategory=person)" & _
                             "(objectClass=user)" & _
                             "(memberOf=CN=MyGroup,OU=Groups,OU=All,DC=Domain,DC=com))"
Greg
You'll probably need to set directorySearcher.PageSize = 1000 if you are widening the scope.
decompiled
Still no luck. I took exactly what you gave, dropped in my specific values, but I'm not getting any results back.
Ek0nomik
@Ek0nomik - My original answer had a typo. I think "memberOf" doesn't have a space.
Greg
@marc_s - How is my answer different from what you suggest in the "Update" section of your answer?
Greg
@Greg: your original post wouldn't have worked.... now that you've corrected it, it's almost the same as mine. I would limit my LDAP filter to objectCategory (single-valued, indexed) and forget about objectClass, generally - but other than that, we're at the same point now.
marc_s
+2  A: 

IF you can, do upgrade to .NET 3.5 and use the new much improved System.DirectoryServices.AccountManagement namespace. Great intro for those new classes is found in Managing Directory Security Principals in the .NET Framework 3.5.

With this, your job becomes trivial:

PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "MyGroup");
PrincipalSearchResult<Principal> members = group.GetMembers();

Does that work for you?

If you cannot use .NET 3.5, you should inspect the member property of the group. The group members are not stored as children logically underneath the group in hierarchy, so you cannot find them by using a DirectorySearcher.

DirectoryEntry group = new DirectoryEntry("LDAP://CN=MyGroup,OU=Groups,OU=All,DC=Domain,DC=com");

foreach(object groupMemberDN in group.Properties["member"])
{
   // grab the group member's DN
}

See the Quick List of C# Code Examples for Active Directory (or the same for Visual Basic .NET) in the MSDN library for this snippet and more.

Update: if you need the users belonging to a particular group (since you want to update their properties or something), you could reverse the approach: search for all the users who have a memberOf property equivalent to the group's DN:

 DirectoryEntry root = new DirectoryEntry("LDAP://dc=domain,dc=com");
 DirectorySearcher searcher = new DirectorySearcher(root);

 searcher.Filter = "(&(objectCategory=user)(memberOf=CN=MyGroup,OU=Groups,OU=All,DC=Domain,DC=com))";
 // set other properties on the searcher

 foreach(object result in searcher.FindAll())
 {
    // do whatever you need to do with the entry
 }
marc_s
Looping through the member properties got me close. I'll still need to pull properties off the member object then (first name, e-mail, etc). I assume I'll need to cast the groupmemberDN in your example to a specific object type so I can pull properties from it?
Ek0nomik
@marc_s - Thanks for your help so far. I have two questions. First, you had said that I couldn't get the members by using a directory searcher, so in your updated example I see that I can, so I was hoping you could elaborate on what you meant there. Second, I am able to get a result by using the directory searcher, but the count in the collection seems to vary each time I run my application, when it should be consistent (nobody is currently being added to the group).
Ek0nomik
@Ek0nomik: you **cannot** enumerate a group to find all its members, since a group is **not** a container in AD which you can enumerate over. It doesn't contain its members as child objects. You can however enumerate a directory branch and find all the users who are member of a specific group.
marc_s