Group Policy

Automating Group Policy Management with Windows PowerShell

Darren Mar-Elia

Parts of this article are based on pre-release software and is subject to change.

At a Glance:

  • Using GPMC APIs
  • Creating Group Policy Reports with Windows PowerShell
  • Cmdlets in Windows 7 and Windows Server 2008 R2

Contents

What Does GPMC Offer?
Automating the GPO Lifecycle
Automating Group Policy Reporting
Generating an HTML-Based Report
Generating an XML-Based Report
Reporting on RSoP logging
An Easier Way

Group Policy is a powerful yet complex technology. It is used, to some extent, in almost every environment. And for many who rely on it heavily to secure and lock down their Windows environment, Group Policy is a key part of their infrastructure.

That said, I am always surprised to see how little automation is used for Group Policy management in many IT organizations. When the Group Policy Management Console (GPMC) shipped, Microsoft made a set of APIs and sample scripts available for automating tasks that were performed with that console. There is much that can be done using these APIs, as well as opportunities to automate other aspects of Group Policy management, such as troubleshooting and diagnostic tasks. And, with the advent of Windows PowerShell, some of these tasks have become easier.

Thorbjörn Sjövold discussed using Windows PowerShell for getting at some of the GPMC APIs in his article "Simplify Group Policy Administration with Windows PowerShell." In this article, I want to build on that foundation with some additional automation techniques you can use to further automate management of your Group Policy environment.

What Does GPMC Offer?

The GPMC is focused on operating against the whole Group Policy Object (GPO), and its associated permissions, links, and so on. It does not provide automation or management of the actual settings within the GPO. However, it can be useful to perform automation against the whole GPO as a way of managing the change process within your Group Policy environment. For example, you can use the GPMC APIs to modify links to GPOs. If you have a new GPO that you want to deploy, you can script the creation of the GPO and then you can script the linking process after its settings have been populated. You can also script the changing of a GPO's permissions, in case you want to modify which security groups are targeted by a GPO or who can edit that GPO.

And of course, you can always use the APIs to query information about GPOs, as opposed to just making changes. This includes generating HTML- and XML-based reports for GPO settings as well as Resultant Set of Policy (RSoP) reports against remote workstations and servers to determine if Group Policy was successfully applied.

It's also worth mentioning that when Microsoft released the updated GPMC that shipped with Windows Vista SP1 and Windows Server 2008, there were some updates to the APIs in order to support some of the new features that GPMC and Group Policy in general support. These include the ability to create new GPOs from "Starter GPOs" and to add comments to a GPO. Starter GPOs are like templates—they let you create a set of Administrative Template policy settings that you can then apply to a new GPO, pre-populating some of its settings. I want to start by looking at how you can automate the process of creating, permissioning, and linking a GPO and then show how you can leverage some of these new GPMC features in this automation.

Automating the GPO Lifecycle

To demonstrate how you can automate creating and managing GPOs, I am going to use Windows PowerShell and the GPMC APIs. In my example, I am creating a GPO called "TechNet Marketing Policy." When I create the GPO, I'm going to use a Starter GPO called "User Lockdown Template" as the starting point and add a comment indicating that I created the GPO. I could create the Starter GPO using GPMC APIs, but in this example, I'm going to assume it already exists.

The next step that I want to automate is the permissioning of the GPO. I'm going to permission the GPO so that only users within the "Marketing Users" group will process the policy, and I will add a group called the "GPO Admins" with the permissions to edit the GPO. Finally, I am going to link the GPO to the Marketing OU in my Active Directory domain.

The entire Windows PowerShell script, which I've called gpoCreate.ps1, is shown in Figure 1. I've added the line numbers simply for reference.

Figure 1 The Windows PowerShell gpoCreate.ps1 scriptt

1. $gpmc = New-Object -ComObject GPMgmt.GPM
2. $constants = $gpmc.GetConstants()
3. $domain = $gpmc.GetDomain("cpandl.com",$null,$null)
4. $starter = $domain.GetStarterGPO("{CDFD6B94-BF4E-4D07-8D99-3D416EC7C9A0}")
5. $gpo = $domain.CreateGPOFromStarterGPO($starter)
6. $gpo.DisplayName = "Technet Marketing Policy"
7. $gpo.Description = "Created by Darren for Technet Demo"
8. $permissions = $gpo.GetSecurityInfo()
9. $permissions.RemoveTrustee("Authenticated Users")
10. $applyPermission = $gpmc.CreatePermission("Marketing Users",$constants.permGPOApply,$false)
11. $editPermission = $gpmc.CreatePermission("GPO Admins",$constants.permGPOEdit,$false)
12. $permissions.Add($applyPermission)
13. $permissions.Add($editPermission)
14. $gpo.SetSecurityInfo($permissions)
15. $som = $domain.GetSOM("OU=Marketing,DC=cpandl,DC=com")
16. $som.CreateGPOLink(1,$gpo)

Line 1 is required to get started using the GPMC APIs. You will use this in any GPMC script you write. This line creates an instance of the base GPMC object and assigns it to the $gpmc variable. Line 2 is another commonly used command. The GPMC provides a set of handy constants that are used across the spectrum of tasks to indicate a particular state. You'll see how I use it later in the script, but for now, I'll just assign the constants to the $constants variable.

In Line 3, I need to get a reference to the Active Directory domain that I'll be operating on. In my example, that is a domain called cpandl.com. To do that, I call the GetDomain method on the $gpmc variable. The two $null parameters are optional and allow you to specify a particular domain controller to connect to when you connect to the domain. By leaving these null, I'm essentially choosing the default, which is the PDC emulator DC.

In Line 4, I need to get a reference to my Starter GPO (User Lockdown Template). The GetStarterGPO method only supports calling the Starter GPO by its GUID, so I have to go into the GPMC console to look for that. (I could have scripted it also.) That's the GUID I'm passing to the GetStarterGPO method.

In Line 5, once I have my Starter GPO reference, I use it to create the new GPO, using the CreateGPOfromStarterGPO method that is available on the $domain variable. I assign the newly created GPO to $gpo so I can continue to use it. Note that at this point, the GPO has no name (well, it has the default name of "New Group Policy Object"). So in Line 6, I modify the displayName property on $gpo to give it a new name. Line 7 is where I add a comment to the GPO, by setting the description property on $gpo.

Now that I've got my GPO created, the next set of tasks is to modify the permissions on the GPO. In Line 8, I start off by getting the current list of permissions on my newly created GPO, using the GetSecurityInfo method on the GPO. The approach for modifying permissions on a GPO is to get the list of current permissions on the GPO, add and delete entries from that list as needed, and then re-apply the list to the GPO. To that end, in Line 9, I remove the Authenticated Users default permission from the newly created GPO.

In Lines 10 and 11, I create the two new permissions that I want to add to the GPO. I create those using the $gpmc CreatePermission method, supplying the Trustee (user group) name and the permission that I want the group to have. Note that I'm using the $constants variable to define the permission. The $constants.permGPOApply property grants the "Read and Apply Group Policy" permissions that allow members of a group to process a GPO, while the permGPOEdit property grants the ability for that group to Edit a GPO. The $false parameter at the end of the CreatePermission method call simply says that the permission should not be inherited, which is the default for GPO permissions.

Once the two permissions are created, Lines 12 and 13 add them back to the $permissions list and Line 14 calls the SetSecurityInfo method on the GPO to apply the new list back to the GPO.

The final two lines link the GPO to the Marketing OU. In Line 15, I call the GetSOM method (SOM stands for "scope of management") on the $domain variable to "connect" to the OU. In Line 16, I call CreateGPOLink on the $som object I just created and pass it two parameters. The first parameter indicates the order on the OU that I want the GPO to be linked (an OU can have multiple GPOs linked to it). The "1" stated for the first parameter indicates that I want the GPO to be linked first in the list. The second parameter (in this case, the $gpo variable) is the reference to the GPO I want to link. And now I've successfully created, permissioned, and linked a GPO using automation. The result is shown in Figure 2.

fig01.gif

Figure 2 Viewing the Newly Created GPO

Automating Group Policy Reporting

Another aspect of Group Policy management you can automate is the reporting. In this respect, there are at least two types of reports that GPMC delivers. The first is the ability to report on the settings within a GPO. This allows you to generate either an HTML- or XML-based report of the settings that are currently enabled in the GPO, as shown in Figure 3.

fig02.gif

Figure 3 Reporting on GPO Settings

The second reporting capability lets you generate Resultant Set of Policy (RSoP) or Group Policy Results reports. There are two types of RSoP reports—logging and planning. A logging report is run against a remote desktop or server, indicating what policies were delivered to that remote system and whether they were successful. The RSoP planning report lets you perform what-if analysis against a particular OU, computer, or user to determine what policies will apply. In both cases—logging and planning—you can generate HTML or XML output using the GPMC APIs and Windows PowerShell.

Generating an HTML-Based Report

To generate a GPO settings report in Windows PowerShell, I start off with two familiar initialization commands, which I used in the previous script:

1. $gpmc = New-Object -ComObject GPMgmt.GPM
2. $constants = $gpmc.GetConstants()

Next, I need to get a reference to the GPO that I want to report on, like so:

3. $domain = $gpmc.GetDomain("cpandl.com",$null,$null)
4. $gpo = domain.GetGPO("{31B2F340-016D-11D2-945F-00C04FB984F9}")

In Line 3 here, I am again connecting to the domain and then in Line 4, I use the GetGPO method on the domain to get a reference to the GPO I want to report on. In this case, I have to pass the GUID of the GPO, which happens to be the "Default Domain Policy."

Next, I need to generate the settings report:

5. $gpo.GenerateReportToFile($constants.ReportHTML,"c:\GPReports\DDPSettings.html")

Here, I am calling the GenerateReportToFile method on the GPO to create the settings report. The first parameter uses the $constants variable to specify an HTML report type. The second parameter points to the path where I want to save the report.

Generating an XML-Based Report

Another way to access the settings data using Windows PowerShell is to take advantage of the built-in XML parsing capabilities in Windows PowerShell and its ability to generate a settings report in XML. So, instead of Line 5 above, I change that to the following:

[xml]$report = ($gpo.GenerateReport($constants.ReportXML)).Result

In this example, I'm using a different method on the GPO, called GenerateReport. This method takes a single parameter, which is the report type. But in this case, I am assigning the output of the method call to a variable called $report and I am preceding that variable name with the Windows PowerShell type accelerator [xml], which tells PowerShell to take the output of the command that I am storing in $report and convert it to an XML document instead of just a bunch of text. However, in order to get the actual XML from GenerateReport, I have to use the Result property on that output, which is what you see at the end of that statement. So the Result property holds the actual XML that I am using to generate my XML document.

Once I have the XML in the $report variable, I can do lots of interesting things with it. For example, consider the following command:

$report.GPO

This returns the "GPO" element within the document that provides overview information about the GPO I am reporting on. Or this command:

$report.GPO.LinksTo

This returns a list of all of the places that this GPO has been linked.

But more interestingly, I can use the structured nature of XML to investigate the actual settings within the GPO from the command-line. For example, since this is the Default Domain Policy GPO, I know it probably contains some security settings related to password policy. By navigating the GPO namespace as represented in the XML file, I can quickly get to those settings, as follows:

$report.GPO.Computer

This returns information about the Computer side of the GPO. If I view the properties on this Computer property, I notice a collection of policy areas under the ExtensionData property, as shown in Figure 4.

fig03.gif

Figure 4 Viewing GPO Settings Through XML

In this example, there are two extension areas within the computer side of this GPO: registry and security. So I issue the following command:

$report.GPO.Computer.ExtensionData[0].Extension

This gives me a list of policy areas implemented under the Security policy section. I see two properties called Account and Security Options. Now I enter the following command:

$report.GPO.Computer.ExtensionData[0].Extension.Account

This gives me a list of each of the Account Policy settings for this GPO, as shown in Figure 5.

fig04.gif

Figure 5 Viewing Account Policy Settings Within the GPO

Notice that some of the settings do not actually show the value in Figure 5. Each setting is returned as a member of a collection under the Account property. So in order to see, for example, the Minimum Password Length setting, I need to index into the collection, like so:

$report.GPO.Computer.ExtensionData[0].Extension.Account[4]

Once you get the hang of navigating the XML namespace for GPO settings, you can easily get to particular settings and use this capability in conjunction with Windows PowerShell to locate the values of settings within a GPO quite quickly.

Reporting on RSoP logging

Just as with GPO settings, you can generate an XML- or HTML-based report in Windows PowerShell that shows the Group Policy settings that have been applied to a given machine. The approach is a little different, though. Starting again with the two initialization commands, I take the script in a slightly different direction:

1. $gpmc = New-Object -ComObject GPMgmt.GPM
2. $constants = $gpmc.GetConstants()
3. $rsop = $gpmc.GetRSOP($constants.RSOPModeLogging,$null,0)
4. $rsop.LoggingComputer = "xp2"
5. $rsop.LoggingUser = "cpandl\dpmtest"
6. $rsop.CreateQueryResults()
7. $rsop.GenerateReportToFile($constants.ReportHTML,"c:\gpreports\XP2Rsop.html")

After Lines 1 and 2 set up the process, Line 3 creates the $rsop variable by calling the GetRSOP method on $gpmc. In that method call, I indicate that I want to create an RSOP logging and not a planning report. Lines 4 and 5 set properties on that $rsop object to tell it what computer and user I want to collect RSOP data against. Then, the sole purpose of Line 6 is to connect to the computer specified in line 5 and generate the RSoP namespace for this query. Finally, in Line 7, I output the results of the query to an HTML file.

Note that the RSoP object also has a GenerateReport method similar to the GPO settings example. And you can output the RSOP report to an XML document and navigate through it in Windows PowerShell to find out what's happening from a Group Policy perspective on that remote client. For example, say I want to quickly find out if Group Policy processing succeeded for the Computer side of GPO processing. I can use the previous script, but replace Line 7 with this:

[xml]$rsopReport = 
  ($rsop.GenerateReport($constants.ReportXML)).Result

This puts my RSoP report into an XML document.

Next, I can navigate into the XML name-space to find out the Client-Side Extension (CSE) status for the computer as follows:

$rsopReport.Rsop.ComputerResults.ExtensionStatus

When I do that, I get a listing that shows me the status on each CSE that was processed by the computer!

An Easier Way

As I've shown so far, there is a lot of powerin leveraging the GPMC APIs to automate Group Policy lifecycle, reporting, and diagnostic tasks. But it does take quite a few steps to get to the desired result. However, there is somerelief and even more coming in the future.

I've created a set of 25 free GPMC Windows PowerShell cmdlets that wrap most of the common GPMC functions into easy-to-use cmdlets. You can download these GPMC cmdlets at www.sdmsoftware.com/freeware. To give you an example of the simplified process, from our first example of creating and then permissioning and linking a GPO, the following script using my GPMC cmdlets would accomplish the same tasks as the script I presented earlier, but with fewer commands:

$gpo = New-SDMgpo "Technet Marketing Policy" 
  -FromStarterGPO "User Lockdown Template" –native
$gpo.Description = 
  "Darren's Technet Demo GPO" Remove-SDMgpoSecurity 
$gpo.DisplayName -Trustee "Authenticated Users"  –PermApply
Add-SDMgpoSecurity $gpo.DisplayName 
  -Trustee "Marketing Users" –PermApply
Add-SDMgpoSecurity $gpo.DisplayName 
  -Trustee "GPO Admins" –PermEdit
Add-SDMgplink "Technet Marketing Policy" 
  -Scope "OU=Marketing,DC=cpandl,DC=com" -Location 1

Even better, Windows 7 and Windows Server 2008 R2 will provide built-in Windows PowerShell cmdlets for GPMC. For example, to create my example GPO from a Starter GPO with a comment, I can issue one Windows PowerShell command, as follows:

new-gpo "Darren's Technet Policy" -starterGPOName 
 "User Lockdown Template" -Comment "Darren's Demo"

Microsoft is also adding support for reading and writing a subset of Group Policy settings. Specifically, there will be support for reading and writing registry settings into either native Administrative Template policy or the newer Group Policy Preferences registry extension. For example, to write a new registry value into Group Policy Preferences, I would issue the following command :

Set-GPPrefRegistryValue "Darren's Technet Policy" 
  -key 'HKEY_LOCAL_MACHINE\Software\SDM Software' 
  -ValueName "Path" -Value "2" -Type String 
  -Context Computer -Action Update

Here, the set-GPPrefRegistryValue cmdlet takes a number of parameters to create a registry policy setting within my "Darren's Technet Policy" GPO for the registry value HKEY_LOCAL_MACHINE\Software\SDM Software\Path= REG_SZ 2. The Context parameter tells the policy whether it should be put under the Computer or User side of the GPO, and the Action parameter specifies how to apply the registry value and corresponds to the options within the GPP UI (other options include Replace, Create and Delete).

As of the time of writing this article, Windows 7 and Windows Server 2008 R2 are planned to ship with 25 cmdlets for managing Group Policy. Once these are available, managing Group Policy through Windows PowerShell will be much easier.

Darren Mar-Elia is a Microsoft Group Policy MVP, creator of the popular Group Policy site www.gpoguy.com and coauthor of Microsoft Windows Group Policy Guide (Microsoft Press, 2005). He is also CTO and founder of SDM Software, Inc. Reach him at Darren@gpoguy.com.