Programming/Dot.NET

ActiveDirectory System.DirectoryServices....

bcheul 2008. 11. 3. 16:07

Creating Groups

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/creating_groups.asp
When you create a new group, you can use flags from the ADS_GROUP_TYPE_ENUM enumeration to assign a group type to the group, such as global (ADS_GROUP_TYPE_GLOBAL_GROUP), domain local (ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP), local (ADS_GROUP_TYPE_LOCAL_GROUP), universal (ADS_GROUP_TYPE_UNIVERSAL_GROUP) or security enabled (ADS_GROUP_TYPE_SECURITY_ENABLED). If you do not specify a group type, the default is to create a global, secured group (ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_GLOBAL_GROUP | ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_SECURITY_ENABLED).

The following code example shows how to create a new group, called Practice Managers to the organizational unit, called Consulting.

DirectoryEntry dom = new DirectoryEntry();    // Bind to the domain that this user is currently connected to. 
DirectoryEntry ou = dom.Children.Find("OU=Consulting");  // Find the container (in this case, the Consulting organizational unit) that you wish to add the new group to. 
DirectoryEntry group = ou.Children.Add("CN=Practice Managers","group"); // Add the new group Practice Managers.
group.CommitChanges();// Commit the new group to the directory. 

The following code example shows how to create a local domain group called Managers to the Consulting organizational unit. Use COM Interop to specify the ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP flag.

DirectoryEntry dom = new DirectoryEntry();
DirectoryEntry ou = dom.Children.Find("OU=Consulting");
DirectoryEntry mgr = ou.Children.Add("CN=Managers","group"); 
            // Set the group type to a secured domain local group. 
mgr.Properties["groupType"].Value = ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP |  
                                                       ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_SECURITY_ENABLED;  
mgr.CommitChanges();

The following code example shows how create a non-security group, which is a distribution list called Full Time Employees to the Consulting organizational unit. Use COM Interop to specify the ADS_GROUP_TYPE_GLOBAL_GROUP flag.

DirectoryEntry dom = new DirectoryEntry(); 
DirectoryEntry ou = dom.Children.Find("OU=Consulting"); 
DirectoryEntry dl = ou.Children.Add("CN=Full Time Employees","group");             // Add the Full Time Employees distribution list. 
dl.Properties["groupType"].Value = ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_GLOBAL_GROUP;     // Set the group type to global.
dl.CommitChanges();

The following code example shows how to add an entire group to another group.

DirectoryEntry dom = new DirectoryEntry();  
DirectoryEntry group = dom.Children.Find("CN=North America");     // Find the container (in this case, the North America group) that you wish to add.
DirectoryEntry mgr = new DirectoryEntry("LDAP://CN=Managers,OU=Consulting,DC=Fabrikam,DC=COM");     // Connect to the group that you wish to add "group" to. 
mgr.Properties["member"].Add(group.Properties["distinguishedName"].Value);     // Add the distinguishedName of "group" to the members property of "mgr". 
mgr.CommitChanges();

Adding Users to a Group

When a group is created, users must be added to the group. The following code example shows how to add a user, new user, to the consulting organization.

DirectoryEntry dom = new DirectoryEntry(); 
DirectoryEntry group = dom.Children.Find("CN=Consulting");
DirectoryEntry usr = group.Children.Find("CN=New User");      // Add a single user to a group; 
    // To add multiple users to a group use group.Properties["member"].AddRange(new string[] {"userDN1","userDN2"}); 
group.Properties["member"].Add(usr.Properties["distinguishedName"].Value);     //To add the user's distinguished name to the member property on the group object
group.CommitChanges();

Dim dom As New DirectoryEntry() 
Dim group As DirectoryEntry = dom.Children.Find("CN=Consulting")
Dim usr As DirectoryEntry = group.Children.Find("CN=New User")          ' Add a single user to a group; 
        ' To add multiple users to a group use 'group.Properties("member").AddRange(New String() {"userDN1", "userDN2"}) 
group.Properties("member").Add(usr.Properties("distinguishedName").Value) 
group.CommitChanges()

Removing Users from a Group

The following code example shows how to remove users from a group. For this task, find the user to be removed, which in the example is User Name, then call the Remove method.

DirectoryEntry dom = new DirectoryEntry(); 
DirectoryEntry ou = dom.Children.Find("OU=Consulting"); 
DirectoryEntry usr = ou.Children.Find("CN=User Name"); 
String userDN = usr.Properties["distinguishedName"].Value.ToString(); 
group.Properties["member"].Remove(userDN); 
group.CommitChanges();

DirectoryEntries.Remove Method

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDirectoryServicesDirectoryEntriesClassRemoveTopic.asp?frame=true
The entry must be an empty container or a noncontainer. To delete an entry and all its children, use the DeleteTree method from DirectoryEntry

The following example creates a new DirectoryEntry with the specified path, then creates a new entry in the container and saves it. Finally, it retrieves the newly created entry and deletes it.

Imports System
Imports System.DirectoryServices

Class MyClass1
   Shared Sub Main()
      Try
         Dim strPath As String = "IIS://localhost/W3SVC/1/Root"
         Dim strName As String = ""

         ' Create a new 'DirectoryEntry' with the given path.
         Dim myDE As New DirectoryEntry(strPath)
         Dim myEntries As DirectoryEntries = myDE.Children

         ' Create a new entry 'Sample' in the container.
         Dim myDirectoryEntry As DirectoryEntry = myEntries.Add("Sample", myDE.SchemaClassName)
         ' Save changes of entry in the 'Active Directory'.
         myDirectoryEntry.CommitChanges()
         Console.WriteLine(myDirectoryEntry.Name + " entry is created in container.")

         ' Find 'Sample' entry in container.
         myDirectoryEntry = myEntries.Find("Sample", myDE.SchemaClassName)
         Console.WriteLine(myDirectoryEntry.Name + " found in container.")
         ' Remove 'Sample' entry from container.
         strName = myDirectoryEntry.Name
         myEntries.Remove(myDirectoryEntry)
         Console.WriteLine(strName + " entry is removed from container.")

      Catch e As Exception
         Console.WriteLine("The following exception was raised : {0}", e.Message.ToString())
      End Try
   End Sub 'Main
End Class 'MyClass1
using System;
using System.DirectoryServices; 

class MyClass1
{
   static void Main()
   {
      try
      {
         String strPath = "IIS://localhost/W3SVC/1/Root";
         String strName = "";

         // Create a new 'DirectoryEntry' with the given path.
         DirectoryEntry myDE = new DirectoryEntry(strPath);
         DirectoryEntries myEntries = myDE.Children;

         // Create a new entry 'Sample' in the container.
         DirectoryEntry myDirectoryEntry = 
            myEntries.Add("Sample", myDE.SchemaClassName);
         // Save changes of entry in the 'Active Directory'.
         myDirectoryEntry.CommitChanges();
         Console.WriteLine (myDirectoryEntry.Name + 
            " entry is created in container.");

         // Find 'Sample' entry in container.
         myDirectoryEntry = myEntries.Find("Sample", myDE.SchemaClassName);
         Console.WriteLine(myDirectoryEntry.Name + " found in container.");
         // Remove 'Sample' entry from container.
         strName = myDirectoryEntry.Name;
         myEntries.Remove(myDirectoryEntry);
         Console.WriteLine(strName+ " entry is removed from container.");

      }
      catch(Exception e)
      {
         Console.WriteLine("The following exception was raised : {0}",
            e.Message);
      }
   }
}

[C++] 
#using
#using
#using

using namespace System;
using namespace System::DirectoryServices; 

int main() {
    try {
        String* strPath = S"IIS://localhost/W3SVC/1/Root";
        String* strName = S"";

        // Create a new 'DirectoryEntry' with the given path.
        DirectoryEntry* myDE = new DirectoryEntry(strPath);
        DirectoryEntries* myEntries = myDE->Children;

        // Create a new entry 'Sample' in the container.
        DirectoryEntry* myDirectoryEntry =  myEntries->Add(S"Sample", myDE->SchemaClassName);
        // Save changes of entry in the 'Active Directory'.
        myDirectoryEntry->CommitChanges();
        Console::WriteLine(S"{0} entry is created in container.", myDirectoryEntry->Name);

        // Find 'Sample' entry in container.
        myDirectoryEntry = myEntries->Find(S"Sample", myDE->SchemaClassName);
        Console::WriteLine(S"{0} found in container.", myDirectoryEntry->Name);
        // Remove 'Sample' entry from container.
        strName = myDirectoryEntry->Name;
        myEntries->Remove(myDirectoryEntry);
        Console::WriteLine(S"{0} entry is removed from container.", strName);
    } catch(Exception* e) {
        Console::WriteLine(S"The following exception was raised : {0}", e->Message);
    }
}

Enumerating Users in a Group

This topic includes code examples for enumerating the members of a group. If the group has many members, you can get a result set by calling IADsGroup::Members.

The following code example shows how to get members using the SearchResult property Properties.

DirectoryEntry group = new DirectoryEntry("LDAP://CN=Sales,DC=Fabrikam,DC=COM");
foreach(object dn in group.Properties["member"] ) { Console.WriteLine(dn); }

The following code example shows how to get members using the Invoke method to call the ADSI IADsGroup::Members method.

DirectoryEntry group = new DirectoryEntry("LDAP://CN=Sales,DC=Fabrikam,DC=COM");
object members = group.Invoke("Members",null);
foreach( object member in (IEnumerable) members) { DirectoryEntry x = new DirectoryEntry(member); Console.WriteLine(x.Name); }

Enumerating Members in a Large Group

This topic explains how range retrieval works and provides several code examples for using range retrieval to obtain the members of a group. The group object contains a property called member which contains multiple values in an array. Because group memberships can sometimes be quite large, this property may contain hundreds of values. Range retrieval is a process of obtaining a portion of the members at a time. For Windows Server 2003 family, the maximum number of values that can be retrieved from the server at one time is 1500. If you set the range retrieval to a value that is higher than the number of values in the set, the search fails. If you set the range to a small number, then you can degrade the performance of the search because it must return to the server for new results more often. For more information about range retrieval, see Enumerating Groups That Contain Many Members.

The following code example shows how to get members of a group using range retrieval. This sample retrieves entries 0-500, inclusively. The maximum entries for this result set are 5001.

DirectoryEntry group = new DirectoryEntry("LDAP://CN=Sales,DC=Fabrikam,DC=COM");
DirectorySearcher groupMember = new DirectorySearcher
    (group,"(objectClass=*)",new string[]{"member;Range=0-500"},SearchScope.Base);
SearchResult result = groupMember.FindOne();
// Each entry contains a property name and the path (ADsPath).
// The following code returns the property name from the PropertyCollection.
String propName=String.Empty;
foreach(string s in result.Properties.PropertyNames)
{
    if ( s.ToLower() != "adspath")  { propName = s; break; }
}
foreach(string member in result.Properties[propName]) { Console.WriteLine(member);}

You can also use range retrieval to retrieve a portion of the result set by starting and ending at a specified point within the result set. To do this, modify the {"member;Range=0-500"} statement. For example, to retrieve the third and fourth entries in the result set, you would use the statement {"member;Range=2-3"}. To retrieve all entries, starting with 502 to the end of the result set, you would use the statement {"member;Range=501-*"}.

The final code example shows how to use range retrieval to get all the members of the group when you do not know how many members are in the group. Because range retrieval does not work if you try to get more members than are in the result set, this code example tests for a failure and when it receives it, it changes the range statement to ("member;range={0}-*", rangeLow) to enumerate the final members in the set.

try
{
    DirectoryEntry entry = new DirectoryEntry("LDAP://CN=My Distribution List,OU=Distribution Lists,DC=Fabrikam,DC=com");
    DirectorySearcher searcher = new DirectorySearcher(entry);
    searcher.Filter = "(objectClass=*)";

    uint rangeStep = 1000;
    uint rangeLow = 0;
    uint rangeHigh = rangeLow + (rangeStep - 1);
    bool lastQuery = false;
    bool quitLoop = false;

    do
    {
        string attributeWithRange;
        if(!lastQuery)   {    attributeWithRange = String.Format("member;range={0}-{1}", rangeLow, rangeHigh);     }
        else  {  attributeWithRange = String.Format("member;range={0}-*", rangeLow);     }          
        searcher.PropertiesToLoad.Clear();
        searcher.PropertiesToLoad.Add(attributeWithRange);
        SearchResult results = searcher.FindOne();
        foreach(string res in results.Properties.PropertyNames)
        {
            System.Diagnostics.Debug.WriteLine(res.ToString());
        }
        if(results.Properties.Contains(attributeWithRange))
        {
            foreach(object obj in results.Properties[attributeWithRange])
            {
                Console.WriteLine(obj.GetType());
                if(obj.GetType().Equals(typeof(System.String)))
                {
                }
                else if (obj.GetType().Equals(typeof(System.Int32)))
                {
                }
                Console.WriteLine(obj.ToString());
            }
            if(lastQuery)     {     quitLoop = true;        }
        }
        else  {  lastQuery = true;  }
        if(!lastQuery)    {  rangeLow = rangeHigh + 1; rangeHigh = rangeLow + (rangeStep - 1);   }
    }
    while(!quitLoop);
}
catch(Exception ex) {    // Handle exception ex.}

Searching for Groups

This topic shows how to search for groups using DirectorySearcher.

The following code example shows how to search for all groups on a domain.

using System.DirectoryServices;
...
DirectorySearcher src = new DirectorySearcher(ou,"(objectCategory=group)");
foreach(SearchResult res in src.FindAll()) { Console.WriteLine(res.Path); }

The following code example shows how to search for all security enabled groups. For this search, use COM Interop. It uses a bitwise search.

using System.DirectoryServices;
...
DirectorySearcher src = new DirectorySearcher(ou,"(objectCategory=group)");
int val = (int) ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_SECURITY_ENABLED;
string query = "(&(objectCategory=group)(groupType:1.2.840.113556.1.4.804:=" + val.ToString() + "))";
src.Filter = query;
foreach(SearchResult res in src.FindAll()) { Console.WriteLine(res.Path); }

The following code example shows how to search for all global domain groups, regardless of whether they are secure or non-secure. For this search, use COM Interop.

using System.DirectoryServices;
...
DirectorySearcher src = new DirectorySearcher(ou,"(objectCategory=group)");
int val = (int) ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_GLOBAL_GROUP;
string query = "(&(objectCategory=group)(groupType:1.2.840.113556.1.4.804:=" + val.ToString() + "))";
src.Filter = query;
foreach(SearchResult res in src.FindAll()) { Console.WriteLine(res.Path); }

The following code example shows how to search for all global domain, secure groups. For this search, use COM Interop.

using System.DirectoryServices;
DirectorySearcher src = new DirectorySearcher(ou,"(objectCategory=group)");
int val = (int) (ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_GLOBAL_GROUP | ActiveDs.ADS_GROUP_TYPE_ENUM.ADS_GROUP_TYPE_SECURITY_ENABLED);
string query = "(&(objectCategory=group)(groupType=" + val.ToString() + "))";
src.Filter = query;
foreach(SearchResult res in src.FindAll()) { Console.WriteLine(res.Path); }

Deleting Groups

The following code example shows how to delete a group using the DirectoryEntries method called Remove. For this task, find the group to delete, which, in the example, is Consulting, then run the Remove method.

'Bind to the current domain. 
Dim dom As New DirectoryEntry()
'Use the Find method to find the Consulting OU
Dim ou As DirectoryEntry = dom.Children.Find("OU=Consulting")
'To delete a group, bind to the group within the OU
Dim group As New DirectoryEntry(ou + "CN=groupname")
'To delete a manager, bind to the manager object within the OU
Dim mgr As New DirectoryEntry(ou + "CN=mgrname")
'To delete a distribution list, bind to the distribution list object
'within the OU
Dim dl As New DirectoryEntry(ou + "CN=dlname")
'Use the remove method to remove each of these objects.
ou.Children.Remove(group)
ou.Children.Remove(mgr)
ou.Children.Remove(dl)

User Management

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/creating_groups.asp
When you setup a user object, set several user properties on the object at the same time. For example, there are several flags in the userAccountControl property that are used to control the user password behavior, account lockout, account enable and disable, the home directory, and the type of account that the user has. Several code examples in this section show how to set flags for the userAccountControl. There are also some samples for setting the properties displayed in the System Administrator property pages for each user.

For more information about properties that can be set on the user object during creation, see Creating a User.

The following topics are provided in this section:

The following code example shows how to create a user in an organizational unit. By default, this account will be disabled. To enable the account, set a password for it. For more information, see Managing User Passwords.

Creating Users

DirectoryEntry ent = new DirectoryEntry();
DirectoryEntry ou = ent.Children.Find("OU=Consulting");

// Use the Add method to add a user in an organizational unit.
DirectoryEntry usr = ou.Children.Add("CN=New User","user");
// Set the samAccountName, then commit changes to the directory.
usr.Properties["samAccountName"].Value = "newuser"; 
usr.CommitChanges();

The samAccountName property is set in this code example. The samAccountName creates a unique samAccountName, such as $CP2000-O16B1V0UKHK7. This property is required on the user account when the domain controller is running on a Windows NT 4.0 server. In Windows Server 2003, the samAccountName property is optional.

This topic provides code examples for enabling and disabling a user account. It uses the Properties method to access the userAccountControl property to set the ADS_UF_ACCOUNTDISABLE flag which is defined in the ADS_USER_FLAG_ENUM.

Enabling and Disabling the User Account

The following code example shows how to enable a user account.

DirectoryEntry usr = new DirectoryEntry("LDAP://CN=New User,CN=users,DC=fabrikam,DC=com");
int val = (int) usr.Properties["userAccountControl"].Value;
usr.Properties["userAccountControl"].Value = val & ~ADS_UF_ACCOUNTDISABLE;
usr.CommitChanges();

The following code example shows how to disable a user account.

DirectoryEntry usr = new DirectoryEntry("LDAP://CN=Old User,CN=users,DC=fabrikam,DC=com");
int val = (int) usr.Properties["userAccountControl"].Value;
usr.Properties["userAccountControl"].Value = val | ADS_UF_ACCOUNTDISABLE;
usr.CommitChanges();

Setting a User Account Expiration

This code example shows how to set the expiration on a user account. This operation uses the InvokeMember method to access the IADsUser property AccountExpirationDate.

using System.Reflection;
... 
Type type = usr.NativeObject.GetType();
Object adsNative = usr.NativeObject;
type.InvokeMember("AccountExpirationDate", BindingFlags.SetProperty, null, 
adsNative, new object[]{"12/29/2004"});
usr.CommitChanges();

Managing User Passwords

The following code example shows how to set the user password by invoking the IADsUser::SetPassword method.

usr.Invoke("SetPassword", new object[]{"secret"});

The following code example shows how to change the user password by invoking the IADsUser::ChangePassword method.

usr.Invoke("ChangePassword",new object[]{"oldpass","newpass"});

The following code example shows how to set the user password so that it must be changed at the next logon. It sets the pwdLastSet property to off (-1).

usr.Properties["pwdLastSet"].Value = -1; // To turn on, set this value to 0.
usr.CommitChanges();

The following code example shows a function that sets an ACE to deny a password change. It uses COM Interop to access the IADsSecurityDescriptor to get the ntSecurityDescriptor property. It then uses the IADsAccessControlList to get the DACL from the security descriptor and IADsAccessControlEntry to get the AceType, AceFlags, Trustee, Flags, ObjectType and AccessMask properties. The AceType flags are defined in ADS_ACETYPE_ENUM. The AceFlags are defined in the ADS_FLAGTYPE_ENUM. AccessMask flags are defined in the ADS_RIGHTS_ENUM.

Imports System
Imports System.DirectoryServices
Imports ActiveDs
...
Shared Sub DenyChangePassword(User As DirectoryEntry)
      Const PASSWORD_GUID As String = "{ab721a53-1e2f-11d0-9819-00aa0040529b}"
      Const ADS_UF_ACCOUNTDISABLE As Integer = 2
      Const ADS_UF_PASSWORD_EXPIRED As Integer = &H800000
      Const ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION As Integer = &H1000000
      
      
      Dim trustees() As String = {"NT AUTHORITY\SELF", "EVERYONE"}
      
      Dim sd As ActiveDs.IADsSecurityDescriptor = CType(User.Properties("ntSecurityDescriptor").Value, 
          ActiveDs.IADsSecurityDescriptor)
      Dim acl As ActiveDs.IADsAccessControlList = CType(sd.DiscretionaryAcl, 
          ActiveDs.IADsAccessControlList)
      Dim ace As New ActiveDs.AccessControlEntry()
      
      Dim trustee As String
      For Each trustee In  trustees
         ace.Trustee = trustee
         ace.AceFlags = 0
         ace.AceType = Fix(ActiveDs.ADS_ACETYPE_ENUM.ADS_ACETYPE_ACCESS_DENIED_OBJECT)
         ace.Flags = Fix(ActiveDs.ADS_FLAGTYPE_ENUM.ADS_FLAG_OBJECT_TYPE_PRESENT)
         ace.ObjectType = PASSWORD_GUID
         ace.AccessMask = Fix(ActiveDs.ADS_RIGHTS_ENUM.ADS_RIGHT_DS_CONTROL_ACCESS)
         acl.AddAce(ace)
      Next trustee
      sd.DiscretionaryAcl = acl
      User.Properties("ntSecurityDescriptor").Value = sd
      User.CommitChanges()
   End Sub 'DenyChangePassword
using System;
using System.DirectoryServices;
using ActiveDs;
...
static void DenyChangePassword(DirectoryEntry User)
{
     const string PASSWORD_GUID = "{ab721a53-1e2f-11d0-9819-00aa0040529b}";
     const int ADS_UF_ACCOUNTDISABLE=2;
     const int ADS_UF_PASSWORD_EXPIRED=0x800000;
     const int ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION=0x1000000;
								
     string[] trustees = new string[]{@"NT AUTHORITY\SELF","EVERYONE"};
				
     ActiveDs.IADsSecurityDescriptor sd = (ActiveDs.IADsSecurityDescriptor)
        User.Properties["ntSecurityDescriptor"].Value;
     ActiveDs.IADsAccessControlList acl = (ActiveDs.IADsAccessControlList) sd.DiscretionaryAcl;
     ActiveDs.IADsAccessControlEntry ace = new ActiveDs.AccessControlEntry();	

     foreach(string trustee in trustees)
     {
          ace.Trustee = trustee;
          ace.AceFlags = 0;
          ace.AceType = (int)ActiveDs.ADS_ACETYPE_ENUM.ADS_ACETYPE_ACCESS_DENIED_OBJECT;
	          ace.Flags = (int)ActiveDs.ADS_FLAGTYPE_ENUM.ADS_FLAG_OBJECT_TYPE_PRESENT;
          ace.ObjectType = PASSWORD_GUID;
          ace.AccessMask = (int)ActiveDs.ADS_RIGHTS_ENUM.ADS_RIGHT_DS_CONTROL_ACCESS;
          acl.AddAce(ace);
     }
     sd.DiscretionaryAcl = acl;
     User.Properties["ntSecurityDescriptor"].Value = sd;
     User.CommitChanges();
}

The following code example shows how to set the password to never expire. It uses the Properties method to access the userAccountControl property to set the ADS_UF_DONT_EXPIRE_PASSWD flag defined in the ADS_USER_FLAG_ENUM.

 Shared Sub DontExpirePassword(User As DirectoryEntry)
 Dim val As Integer
 Const ADS_UF_DONT_EXPIRE_PASSWD As Integer = &H10000
 val = Fix(User.Properties("userAccountControl").Value)
 User.Properties("userAccountControl").Value = val Or ADS_UF_DONT_EXPIRE_PASSWD
 User.CommitChanges()
 End Sub 'DontExpirePassword
using System;
using System.DirectoryServices;
using ActiveDs;
...
static void DontExpirePassword(DirectoryEntry User)
{
     int val;
     const int ADS_UF_DONT_EXPIRE_PASSWD =0x10000;
     val = (int) User.Properties["userAccountControl"].Value;
     User.Properties["userAccountControl"].Value = val | 
     ADS_UF_DONT_EXPIRE_PASSWD;
     User.CommitChanges();
}

Setting User Account Flags

This topic contains code examples that set various user flags. It uses the Properties method to access the userAccountControl property to set flags defined in the ADS_USER_FLAG_ENUM.

The following code example shows how to require that a SmartCard be used for an interactive logon.

val= (int) usr.Properties["userAccountControl"].Value;
usr.Properties["userAccountControl"].Value = val | 
ADS_UF_SMARTCARD_REQUIRED;
usr.CommitChanges();

The following code example shows how to set the account to use a DES encryption type.

const int ADS_UF_USE_DES_KEY_ONLY=0x200000;
val= (int) usr.Properties["userAccountControl"].Value;
usr.Properties["userAccountControl"].Value = val | ADS_UF_USE_DES_KEY_ONLY;
usr.CommitChanges();

The following code example shows how to set the account so that it is trusted for delegation.

const int ADS_UF_TRUSTED_FOR_DELEGATION =0x80000;
val= (int) usr.Properties["userAccountControl"].Value;
usr.Properties["userAccountControl"].Value = val | 
ADS_UF_TRUSTED_FOR_DELEGATION;
usr.CommitChanges();

The following code example shows how to show that the account is sensitive and cannot be used for delegation.

const int ADS_UF_NOT_DELEGATED=0x100000;
val= (int) usr.Properties["userAccountControl"].Value;
usr.Properties["userAccountControl"].Value = val | ADS_UF_NOT_DELEGATED;
usr.CommitChanges();

The following code example shows how to set the account so that it does not require Kerberos pre-authentication.

const int ADS_UF_DONT_REQUIRE_PREAUTH=0x400000;
val= (int) usr.Properties["userAccountControl"].Value;
usr.Properties["userAccountControl"].Value = val | 
ADS_UF_DONT_REQUIRE_PREAUTH;
usr.CommitChanges();

Setting Properties Displayed on Property Pages

This topic provides code examples for setting the properties that appear in the property pages for users, which is accessed through the Active Directory Users and Computers MMC snap-in. If you have not used this snap-in before, you can open it on the server by selecting Start>All Programs>Administrative Tools>Active Directory Users and Computers. In the Users folder, right-click on a user name and select Properties. If you are setting up an application that allows a user to change information such as a home address, this is a useful piece of code to add to your application.

The following code example shows how to set common properties displayed in the General page.

usr.Properties["givenName"].Value = "New User";
usr.Properties["initials"].Value = "Ms";
usr.Properties["sn"].Value = "Name";
usr.Properties["displayName"].Value = "New User Name";
usr.Properties["description"].Value = "Vice President-Operation";
usr.Properties["physicalDeliveryOfficeName"].Value = "40/5802";
usr.Properties["telephoneNumber"].Value = "(425)222-9999";
usr.Properties["mail"].Value = "newuser@fabrikam.com";
usr.Properties["wWWHomePage"].Value = "http://www.fabrikam.com/newuser";
usr.Properties["otherTelephone"].AddRange(new 
string[]{"(425)111-2222","(206)222-5263"});
usr.Properties["url"].AddRange(new 
string[]{"http://newuser.fabrikam.com","http://www.fabrikam.com/officers"});
usr.CommitChanges();

The following code example shows how to set common properties displayed in the Address page.

usr.Properties["streetAddress"].Value = "2050 Fabrikam Way NE";
usr.Properties["postOfficeBox"].Value = "S/2523";
usr.Properties["l"].Value = "Sammamish";
usr.Properties["st"].Value = "Washington";
usr.Properties["postalCode"].Value = "98074";
usr.Properties["c"].Value = "US";
usr.CommitChanges();

The following code example shows how to set common properties displayed in the Account page.

usr.Properties["userPrincipalName"].Value = "newuser@fabrikam.com";
usr.Properties["sAMAccountName"].Value = "newuser";
usr.Properties["userWorkstations"].Value = "wrkst01,wrkst02,wrkst03";
usr.CommitChanges();

Enumerating User Memberships

This topic includes information and a code example that shows how to use a Windows form to enumerate user memberships

To create a Windows form to display user memberships

  1. Open Visual Studio .NET and select New Project.
  2. From Project Types, select Visual C# or Visual Basic and from Templates, select Windows Application.
  3. Name the new project and select OK.
  4. Select Project>Add Reference and select System.DirectoryServices from the list displayed on the .NET tab.
  5. On the form design page, drag a text box from the Toolbox to the form and format it. This is where the user will add a user name to bind to.
  6. Drag a label from the Toolbox to the form and modify the Text property to read "Enter Name:"
  7. Drag a button from the Toolbox to the form and modify the Text property to read "Find Groups".
  8. Drag a ListBox from the Toolbox to the form. This is where the results will be displayed.
  9. Double-click the form to go to the code page.
  10. Add the "using System.DirectoryServices;" statement to the end of the using statement list.
  11. Add the code example, that follows this procedure, to main.
  12. Compile and run the application.

The following code example shows how to use a Windows form to enumerate user memberships.

static void Main() 
{
    Application.Run(new Form1());
}
private void label1_Click(object sender, System.EventArgs e)
{
}
private void textBox1_TextChanged(object sender, System.EventArgs e)
{
}
private void button1_Click(object sender, System.EventArgs e)
{
    string strUserADsPath = "LDAP://fabrikam/cn=" +textBox1.Text +",cn=users,dc=fabrikam,dc=com";
    DirectoryEntry oUser;
    oUser = new DirectoryEntry(strUserADsPath);
    listBox1.Items.Add("Groups to which {0} belongs:"+ oUser.Name);
    // Invoke IADsUser::Groups method.
    object groups = oUser.Invoke("Groups");
    foreach ( object group in (IEnumerable)groups)   
    {
        // Get the Directory Entry.
        DirectoryEntry groupEntry  = new DirectoryEntry(group);
        listBox1.Items.Add(groupEntry.Name); 
    }
}
    private void Form1_Load(object sender, System.EventArgs e)
    {		
    }	
}

System.DirectoryServices Reference

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/creating_groups.asp
The System.DirectoryServices namespace provides easy access to Active Directory from managed code. The namespace contains two component classes, DirectoryEntry and DirectorySearcher, which use the Active Directory Services Interfaces (ADSI) technology. ADSI is the set of interfaces that Microsoft provides as a flexible tool for working with a variety of network providers. ADSI gives the administrator the ability to locate and manage resources on a network with relative ease, regardless of the network's size.

The classes in this namespace can be used with any of the Active Directory service providers. The current providers are: Internet Information Services (IIS), Lightweight Directory Access Protocol (LDAP), Novell NetWare Directory Service (NDS), and WinNT.

ADSI is a programmatic interface for Microsoft Active Directory that enables your applications to interact with diverse directories on a network, using a single interface. Using ADSI, you can create applications that can perform common tasks, such as backing up databases, accessing printers, and administering user accounts.

It is assumed that you have a general understanding of Active Directory before using these classes.

Active Directory is a tree structure. Each node in the tree contains a set of properties. Use this namespace to traverse, search, and modify the tree, and read and write to the properties of a node.

The DirectoryEntry class encapsulates a node or object in the Active Directory hierarchy. Use this class for binding to objects, reading properties, and updating attributes. Together with helper classes, DirectoryEntry provides support for life-cycle management and navigation methods, including creating, deleting, renaming, moving a child node, and enumerating children.

Use the DirectorySearcher class to perform queries against the Active Directory hierarchy. LDAP is the only system-supplied Active Directory Service Interfaces (ADSI) provider that supports searching.

A search of the Active Directory hierarchy through DirectorySearcher returns instances of SearchResult, which are contained in an instance of the SearchResultCollection class.