Windows Server 2003's Microsoft Management Console (MMC) Group Policy Management Console (GPMC) snap-in installs COM objects that support automation through scripting, opening up a world of possibilities when dealing with Active Directory (AD) Group Policy Objects (GPOs). (For details about the GPMC, see "Related Reading," page 6.) Building on the capabilities I discuss in "Scripting Group Policy Searches," November 2003, http://www.winnetmag.com/windowsscripting, InstantDoc ID 40231, and "Scripting Group Policy Objects," October 2003, InstantDoc ID 39856, you can use GPM objects to add or remove the Read and Apply Group Policy permissions for security principals on AD objects such as GPOs, Scope of Management (SOM) objects, and Windows Management Instrumentation (WMI) filters. (To set Deny or Custom permissions on these objects, you still need to use Active Directory Service Interfaces—ADSI—tools such as IADsSecurityDescriptor or Microsoft's adssecurity.dll.)
Setting Permissions on a GPO
Let's begin by using GPM objects to set permissions on a GPO's ACL, which defines which users and computers have permissions to apply the GPO. The ability to use the GPM objects to grant Read and Apply Group Policy permissions according to security-group membership can be extremely useful. For example, suppose you want a security group containing several computers in an organizational unit (OU) in your domain to have access to a GPO linked to that OU. Currently, those computers are denied access to the GPO. The script that Listing 1 shows, SettingGPOPermissions.vbs, creates a new set of Read and Apply Group Policy permissions for the group, connects to the GPO, removes the existing permissions for the group (including the ones that deny the group access to the GPO), and applies the new set of permissions.
The code at callout A in Listing 1 defines constants that you'll need to change to suit your environment: the GPO's globally unique identifier (GUID), the domain name, and the security group. The script then connects to the domain and the GPO and retrieves a reference to the GPM object's constants.
Next, the script uses the GPM object's CreatePermission method to create the new permissions; I recommend that you use this method anytime you want to script GPM to create a permission object for a GPO, SOM, or WMI filter. The method takes three parameters. The first parameter represents the trustee (i.e., the AD user, computer, or security group to which the permission applies). The second parameter represents the permission to be applied, using the defined constants and beginning with the Perm prefix. The third parameter is a Boolean value indicating whether child objects (e.g., lower-level OUs) should inherit the permission. SettingGPOPermissions.vbs passes the name of the trustee (i.e., the GROUP security group), a constant representing the Read and Apply Group Policy permissions (i.e., PermGPOApply), and the Boolean value TRUE (indicating that child objects should inherit the permissions).
The script then uses the GPMGPO object's GetSecurityInfo method to retrieve the GPO's existing GPMSecurityInfo collection. This collection might contain many permissions, so you need to remove and replace only the specific permissions you're interested in, rather than simply inserting a new collection. To remove the permissions that apply to the group, SettingGPOPermissions.vbs uses the GPMSecurityInfo object's RemoveTrustee method, simply passing the group's SAM name (i.e., domain\name) to this method. If you don't want to use the group's SAM name—for example, because you want to remove all trustees from a GPO—you can use the trustee's unique SID instead. Use the GPMPermission object's Trustee method to read the trustee from the GPMPermission object, then use the resulting GPMTrustee object with the GPMTrustee object's TrusteeSid property method to retrieve the trustee's unique SID. In this type of situation, replace the code at callout B in Listing 1 with the following two lines of code:
strSID = gpmPerm.Trustee.TrusteeSid gpmSecInfo.RemoveTrustee strSID
(Be aware that you can't use the GPMTrustee object's TrusteeName method in a similar manner because this method doesn't return the name in SAM format.)
The script then uses the GPMSecurityInfo object's Add method to add the new permissions to the collection, then ends by using the GPMGPO object's SetSecurityInfo method to commit the changed collection of permissions to the GPO.
You can modify the script to use the GPM object's CreatePermission method to give a trustee Read access only, to allow a trustee to Read and Edit the policy settings in the GPO, or to allow a trustee to Modify the GPO's permissions (so that you can script delegation of administration). You can combine these capabilities with the capabilities I describe in the previous articles in this series to search for some or all GPOs in a domain, then apply a set of permissions to those GPOs.
Setting Permissions on SOMs and WMI Filters
So what about SOMs and WMI filters? You can use GPM objects to set six permissions for SOMs and two permissions for WMI filters. (For more information about SOMs, see "Scripting Group Policy Searches"; for more information about WMI filters, see the sidebar "WMI Filters.") The SOM permission constants let trustees link GPOs to SOMs to generate Resultant Set of Policies (RSoP) logging or planning data for OUs and domains, to have full control over all WMI filters in the domain, or to create WMI filters or GPOs for the entire domain. The permissions that apply to WMI filters let trustees edit or gain full control over a WMI filter. To set permissions on these objects, you can use the methods that Listing 1 shows; simply modify the permission constant in the GPMConstants object.
As "WMI Filters" explains, one possible use for WMI filters is to determine whether a specific hotfix has been applied to a system. Suppose you have a set of Windows XP computers on which you plan to update software, but the update requires a specific hotfix to be installed first. You can use ADSI to create a WMI filter that determines which systems are running the hotfix, then use a script such as SetWMIFilterAndPermissions.vbs, which Listing 2 shows, to set the filter and apply a GPO that installs the updated software on the systems that the filter determines are running the hotfix. This script also adds a permission that lets the specified security group edit the WMI filter.
Note that the GPO_PATH and WMIFILTER constants appear here as wrapped lines but must actually be formatted in one line of code each. GPO data resides in two places: Group Policy Configuration data resides in AD, and certain key Group Policy Template data exists as files and directories in the system volume (i.e., SYSVOL). For our example, you need to manipulate the data in AD. All GPO data in AD resides in one folder, listed according to GUID. The GPO_PATH constant defines the Lightweight Directory Access Protocol (LDAP) path to that information. The WMIFILTER constant defines the WMI filter string.
Setting the WMI filter is simple. The script uses VBScript's GetObject call to bind to the LDAP path that the GPO_PATH constant defines, connecting to the GPO object in AD. The script then uses ADSI's IADs::Put method to set the gPCWQLFilter string property and IADs::SetInfo method to write the results to AD.
Next, the script uses the GPMGPO object's GetWMIFilter method to retrieve a GPMWMIFilter object, then uses the GPMWMIFilter object's GetSecurityInfo method to retrieve the object's security permissions. The script then uses the GPMConstant object's PermWMIFilterEdit property as a parameter to the GPM object's CreatePermission property to create the Edit permission for the defined group. The script removes the existing permissions for the specified trustee (i.e., GROUP) for that GPO, then sets the new permission into the GPMSecurityInfo collection object. The script finishes by using the GPMWMIFilter object's SetSecurityInfo method to write the modified GPMSecurityInfo collection object back into the WMI filter.
Be aware that the GetSecurityInfo and SetSecurityInfo methods for the GPMWMIFilter, GPMGPO, and GPMSOM objects all retrieve and manipulate permissions collections but that these collections are very different from one another, so be careful not to confuse these methods. Also, don't be concerned because the script removes permissions first, then adds permissions, rather than performing these operations the other way around. The code to remove permissions removes only the permissions for the specified trustee so that I can start with a blank slate for that trustee before I add new permissions.
Time to Experiment
I hope this series of articles shows you how to begin scripting Group Policy with GPM COM objects. I also encourage you to look through the Microsoft Developer Network (MSDN) and experiment with the information you find there.
"Enterprise Management with the Group
Policy Management Console"
"Group Policy Management Console Reference"
Robbie Allen and Alistair G. Lowe-Norris
Active Directory, 2nd edition
(O'Reilly and Associates, 2003)
"Chapter 7: Profiles and Group Policy Primer"
and "Chapter 10: Designing Organization-Wide Group Policies"