Managing Groups

High on the list of common administrative tasks is managing groups. A group is simply a list of related objects. Generally, a group contains a list of users, computers, or other groups. An example of a group is all the managers in an organization. Adding each manager's user object to the group provides centralized administration and easier communication with all the managers. The chairman of a company can then send e-mail to a single address, such as managers@coppersoftware.com, to reach all the managers at once. Network administrators can assign specific security privileges to a group that enables group members to perform specific tasks. For example, the manager's group might be given access to restricted shared folders or files.

Types of Groups

Active Directory represents a group as a single object of the group class. This object contains attributes describing group properties and group members. There are two types of groups: distribution and security.

A distribution group is used for e-mail distribution lists or other, nonsecurity related purposes. For example, the list of people to receive the company newsletter could be contained in a distribution group named Newsletter Readers. If you've worked with Microsoft Exchange Server 5.5 or earlier, you probably created distribution lists. A distribution group in Active Directory is the same in concept and is used by Microsoft Exchange 2000 Server for the same purpose.

A security group is used to apply a common set of access permissions to the members of the group. Security groups have the same benefits as distribution groups but also provide security information. The permissions assigned to the group are applied to the members of the group when they log on to the network.

Distribution and security groups in Active Directory have a scope that determines how security permissions are set. A group has one of three scopes: universal, global, or domain local. A universal group covers all the domains within a group. Users can be added from any domain, and the group's permissions apply to all the domains in the forest. A global group applies to the domain in which the group was created. Only users in the same domain can be added, but permissions apply to all the domains in the forest. The domain local scope is the opposite of the global scope. A domain local group can have members from anywhere in the forest, but permissions are applied only to the domain that the group was created in.

In most cases, global groups are sufficient. Changing the members in a universal group triggers replication between domains and global catalog servers. If a universal group is required, consider creating global groups in each domain and adding members for that domain. Then add each global group to the universal group. This will prevent unnecessary replication each time the global group changes membership. Domain local groups are best for assigning special permissions on a per-domain basis and for controlling access to nondirectory objects such as files and shared folders.


Real-World Advice

Andy Webb, cofounder of Simpler-Webb, Inc. is an experienced developer working with Active Directory and Microsoft Exchange Server. He confirms the potential replication issues with universal groups, saying: "The group membership is a single multivalued property on the group object. Whenever a member is added or removed, this property is updated and must be replicated to global catalog servers. It is possible to make a change to the group on more than one global catalog. For example, someone is added to a group in one domain. That change is reflected in the local global catalog quickly. However, if in another domain someone is removed from the same group, a replication conflict occurs because that domain doesn't have the change from the first domain yet. The first change is going to be lost in favor of the second change, which occurred later in time. With just two global catalogs it's unlikely that this would happen since replication will be pretty simple and quick. With a large, highly distributed set of global catalogs, the `window' of risk gets much bigger."

Because of the potential of replication conflicts and changes being lost, developers and administrators working with Active Directory should avoid creating universal groups with memberships that change often. Since changes to global groups do not force global catalog updates, using global groups as members of a universal group effectively avoids this problem.

The next release of Active Directory is expected to improve its support of group handling and replication issues. Of course, careful planning will reap benefits now and in the future.


ADSI Group Interfaces

ADSI includes an interface for working with groups, appropriately named IADsGroup. This interface contains Add and Remove methods to manage the list of group members. The properties and methods of IADsGroup are listed in Tables 10-6 and 10-7.

IADsGroup Property Data Type Description

Description

String

A description of the group

Table 10-6 Properties of the IADsGroup interface.

IADsGroup Method Description

Add

Adds a user or other security principle to the group

IsMember

Checks to see whether the specified object is a member of the group

Members

Returns a collection of member objects of the group by using the IADsMember interface

Remove

Removes a member from the group

Table 10-7 Methods of the IADsGroup interface.

Creating a Group

To create a group, start by calling the Create method of the IADsContainer interface. The Create method of the IADsContainer interface was used earlier in the CreateUser script to create a user object, and using it to create a group is no different. Then fill in the necessary information about the group.

For a group, Active Directory requires that the cn, groupType, and sAMAccountName attributes be filled in before a program or script calls SetInfo. The cn attribute is simply the name of the group. The groupType attribute is the combination of constants from the ADS_GROUP_TYPE_ENUM enumeration. The sAMAccountName is the name used by down-level (older) clients such as Windows 95, Windows 98, and Windows NT 4.0 to access the group using the SAM API functions such as NetGroupGetInfo. The sAMAccountName for groups can be up to 256 characters long. As mentioned earlier, the limit for users is 20 characters.

After all the required properties are filled in with values, the SetInfo method of IADs is called to update the directory server. A new group object isn't actually saved to the directory until the SetInfo method is called.

Listing 10-4 shows a script, available on the companion CD, that creates a security-enabled group with global scope. Once the group is created and the required properties are specified, the SetInfo method is called. The script checks for any errors that might have occurred. If any do occur, the script displays the error information and exits. If no errors occur, the script continues setting descriptive properties of the group and then updates the server with a final call to SetInfo.

 <job >
<reference gu/>
<script language="VBScript">
` CreateGroup.wsf - Creates an example group in the Users container
`
` Strings used to identify and describe the new group
strGroupName = "Example Group"
strGroupDesc = "Example group for testing purposes."
strGroupInfo = "This is an example group, safe to delete."
` Display info
WScript.Echo "Creating group `" & strGroupName & "`..."
` Bind to the RootDSE and get the default domain partition
Set adsRootDSE = GetObject("LDAP://RootDSE")
strDomainDN = adsRootDSE.Get("defaultNamingContext")
` Bind to the Users container of the domain
strADsPath = "LDAP://CN=Users," & strDomainDN
Set adsContainer = GetObject(strADsPath)
` Go to the next line if an error occurs
On Error Resume Next
` Create the group object in the container
Set adsGroup = adsContainer.Create("group", "CN=" + strGroupName)
` Set type as security and scope to global
lGroupType = ADS_GROUP_TYPE_SECURITY_ENABLED Or _
    ADS_GROUP_TYPE_GLOBAL_GROUP 
adsGroup.Put "groupType", lGroupType
` Set the account name for the group 
` Can be same as full group name (<256 characters)
adsGroup.Put "sAMAccountName", strGroupName
` Update server with required properties
adsGroup.SetInfo
` Check for errors
If Err.Number <> 0 Then
    ` Check to see whether group already exists error
    If Err.Number = &H80071392 Then
        ` Display error message and exit
           WScript.Echo "The group `" & strGroupName & _
               "` already exists."
           WScript.Quit 1     Else
        WScript.Echo "Unexpected error creating group." & vbNewLine & _
            Err.Description & " (" & Hex(Err.Number) & ")"
        WScript.Quit 1
    End If
End If
` Turn off error handling
On Error Goto 0
` Set the description using the Description property
adsGroup.Description = strGroupDesc
` Set the notes field using the info attribute
adsGroup.Put "info", strGroupInfo
` Apply the properties to the group entry
adsGroup.SetInfo
` Release objects
Set adsGroup = Nothing
Set adsContainer = Nothing
` Finish
WScript.Echo "Group created successfully."
</script>
</job>

Listing 10-4 CreateGroup.wsf shows how to create a security-enabled group with global scope.

When you run the CreateGroup script, a group named "Example Group" is created in the Users container. Figure 10-3 shows the Properties dialog box for the new group in Active Directory Users and Computers.

An important caveat when creating groups is to avoid hard coding a particular location or container name. Placing fixed addresses or names in applications is generally a bad practice and it's particularly true for Active Directory–enabled applications because each domain may be configured differently. The CreateGroup script creates the example group in the Users container. A better approach would be to use the well-known GUID for the Users container. In addition, applications should not depend on groups always being in the same location because an administrator might move the group or rename one of its containers. Applications can search for the group or use the otherWellKnownObjects attribute to track the object's location in the directory regardless of name or location. The Create-Computer sample shown in the next section uses the well-known GUID to locate the Computers container. See Chapter 4 for more information about binding to objects with well-known GUIDs.

Figure 10-3 Properties dialog box for the new group created with the CreateGroup script.

Enumerating Groups

Using the IADsGroup interface, you can obtain the list of members of a group. When you call the Members method of IADsGroup, you receive an IADs-Members interface, which exposes the collection of members. IADsMembers is very similar in both function and purpose to IADsContainer. Both allow enumeration using the For Each statement in Visual Basic and VBScript. Table 10-8 shows the properties of IADsMembers.

IADsMembers Property Data Type Description

Count

Long

Number of members in the collection.

Filter

Variant array of strings

Array of class names used to filter the enumeration of members. Same as the Filter method of the IADsContainer interface.

get__NewEnum(Not exposed in Visual Basic)

Object

Creates a new enumerator object that supports the IEnumVARIANT interface. Called indirectly from Visual Basic by using the For Each statement. Returns an IUnknown interface pointer. Note that there are two underscore (_) characters in the name.

Table 10-8 Properties of the IADsMembers interface.

The following code illustrates how to enumerate the members of a group.

 ` Get the members collection
Set adsMembers = adsGroup.Members
` Enumerate each member
For Each adsMember In adsMembers
    ` Display the full name of the member
    WScript.Echo adsMember.Get("name")
Next

Modifying Group Membership

The Add and Remove methods of IADsGroup are used to modify the membership of a group. Listing 10-5 shows the ModifyGroup script, available on the companion CD, that shows how to add, remove, verify, and list members in a group. The ModifyGroup script runs at the command prompt and accepts a group name, an action (add, del, test, or list), and a user name. Based on the input, the script will add the user to the group, remove the user from the group, use the IsMember method to confirm membership, or list the group members. Here are some examples of its usage:

 cscript modifygroup.wsf "coppersoftware\Example Group" /add "Joe A. User"
cscript modifygroup.wsf "coppersoftware\Example Group" /test "Joe A. User"
cscript modifygroup.wsf "coppersoftware\Example Group" /list
cscript modifygroup.wsf "coppersoftware\Example Group" /del "Joe A. User"

To list the members of the group, the Members method is called to return a collection of members, which is enumerated using the For Each statement.

 <job >
<reference gu/>
<script language="VBScript">
`
` ModifyGroup
` Can add, remove, verify, and list members of a group
`
` Check whether there is a command-line argument
Set wshArguments = WScript.Arguments
` Get parameters based on number of arguments
Select Case wshArguments.Count Case 1
        strGroup = wshArguments(0)
        
    Case 2
        strGroup = wshArguments(0)
        strAction = wshArguments(1)
    
    Case 3
        strGroup = wshArguments(0)
        strAction = wshArguments(1)
        strUser = wshArguments(2)
End Select
` Check for no group name or help request
If strGroup = "" Or InStr(1, strGroup, "?", vbTextCompare) > 0 Then
    ` Show usage and quit
    strUsage = "Usage: modifygroup `groupname'"
    strUsage = strUsage & vbCrLf & "             [ /add  username ]"
    strUsage = strUsage & vbCrLf & "             [ /del  username ]"
    strUsage = strUsage & vbCrLf & "             [ /test username ]"
    strUsage = strUsage & vbCrLf & "             [ /list ]"
    `
    strUsage = strUsage & vbCrLf & _
        "Where username is either UPN (charles@coppersoftware.com) "
    strUsage = strUsage & vbCrLf & "or Domain (domainname\username)"
    WScript.Echo strUsage
    WScript.Quit (1)
End If
` Figure out action requested
` Take the left-most 2 characters of the parameter and
` check whether they match into the argument list
nAction = InStr(1, "/t/l/a/d", Left(strAction, 2), vbTextCompare)
` Use NameTranslate to look up the group in the directory
Set adsNameTranslate = CreateObject("NameTranslate")
` Specify the GC for quick lookups
adsNameTranslate.Init ADS_NAME_INITTYPE_GC, vbNull
` Set the group name into NameTranslate
` Specify unknown format to have object determine
adsNameTranslate.Set ADS_NAME_TYPE_UNKNOWN, strGroup
` Get the DN of the group
strGroupDN = adsNameTranslate.Get(ADS_NAME_TYPE_1779) ` Bind to group object
Set adsGroup = GetObject("LDAP://" & strGroupDN)
` If a user was specified, get their information
If strUser <> "" Then
    ` Set the user name into NameTranslate
    adsNameTranslate.Set ADS_NAME_TYPE_UNKNOWN, strUser
    ` Get the DN of the user
    strUserDN = adsNameTranslate.Get(ADS_NAME_TYPE_1779)
    
    ` Bind to the user object
    Set adsUser = GetObject("LDAP://" & strUserDN)
Else
    
    ` If no user specified, can only list
    nAction = 3
End If
    
` Perform an action
Select Case nAction
    
    Case 1
        ` Test for membership
        If adsGroup.IsMember(adsUser.ADsPath) Then
            
            ` Display if member
            WScript.Echo adsUser.FullName & " is a member of the " & _
                adsGroup.Get("name") & " group."
        Else
            
            ` Display if not member
            WScript.Echo adsUser.FullName & " is not a member of the " & _
                adsGroup.Get("name") & " group."
        End If
        
    Case 5
        ` Add action
        WScript.Echo "Adding " & adsUser.FullName & " to group " & _
            adsGroup.Get("name")
        
        ` Add user to group
        adsGroup.Add adsUser.ADsPath
        
    Case 7
        ` Remove action, get confirmation
        strPrompt = strAction & adsUser.FullName & strVerb & _
            adsGroup.Get("name") & "?"
                 If MsgBox(strPrompt, vbYesNo, "Modify Group") = vbYes Then
        
            WScript.Echo "Removing " & adsUser.FullName & _
                " from group " & adsGroup.Get("name")
        
            ` Remove user from group
            adsGroup.Remove adsUser.ADsPath
        End If
        
    Case Else
        ` Some other action, list membership
        WScript.Echo "Listing all members in group " & adsGroup.Name
                
        ` Skip to the next line on errors
        On Error Resume Next
        
        ` Get the description
        strDescription = adsGroup.Description
        
        ` If something was returned, display it
        If strDescription <> "" Then
        
            ` Creation description string
            strDescription = "Description: " & strDescription
            WScript.Echo strDescription
            
        End If
        
        ` Display separator
        WScript.Echo String(Len(strDescription), "-")
        
        ` Get the members collection
        Set adsMembers = adsGroup.Members
        
        ` Enumerate each member
        For Each adsMember In adsMembers
        
            ` Display the name of the member
            WScript.Echo adsMember.Get("name")
        Next
        
        ` Turn error handling back on
        On Error GoTo 0
End Select WScript.Echo "Finished."
</script>
</job>

Listing 10-5 ModifyGroup.wsf shows how to add, remove, verify, and list members of a group.

If you attempt to use the ModifyGroup script or any interface to Active Directory to list the members of the Domain Users group, you will find that none are listed. Since every user created in the domain is automatically a member of the Domain Users group, Microsoft realized that thousands of values could be written to the members attribute of the group. This would cause problems with replication and performance, so Active Directory simply doesn't bother trying to keep the Domain Users group updated. However, Active Directory maintains an association between the Domain Users group and its members via the primaryGroupID attribute of the user object. When a new user is created, this attribute is given the security identifier of the Domain Users group.



MicrosoftR WindowsR 2000 Active DirectoryT Programming
MicrosoftR WindowsR 2000 Active DirectoryT Programming
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 108

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net