понедельник, 14 декабря 2009 г.

Using System.DirectoryServices.AccountManagement


In this article, we will be focusing on creating, editing, and deleting both user accounts or groups on Active Directory or Machine SAM by using theSystem.DirectoryServices.AccountManagement namespace that .NET Framework 3.5 includes. We were able to develop these functionalities by using the Invoke method of the DirectoryEntry object which is returned by the DirectorySearcher component in .NET Framework 2.0, but this new namespace works faster and is easy to develop. It also is in a more object oriented structure.
Before starting, let's just have a sneak peek at the objects we will be using during this article.
PrincipalContextPrincipalContext is the object that provides directory services such as AD or Machine SAM. In other words, it holds the connection to a directory.
PrincipalPrincipal is the base class of principal objects that we will be describing below. It includes common methods such as Save, Delete.
GroupPrincipalAs can be understood from the name, the GroupPrincipal object provides functionality for Group objects at directory level and is derived from thePrincipal object.
AuthenticablePricipalThis class is also derived from the Principal class, and besides that, it includes methods for authentication mechanisms.
UserPricipalUserPrincipal is the object that represents users on both the Active Directory or the Local SAM, it provides functionality for user items.

Using the code

I believe that the best learning method in programming is writing code. So, let's start writing our code. Instead of pasting all the code here, I will give some examples of critical points, and try to explain the idea of working with these classes.
For further information, you can download the source from the link above. Here are some functionalities this program includes.
  • Groups: Listing, Filtering, Creating, Editing, Deleting, Viewing users of a group.
  • Users: Listing, Filtering, Creating, Editing, Deleting, Changing password, Viewing user groups, Adding user to a group, Removing user from a group.
Let's start with creating an instance of a PrincipalContext object.
PrincipalContext insPrincipalContext =    new PrincipalContext(ContextType.Machine);//Connecting to local computer. PrincipalContext insPrincipalContext = new PrincipalContext(ContextType.Domain, "MyDomain",                                         "DC=MyDomain,DC=com");                                        //Connecting to Active Directory PrincipalContext insPrincipalContext = new PrincipalContext(ContextType.Machine,"TAMERO",                                         "administrator","password");                                        //Connecting to local computer                                         //with credentials of an user
As you see, there is no difference between connecting to a Machine SAM and Active Directory. I will continue with my article giving examples from Machine SAM, but as I said, there is no difference. Also, with this object, you can validate a user's credentials. I will provide an example of using this method at the end of the article.
Now, let's look at how to list or filter users or groups.
private void SearchGroups(GroupPrincipal parGroupPrincipal) {     lbGroups.Items.Clear();     PrincipalSearcher insPrincipalSearcher = new PrincipalSearcher();     insPrincipalSearcher.QueryFilter = parGroupPrincipal;     PrincipalSearchResult results = insPrincipalSearcher.FindAll();     foreach (Principal p in results)     {         lbGroups.Items.Add(p);     } } private void SearchUsers(UserPrincipal parUserPrincipal) {     lbUsers.Items.Clear();     PrincipalSearcher insPrincipalSearcher = new PrincipalSearcher();     insPrincipalSearcher.QueryFilter = parUserPrincipal;     PrincipalSearchResult results = insPrincipalSearcher.FindAll();     foreach (Principal p in results)     {         lbUsers.Items.Add(p);     } } private void ListGroups() {     GroupPrincipal insGroupPrincipal = new GroupPrincipal(insPrincipalContext);     insGroupPrincipal.Name = "*";     SearchGroups(insGroupPrincipal); } private void ListUsers() {     UserPrincipal insUserPrincipal = new UserPrincipal(insPrincipalContext);     insUserPrincipal.Name = "*";     SearchUsers(insUserPrincipal); }
Now, let's look at the logic behind listing and filtering users or groups. You can easily see that both the SearchGroups and SearchUsers methods are similar. The most important point is using GroupPrincipal for Group, and UserPrincipal for User functions. And, principal searcher is the common class that provides the search functionality. After assigning an object (GroupPrincipal or UserPrincipal) that contains filters to the QueryFilter property of this object, the FindAll method returns all the records, and the FindOnemethod returns the first record. And, another point is how to set search criteria, for example, for a property that contains a "b" character, you can assign "*b*" to that property, or for a property that starts with a "b" character, you can assign "b*" to that property. I will also tell how to set filters that depend on comparison (e.g., PasswordExpirationDate is in the next 5 days) at the end of this article.
Now, let's look at the code that creates a new user:
UserPrincipal insUserPrincipal = new UserPrincipal(insPrincipalContext);  //method that assign properties to insUserPrincipal object insUserPrincipal.Save(); insUserPrincipal.Dispose(); MessageBox.Show("User created."); GroupPrincipal insGroupPrincipal = new GroupPrincipal(insPrincipalContext);  //method that assign properties to insGroupPrincipal object insGroupPrincipal.Save(); insGroupPrincipal.Dispose(); MessageBox.Show("Group created.");
It is very easy to create an entry. As you can see, after creating a principal object (User or Group), invoking its Save method saves the record. Editing and deleting works the same. Instead of creating a Principal object, if you get a Principal object reference, then change the properties and invoke the Save method, and your object is updated. For deleting an entry, the only thing you should do is call the Delete method of the Principal object that references to the entry.
And now, let's talk about changing the password of a user:
UserPrincipal insUserPrincipal = (UserPrincipal)lbUsers.SelectedItem; insUserPrincipal.SetPassword("12345678"); MessageBox.Show("Password changed.");
You can get the members of a group from the Members property of the GroupPrincipal object. You can use this property as an enumeration. To add a user to a group, you should add the UserPrincipal object that holds the reference of a user to this enumeration. And the same logic for removing a user from a group: you must remove that user from the enumeration. But, do not forget to execute the Save method of GroupPrincipal after making changes. You can list the user groups by executing the method GetGroups() of theUserPrincipal object. Here are some examples:
//Listing groups members GroupPrincipal insGroupPrincipal = (GroupPrincipal)lbGroups.SelectedItem; List insListPrincipal = new List(); foreach (Principal p in insGroupPrincipal.Members) {     insListPrincipal.Add(p); }  //Listing users groups UserPrincipal insUserPrincipal = (UserPrincipal)lbUsers.SelectedItem; List insListPrincipal = new List(); foreach (Principal p in insUserPrincipal.GetGroups()) {     insListPrincipal.Add(p); }  //Adding user to a group UserPrincipal insUserPrincipal = (UserPrincipal)lbUsers.SelectedItem; GroupPrincipal groupPrincipal =    GroupPrincipal.FindByIdentity(insPrincipalContext, group.GroupName); if (groupPrincipal.Members.Contains(insPrincipalContext,      IdentityType.SamAccountName, insUserPrincipal.SamAccountName)) {     MessageBox.Show(insUserPrincipal.Name +        " is already a member of group " + group.GroupName);     return; } groupPrincipal.Members.Add(insUserPrincipal); groupPrincipal.Save();  //Removing user from a group UserPrincipal insUserPrincipal = (UserPrincipal)lbUsers.SelectedItem; GroupPrincipal groupPrincipal =    GroupPrincipal.FindByIdentity(insPrincipalContext, group.GroupName); groupPrincipal.Members.Remove(insUserPrincipal); groupPrincipal.Save();
And, here is the code for validating user credentials and filtering comparison values:
insPrincipalContext.ValidateCredentials("Tamer", "12345678"); parUserPrincipal.AdvancedSearchFilter.AccountExpirationDate(                  DateTime.Now.Date.AddDays(10), MatchType.Equals); parUserPrincipal.AdvancedSearchFilter.BadLogonCount(5, MatchType/span>.GreaterThanOrEquals);

Комментариев нет: