Programming in C#

Directory Services

Originally, Windows provide directory services access via the Activeds.tlb and Activeds.dll libraries. Now, with the .NET Framework, you can now use the DirectoryServices assemblies instead with additional features.

1. Using the UserPrincipal object.

This object provides a simple way of accessing, creating and updating User account within a directory such as Active Directory or other LDAP service. To use the new Directory Services properties and methods, you need ato add a reference to the System.DirectoryServices and System.DirectoryServices.AccountManagement assemblies.

a) Creating a User Principal object

You can create an object by creating a new instance of the UserPrincipal object with details of the user: context type, server name, container, and account enabled.

Container is a string with the path to an object or the parent container. Each item is comma seperated. So cn=Common Name (aka object name), DC=Domain Container, OU = Organisational Unit).
Also, you may optionally provide a user with permissions to the Domain to allow you to create, modify or remove objects, although to avoid having to provide them in clear text, you would either run it under a user with the appropiate privileges.
A UserPrincipal has a limited number of properites including GivenName, MiddleName, Surname, EmailAddress, EmployeeId, VoiceTelephoneNumber. These be set by using the object instance name and the property name.

UserPrincipal userObj;
PrincipalContext context;
string userid, passwd;

context = new PrincipalContext(ContextType.Domain ,"dc1","cn=Users,dc=mycompany,dc=com", "admin", "password");
userid = "JThompson";
passwd = "BlueTower";
userObj = new UserPrincipal(context, userid, passwd, true);

// Set some properties
userObj.Name = userid;
userObj.GivenName = "John";
userObj.Surname = "Thompson";
userObj.EmailAddress = "j.thompson@mycompany.com";
userObj.SetPassword("mypass876");
userObj.Save(); // Save changes to store in DS

b) Retreiving and updating a User Principal Object

Here, you can either specify the context of the user or just do a search in the domain for the object using a PrincipalSearcher. Here, the searcher uses a query based on a UserPrincipal with the specified values to search for.
You can use the function to FindAll() or just FindOne() to find the object(s) required and process the resulting object.

UserPrincipal userObj, queryObj;
PrincipalContext context;
PrincipalSearcher Psearch;
PrincipalSearchResult result;
string userid, passwd;

// Specify top of domain to search
context = new PrincipalContext(ContextType.Domain ,"dc1","dc=mycompany,dc=com", "admin", "password");
// Create an empty user principal for the query.
queryObj = new UserPrincipal();
queryObj.Name = "JThompson";
// Run the query in search and get results
PSearch = new PrincipalSearcher(queryObj);
PrincipalSearchResult<Principal> result = PSearch.FindAll();
for each (userObj in result)
{
  if (userObj.Name == queryObj.Name){
     break;
   }
}

// Update the userObj with new Email address
userObj.EmailAdress = "John.Thompson@mycompany.com";
userObj.Save();

c) Removing a User Principal Object

To remove a UserPrincipal, just need to use the Delete method.
e.g.
userObj.Delete();

d) Create a Group Principal

You can also create groups using the GroupPrincipal object, in the same way as UserPrincipal. You need to specify the context of where to create the object and create it.

UserPrincipal userObj;
GroupPrincipal groupObj;
PrincipalContext context;
string Name;

context = new PrincipalContext(ContextType.Domain ,"dc1","cn=Users,dc=mycompany,dc=com", "admin", "password");
Name = "Sales Group";
groupObj = new GroupPrincipal(context, Name);
groupObj.Description = "All sales people";
groupObj.DisplayName = "Sales Group";
groupObj.Members.Add(userObj);
groupObj.Save();

e) Using the DirectoryEntry type for users, groups, containers.

The only problem with using UserPrincipal and GroupPrincipal objects is that you are restricted on what properties you can set beyond what is allowed for those objects.For example, in Active Directory, you can have
many properties you can set which you cannot use in UserPrincipal object e.g. Title, JobTitle, RoomNumber, Company name, Department name, Exchange attributes etc. You will need to know the exact property names to set.
To get around this you can use the DirectoryEntry object to create any type of object and set any properties you require. Instead of Save(), use CommitChanges() to apply changes to the object.

DirectoryEntry userObj, contObj;
DirectoryEntries entries;
string userid, name;

// Set user information
userid = "MJones";
name = "Melissa Jones";
// Use distinguished address to get parent container
contObj = new DirectoryEntry("LDAP://cn=Users,dc=mycompany,dc=com")
// Get list of entries in the container
entries = contObj.Children;
// Add a new user to the list of entries
userObj = entries.Add("cn=" + userid, "User");
// Set user properties
userObj.Properties["name"].Value = userid;
userObj.Properties["displayName"].Value = name;
userObj.Properties["givenName"].Value = name.Split( ' ')[0];
userObj.Properties["sn"].Value = name.Split(' ')[1];
userObj.Password = "newPass345";
userObj.CommitChanges();