1
\$\begingroup\$

This is intended to be a model for an application that queries an Active Directory. It can return IEnumerables of the following:

  • Users, given context.
  • Groups, given context or users.
  • Users, given group.
  • User Group Membership, given context or users.
  • User Direct Reports, given context or users.
  • Computers, given context.
  • Computers, given group.

This should allow any program calling these methods to access everything in the active directory by all possible queries. If you can think of an additional query that you would find useful, please include it in your answer.

There are also some included extension methods to make the code more organized in my opinion. Again, if this were used in another program, the underlying directory entry for principals and all the properties thereof would be more convenient to access by using user.GetProperty(propertyName) instead of

var userAsDirectoryEntry = user.GetUnderlyingObject() as DirectoryEntry;
userAsDirectoryEntry.Properties[proeprtyName];

where user is a UserPrincipal in both cases.

ActiveDirectorySearcher.cs

using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Linq;

namespace ActiveDirectoryTool
{
    internal struct DirectReports
    {
        internal IEnumerable<UserPrincipal> Reports { get; set; }
        internal UserPrincipal User { get; set; }
    }

    internal struct UserGroups
    {
        internal IEnumerable<GroupPrincipal> Groups { get; set; }
        internal UserPrincipal User { get; set; }
    }

    internal static class UserPrincipalExtensions
    {
        internal static DirectoryEntry GetAsDirectoryEntry(
            this UserPrincipal user)
        {
            return user.GetUnderlyingObject() as DirectoryEntry;
        }

        internal static IEnumerable<string> GetDirectReportDistinguishedNames(
            this UserPrincipal user)
        {
            return ((IEnumerable<string>)user.GetProperty("directReports"));
        }

        internal static IEnumerable<UserPrincipal> GetDirectReports(
            this UserPrincipal user)
        {
            var directReports = new List<UserPrincipal>();
            foreach (var directReportDistinguishedName in
                user.GetDirectReportDistinguishedNames())
            {
                directReports.Add(UserPrincipal.FindByIdentity(
                    user.Context,
                    IdentityType.DistinguishedName,
                    directReportDistinguishedName));
            }
            return directReports;
        }

        internal static object GetProperty(
            this UserPrincipal user, string propertyName)
        {
            return user.GetAsDirectoryEntry().Properties[propertyName];
        }
    }

    internal class ActiveDirectorySearcher
    {
        internal static IEnumerable<ComputerPrincipal> GetComputersFromContext(
            PrincipalContext context)
        {
            var computers = new List<ComputerPrincipal>();
            using (var searcher = new PrincipalSearcher(
                    new ComputerPrincipal(context)))
            {
                computers =
                    searcher.FindAll().OfType<ComputerPrincipal>().ToList();
            }
            return computers;
        }

        internal static IEnumerable<ComputerPrincipal> GetComputersFromGroup(
            GroupPrincipal group)
        {
            return group.GetMembers().OfType<ComputerPrincipal>();
        }

        internal static IEnumerable<DirectReports> GetDirectReportsFromUsers(
                    IEnumerable<UserPrincipal> users)
        {
            var directReports = new List<DirectReports>();
            foreach (var user in users)
            {
                directReports.Add(new DirectReports
                {
                    User = user,
                    Reports = user.GetDirectReports()
                });
            }
            return directReports;
        }

        internal static IEnumerable<DirectReports> GetDiretReportsFromContext(
            PrincipalContext context)
        {
            return GetDirectReportsFromUsers(GetUsersFromContext(context));
        }

        internal static IEnumerable<GroupPrincipal> GetGroupsFromContext(
            PrincipalContext context)
        {
            return GetGroupsFromUsers(GetUsersFromContext(context));
        }

        internal static IEnumerable<GroupPrincipal> GetGroupsFromUsers(
            IEnumerable<UserPrincipal> users)
        {
            var groups = new HashSet<GroupPrincipal>();
            foreach (var user in users)
            {
                groups.UnionWith(
                    user.GetGroups().OfType<GroupPrincipal>().ToList());
            }

            return groups;
        }

        internal static IEnumerable<UserGroups> GetUserGroupsFromContext(
            PrincipalContext context)
        {
            return GetUserGroupsFromUsers(GetUsersFromContext(context));
        }

        internal static IEnumerable<UserGroups> GetUserGroupsFromUsers(
            IEnumerable<UserPrincipal> users)
        {
            var userGroups = new List<UserGroups>();
            foreach (var user in users)
            {
                userGroups.Add(new UserGroups
                {
                    User = user,
                    Groups = user.GetGroups().OfType<GroupPrincipal>().ToList()
                });
            }
            return userGroups;
        }

        internal static IEnumerable<UserPrincipal> GetUsersFromContext(
            PrincipalContext context)
        {
            var users = new List<UserPrincipal>();
            using (var searcher = new PrincipalSearcher(new UserPrincipal(
                context)))
            {
                users = searcher.FindAll().OfType<UserPrincipal>().ToList();
            }
            return users;
        }

        internal static IEnumerable<UserPrincipal> GetUsersFromGroup(
            GroupPrincipal group)
        {
            return group.GetMembers().OfType<UserPrincipal>().ToList();
        }
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ It's fairly hard to fault the code you've written, neglecting the fact that everything is static. \$\endgroup\$ – RubberDuck Jun 9 '16 at 23:23
  • \$\begingroup\$ @RubberDuck Could you recommend a resource about how to avoid static stuff? I find myself in situations where I just need a bunch of methods to do something, but they don't really fit well with an object. In this case, a lot of these are extension methods, which must be static (in a static class). I suppose I could arbitrarily make the rest attached to an object, but I don't see the point, as the object would have no fields/properties to store. I have tended to make things static ever since I started programming unless I specifically need an object, and have never really found a "solution." \$\endgroup\$ – Michael Brandon Morris Jun 10 '16 at 1:19
  • 1
    \$\begingroup\$ The extension methods seem fine to me. There's not really an alternative for those. It's the other set that doesn't sit right with me. As for a resource... Experience is the only teacher I have there. Start test driving your code and you'll quickly see why you may want to have an instance of an object that you can fake. \$\endgroup\$ – RubberDuck Jun 10 '16 at 3:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.