7

Hi,

I have the following code to create a tree from the current AD :

public static ActiveDirectory GetActiveDirectoryTree(string pathToAD = "")
{
    DirectoryEntry objADAM = default(DirectoryEntry);
    // Binding object. 
    DirectoryEntry objGroupEntry = default(DirectoryEntry);
    // Group Results. 
    DirectorySearcher objSearchADAM = default(DirectorySearcher);
    // Search object. 
    SearchResultCollection objSearchResults = default(SearchResultCollection);
    // Binding path. 
    ActiveDirectory result = new ActiveDirectory();
    ActiveDirectoryItem treeNode;

    // Get the AD LDS object. 
    try
    {
        if (pathToAD.Length > 0)
            objADAM = new DirectoryEntry();
        else
            objADAM = new DirectoryEntry(pathToAD);
        objADAM.RefreshCache();
    }
    catch (Exception e)
    {
        throw e;
    }

    // Get search object, specify filter and scope, 
    // perform search. 
    try
    {
        objSearchADAM = new DirectorySearcher(objADAM);
        objSearchADAM.Filter = "(&(objectClass=group))";
        objSearchADAM.SearchScope = SearchScope.Subtree;
        objSearchResults = objSearchADAM.FindAll();
    }
    catch (Exception e)
    {
        throw e;
    }

    // Enumerate groups 
    try
    {
        if (objSearchResults.Count != 0)
        {
            //SearchResult objResult = default(SearchResult);
            foreach (SearchResult objResult in objSearchResults)
            {
                objGroupEntry = objResult.GetDirectoryEntry();
                result.ActiveDirectoryTree.Add(new ActiveDirectoryItem() { Id = objGroupEntry.Guid, ParentId = objGroupEntry.Parent.Guid, AccountName = objGroupEntry.Name, Type = ActiveDirectoryType.Group, PickableNode = false });

                foreach (object child in objGroupEntry.Properties["member"])
                {
                    treeNode = new ActiveDirectoryItem();
                    var path = "LDAP://" + child.ToString().Replace("/", "\\/");
                    using (var memberEntry = new DirectoryEntry(path))
                    {
                        if (memberEntry.Properties.Contains("sAMAccountName") && memberEntry.Properties.Contains("objectSid"))
                        {
                            treeNode.Id = Guid.NewGuid();
                            treeNode.ParentId = objGroupEntry.Guid;
                            treeNode.AccountName = memberEntry.Properties["sAMAccountName"][0].ToString();
                            treeNode.Type = ActiveDirectoryType.User;
                            treeNode.PickableNode = true;
                            treeNode.FullName = memberEntry.Properties["Name"][0].ToString();

                            byte[] sidBytes = (byte[])memberEntry.Properties["objectSid"][0];
                            treeNode.ObjectSid = new System.Security.Principal.SecurityIdentifier(sidBytes, 0).ToString();

                            result.ActiveDirectoryTree.Add(treeNode);
                        }
                    }
                }
            }
        }
        else
        {
            throw new Exception("No groups found");
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.Message);
    }

    return result;
} 

The problem is that using (var memberEntry = new DirectoryEntry(path)) returns DomainUsers as a user to this tree and Im not sure if this is correct?

Say that I store the sidId for the DomainUsers node and then sends it to the following method :

public static Boolean GetActiveDirectoryName(string sidId,out string samAccountName,out string fullName)
        {
            samAccountName = string.Empty;
            fullName = string.Empty;


            if (sidId != null && sidId.Length > 0)
            {
                var ctx = new System.DirectoryServices.AccountManagement.PrincipalContext(ContextType.Domain, null);
                using (var up = UserPrincipal.FindByIdentity(ctx, IdentityType.Sid, sidId))
                {
                    samAccountName = up.SamAccountName;
                    fullName = up.Name;

                    return true;
                }
            }
            return false;
        }

The up will be set to null? If I choose another user in the AD then it workes just fine. I suspect that the DomainUsers is a group, but how do I check for this on then DirectoryEntry?

BestRegards

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Banshee
  • 15,376
  • 38
  • 128
  • 219

2 Answers2

6

Off the top of my head: Have you considered checking Schema properties of the returned result? I'm thinking you could easily figure a group by using DirectoryEntry.SchemaEntry.Name. It should return group if your schema entry is a group.

Reference: MSDN: DirectoryEntry.SchemaEntry


Just out of curiosity and a bit off topic in your code above:
 if (pathToAD.Length > 0)
      objADAM = new DirectoryEntry();
 else
      objADAM = new DirectoryEntry(pathToAD);
 objADAM.RefreshCache();

wouldn't you want to use pathToAD IF the Length>0?

Maverik
  • 5,619
  • 35
  • 48
  • Thanks! Strange, in my solution the SchemaEntry.Name is set to group? not container? Thanks for the second sugestion! – Banshee Jun 15 '11 at 11:39
  • You're welcome. Well thats MSDN for you :) I haven't had to recursively find groups yet myself so didn't know it had changed. Thanks for letting me know too. – Maverik Jun 15 '11 at 11:55
  • 1
    @ChrisHayes updated answer. `group` is the correct return value, `container` is for OUs which is what's being shown in MSDN example. – Maverik Jun 13 '16 at 17:52
3

Warning:
The accepted answer is dangerous to use since the DirectoryEntry.SchemaEntry.Name might be anything. (See here for more details).

So, the easiest way would be to check the objectClass instead, like this:

// For group check
bool isGroup = entry.Properties["objectClass"]?.Contains("group") == true;
// For user check
bool isUser = entry.Properties["objectClass"]?.Contains("user") == true;

P.S. For those who are wondering why I've used == true, see here

Just Shadow
  • 10,860
  • 6
  • 57
  • 75