Active Directory

User and Group Information in AD

Continuing our Active Directory theme from the last post, I wanted to follow up on locating the groups that users belong to or groups you’d like to add to a user account.  These examples will also continue with using the .Net 3.5 DirectoryServices.AccountManagement namespace since there is quite a bit less code than using the methods for .Net 2.0.

So, the first example deals with getting all of the groups of a user account. Some of the code you might have already seen.

UserPrincipal user = null;
//Create a PrincipleContext that will search the full domain
//ie not just the site's user OU
//FQDC = Fully Qualified Domain Controller
string userName = "MyUserToSearch";
using (var context = new PrincipalContext(ContextType.Domain, FQDC))
{
    try
    {
        if ((user = UserPrincipal.FindByIdentity(context, userName)) != null)
        {
            // Search for current groups
            PrincipalSearchResult<Principal> groups = user.GetGroups();

            // Iterate group membership
            foreach (GroupPrincipal g in groups)
            {
                Console.WriteLine(g.Name);
            }
        }
    }
}

Now we know how to grab the group information for a user, but what if we want to remove a group?

UserPrincipal user = null;
//Create a PrincipleContext that will search the full domain
//ie not just the site's user OU
//FQDC = Fully Qualified Domain Controller
string userName = "MyUserToSearch";
using (var context = new PrincipalContext(ContextType.Domain, FQDC))
{
    try
    {
        if ((user = UserPrincipal.FindByIdentity(context, userName)) != null)
        {
            // Search for current groups
            PrincipalSearchResult<Principal> groups = user.GetGroups();

            // Iterate group membership and remove IT_Dept group
            foreach (GroupPrincipal g in groups)
            {
                if (g.Name == "IT_Dept")
                {
                    g.Members.Remove(user);
                    g.Save();
                }
            }
        }
    }
}

Finally, adding a new group is a little different.

UserPrincipal user = null;
//Create a PrincipleContext that will search the full domain
//ie not just the site's user OU
//FQDC = Fully Qualified Domain Controller

string userName = "MyUserToSearch";
using (var context = new PrincipalContext(ContextType.Domain, FQDC))
{
    try
    {
        if ((user = UserPrincipal.FindByIdentity(context, userName)) != null)
        {
            // Add user to new group
            string groupName = "GroupToAddUser";
            using (var group = GroupPrincipal.FindByIdentity(context, IdentityType.Name, groupName))
            {
                // Verify user is not currently a member and save
                if (!group.Members.Contains(user))
                {
                    group.Members.Add(user);
                    group.Save();
                }
            }
        }
    }
}

Here we search for the group name explicitly, check that the user isn’t already in it and then add the user.  Pretty simple stuff.

Tags: Active Directory, C#

Friday, August 26th, 2011 C# 3 Comments

Active Directory UserPrincipals in .Net

Continuing our Active Directory theme from the last post, I wanted to step back for a second and discuss UserPrincipal objects a little more as I have a few posts relating more to accounts following this one.

The UserPrincipal class has two constructors.  One takes a PrincipalContext and the other one takes the PrincipalContext, SAM account name, password, and enabled value.  In general, I use the constructor with just the PrincipalContext when searching for an existing AD account and the ‘expanded’ constructor when I am creating a new AD user object.  As most Active Directory environments need passwords, and I generally make it a point to not know user passwords (after I create them) I think this makes sense.  So, now I’ll detail these two uses below.

First, let’s take a look at finding a user and mapping it to a UserPrincipal object.  What I’m really focused on here is the UserPrincipal itself and I’ll cover searching more in other articles.  Here’s some code:

using (var context = new PrincipalContext(ContextType.Domain, FQDC))
{
   UserPrincipal user = null;
   do
   {
      // We don't create accounts with '1' so we need to increment again.
      if (count == 1) { count++; }
      // Similar to the ADID we need to determine the identifier for the username
      string filter = count > 0 ? this.UserName + count.ToString() : this.UserName;
      user = UserPrincipal.FindByIdentity(context, filter);
      count++;
   } while (user != null);
}

This is a somewhat expanded example of a routine I use to determine AD usernames but I didn’t want to just throw in three lines and call it a day.  My primary AD domain has 18000+ user accounts so we’re bound to have duplicate names using our standard naming scheme.  In case of a duplicate, I need to append a number on it so that’s what you see here, me determining the number.  What’s truly important here is that by using the FindByIdentity method, we return a UserPrincipal object from AD that contains common AD attributes that we may be interested in and once we have this object we can manipulate these values quite easily.  As a bonus, we can extend this object with custom code and map properties such as the EmployeeID field (which is not exposed by UserPrincipal).  I’ll save that for a later post though.

Now, the second scenario involves us wanting to create a new user.  Finding and connecting to a current user is easy and so is creating a new one.

using (PrincipalContext adPC = new PrincipalContext(ContextType.Domain, FQDC))
{
    using (UserPrincipal user = new UserPrincipal(adPC, this.CommonName, this.Pass, true))
    {
        user.SamAccountName = UserName;
        user.UserName = UserName;
        user.UserPrincipalName = UserName + "@some.domain";
        user.GivenName = FirstName;
        if (this.mName != "") { user.Initials = MiddleName; }
        user.Surname = LastName;
        user.DisplayName = this.CommonName;
        user.EmailAddress = UserName + "@mydomain.com";
        user.SetPassword(this.Pass);
        user.Department = "Rocking IT Department";
        user.Company = "My Fake Company";
        user.PhysicalDeliveryOfficeName = officeLocation;
        user.ExpirePasswordNow();
        user.Enabled = true;
        user.PasswordNotRequired = false;
        user.Save();
    }
}

So creating an account is pretty simple too.  Using a PrincipalContext attached to the DC that you want to create the object on, you create a new UserPrincipal passing in the values for the context, the name as it’ll appear in AD (First Last or Last, First — however your procedures require it)  the temporary password and true to say it’s enabled (although we do set that below).  The rest are fairly standard properties that you may be setting in your schema.  Once you’ve set all of your properties save the object and you have a new Active Directory user.

Tags: Active Directory, C#

Monday, August 22nd, 2011 C#, Code No Comments

Querying AD from C# using DirectoryServices.AccountManagement

I ran across a need  to query AD and make bulk changes to a subset of AD user accounts.  When creating an account in Active Directory using a UserPrincipal object you must specify certain properties on the account.  The ones I was interested in are as follows:

PasswordNotRequired
UserCannotChangePassword
PasswordNeverExpires

During my initial creation, I forgot to set PasswordNotRequired to false and needed to go back and set this on a group of accounts.  My initial attempt had a problem…it only returns the first 1000 results:

using (var context = new PrincipalContext(ContextType.Domain, FQDC))
{
     UserPrincipal up = new UserPrincipal(context);

     up.EmployeeId = "*";
     up.Enabled = true;

     PrincipalSearcher ps = new PrincipalSearcher();
     ps.QueryFilter = up;

     PrincipalSearchResult<Principal> results = ps.FindAll();

     if (results != null) ...

Here we setup a PrincipalContext and create a new UserPrincipal with it. We then set the search criteria (some value entered in the EmployeeID field and an Enabled account).  After creating a PrincipalSearcher we set a QueryFilter and then return the results.  Again, this works great but it only returns 1000 results.  As I was expecting closer to 15000, this was a slight problem. 😉

So, how do we return all of the results?  The solution is actually quite simple and I’ll highlight the one-line code change below.

...
PrincipalSearcher ps = new PrincipalSearcher(up);
...

When creating the PrincipalSearcher, we need to pass in the UserPrincipal object to get the desired result.  According to MSDN, the QueryFilter must be set (we set it in the example above) before passing it into the PS object.  Also, you can go the long route and set the PageSize in the underlying DirectorySearchwe object, but I find this way to be much easier.

One other side note. Don’t forget how it easy it is to “parallelise” your operations.

if (results != null)
{
     int count = 0;
     Parallel.ForEach (results, s =>
     {
           code to do stuff....
      });
}

.Net makes it very easy to make your operations parallel.

Tags: Active Directory, C#

Sunday, August 21st, 2011 C#, Code 1 Comment

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

WordPress SEO fine-tune by Meta SEO Pack from Poradnik Webmastera