Just a little place for me

C#

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 alreadyseen.

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:

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.

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.

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:

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.