Create or Update a Group Policy Using Settings From Another Group Policy Using Microsoft PowerShell

Over the course of the past several months, I have had several projects where I needed to create, edit, or fix group policies. A problem I ran into was I only needed a subset of the policy settings (Site to Zone Mappings, Microsoft Office settings). Another problem was corrupt group policies that would not backup. How can I get just the settings I needed into a test group policy? This article shows the script I created to handle those situations.

Yes, I know I can just backup a group policy (GPO), create an empty GPO, and then import the backup into the new GPO. But what if the original GPO is corrupted? Or contains hundreds or thousands of settings, and you only need a small subset of those settings?

Every project I have worked on recently has made me glad I created this script. I recently wrote about troubleshooting Site to Zone Mappings. For that project, the customer had hundreds of settings in the GPO that contained the Site to Zone Mappings I needed to troubleshoot. How could I get just those policy settings and ignore all the rest? Sure, I could have done the backup/create empty/import routine, but then I would have spent hours removing all the other policy settings I did not need.

Enough chit-chat. Let’s get to work.

GPOs are made up of various parts. Preferences are stored in XML files, some settings are stored in INF files, and other settings are stored in a registry.pol file. For the work I have been doing, all the settings I need have been in the registry.pol file (so far).

Find the GPO you need the settings for, go to the Details tab in the Group Policy Management Console (GPMC), and copy the Unique ID, as shown in Figure 1.

Figure 1
Figure 1

Browse the SYSVOL folder. I do it by Start, Run, and typing in the domain name like \domain.tld, as shown in Figure 2.

Figure 2
Figure 2

Double-clicking SYSVOL, as shown in Figure 3.

Figure 3
Figure 3

Then double-click the domain name, then Policies, paste the Unique ID into the Search box, and double-click the found result, as shown in Figure 4.

Figure 4
Figure 4

Depending on if the GPO settings you need are from the Computer Configuration or User Configuration, double-click either Machine or User. For this example, the settings I need are User settings, as shown in Figure 5.

Figure 5
Figure 5

Copy and paste the registry.pol file to a work location, as shown in Figures 6 and 7.

Figure 6
Figure 6
Figure 7
Figure 7

Now you need to use Darren Mar-Elia’s Registry.Pol Viewer Utility to create a CSV file from the registry.pol file.

Start polviewer.exe, browse to the registry.pol file and click Submit, as shown in Figure 8.

Figure 8
Figure 8

Click File, Save to CSV, and save the CSV file to your work location, as shown in Figure 9.

Figure 9
Figure 9

Use your favorite text editor, remove the lines of the policy settings you don’t need, and save the updated file, as shown in Figure 10.

Figure 10
Figure 10

Start an elevated PowerShell session and run the script .\CreateGPO.ps1, as shown in Figures 11 and 12.

Figure 11
Figure 11
Figure 12
Figure 12

Open up GPMC, or refresh GPMC, and the new unlinked GPO shows in the Group Policy Objects node, as shown in Figure 13.

Figure 13
Figure 13

I don’t know about you, but that is MUCH faster than importing an entire GPO and then taking the time to delete the settings that are not needed. Now the GPO can be changed to do what is needed, linked, and tested.

Here is the script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#requires -Module GroupPolicy
#region help text
<#
.SYNOPSIS
Creates an unlinked Group Policy Object from an imported CSV file.
If the Group Policy Object exists, linked or unlinked, it is updated with the
settings from the imported CSV file.
.DESCRIPTION
Creates an unlinked Group Policy Object from an imported CSV file.
The CSV file is created using Darren Mar-Elia's Registry .Pol Viewer Utility
The Registry.pol files only contain settings from the Administrative Templates
node in the Group Policy Management Console.
This script is designed for consultants and trainers who may create Group Policies
in a lab and need a way to recreate those policies at a customer or training site.
The GroupPolicy module is required for the script to run.
On a server, Group Policy Management must be installed.
On a workstation, RSAT is required.
Remote Server Administration Tools for Windows 7 with Service Pack 1 (SP1)
Remote Server Administration Tools for Windows 8
Remote Server Administration Tools for Windows 8.1
Remote Server Administration Tools for Windows 10
.PARAMETER PolicyName
Group Policy Name.
This is a required parameter.
This parameter has an alias of PN.
.PARAMETER PolicyType
The type of Group Policy settings to import.
M - Machine (Computer)
C - Machine (Computer)
U - User
This is a required parameter.
This parameter has an alias of PT.
Default is Machine.
If a Group Policy is to contain both Computer and User settings, there will be
two .Pol files. One for Machine (Computer) settings and a separate .Pol file
for User settings. Each .Pol file is named Registry.pol. The CSV files will need
to be have different names. There will then be two CSV files to import.
The script will detect if the Group Policy Name exists and if it does, the next
set of settings will be added to the existing script.
If the Group Policy Name does not exist, a new Group Policy is created with the
imported settings.
.PARAMETER CSVFile
CSV file created by Registry PolViewer utility.
This is a required parameter.
The parameter has an alias of CSV.
The CSV file will contain either Machine or User policy settings. It should
contain both.
.EXAMPLE
PS C:\PSScript > .\CreateGPO.ps1 -PolicyName "Sample Policy Name" -PolicyType M -CSVFIle C:\PSScript\GPOMSettings.csv
Darren's PolViewer.exe utility is used first to create the
C:\PSScript\GPOMSettings.csv file.
If a Group Policy named "Sample Policy Name" does not exist, a policy will be
created using the Machine settings imported from the GPOMSettings.csv file.
If a Group Policy named "Sample Policy Name" exists, the policy will be
updated using the Machine settings imported from the GPOMSettings.csv file.
.EXAMPLE
PS C:\PSScript > .\CreateGPO.ps1 -PolicyName "Sample Policy Name" -PolicyType U -CSVFIle C:\PSScript\GPOUSettings.csv
Darren's PolViewer.exe utility is used first to create the
C:\PSScript\GPOUSettings.csv file.
If a Group Policy named "Sample Policy Name" does not exist, a policy will be
created using the User settings imported from the GPOUSettings.csv file.
If a Group Policy named "Sample Policy Name" exists, the policy will be
updated using the User settings imported from the GPOUSettings.csv file.
.INPUTS
None.  You cannot pipe objects to this script.
.OUTPUTS
No objects are output from this script. 
This script creates or updates a Group Policy Object.
.NOTES
NAME: CreateGPO.ps1
VERSION: 1.00
AUTHOR: Carl Webster
LASTEDIT: March 18, 2016
#>
#endregion
#region script parameters
[CmdletBinding(SupportsShouldProcess = $False, ConfirmImpact = "None", DefaultParameterSetName = "Machine") ]
Param(
[parameter(ParameterSetName="Machine",Mandatory=$True)]
[parameter(ParameterSetName="User",Mandatory=$True)]
[Alias("PN")]
[ValidateNotNullOrEmpty()]
[String]$PolicyName,
[parameter(ParameterSetName="Machine",Mandatory=$True,
HelpMessage="Enter M or C for Machine or U for User")]
[parameter(ParameterSetName="User",Mandatory=$True,
HelpMessage="Enter M or C for Machine or U for User")]
[Alias("PT")]
[String][ValidateSet("M", "C", "U")]$PolicyType="M",
[parameter(ParameterSetName="Machine",Mandatory=$True,
HelpMessage="Enter path to CSV file.")]
[parameter(ParameterSetName="User",Mandatory=$True,
HelpMessage="Enter path to CSV file.")]
[Alias("CSV")]
[ValidateNotNullOrEmpty()]
[String]$CSVFile
)
#endregion
#region script change log  
#webster@carlwebster.com
#@carlwebster on Twitter
#Created on November 7, 2015
#released to the community on 18-Mar-2016
#endregion
#region initial variable testing and setup
Set-StrictMode -Version 2
If(!(Test-Path $CSVFile))
{
Write-Error "$(Get-Date): CSV file $($CSVFile) does not exist.`n`nScript cannot continue"
Exit
}
#endregion
#region functions
Function SetPolicySetting
{
Param([string]$Key, [string]$ValueName, [string]$ValueType, $Data)
If($Key -eq "" -or $ValueName -eq "" -or $ValueType -eq "" -or $Null -eq $Key -or $Null -eq $ValueName -or $Null -eq $ValueType)
{
#failure
Write-Warning "$(Get-Date): Missing data: `nKey: $($Key) `nValueName: $($ValueName) `nValueType: $($ValueType) `nData: $($Data)`n`n"
}
Else
{
#Specifies the data type for the registry-based policy setting. You can specify one of the following data
#types: String, ExpandString, Binary, DWord, MultiString, or Qword.
$NewType = ""
$NewData = ""
Switch ($ValueType)
{
"REG_DWORD" {$NewType = "DWord"; $NewData = Invoke-Expression ("0x" + $Data)}
"REG_SZ"    {$NewType = "String"; $NewData = $Data}
"REG_EXPAND_SZ" {$NewType = "ExpandString"; $NewData = $Data}
"REG_BINARY"    {$NewType = "Binary"; $NewData = $Data}
"REG_MULTI_SZ"  {$NewType = "MultiString"; $NewData = $Data}
"REG_QDWORD"    {$NewType = "QWord"; $NewData = Invoke-Expression ("0x" + $Data)}
}
If($PolicyType -eq "M" -or $PolicyType -eq "C")
{
$NewKey = "HKLM\$($Key)"
}
ElseIf($PolicyType -eq "U")
{
$NewKey = "HKCU\$($Key)"
}
$results = Set-GPRegistryValue -Name $PolicyName -key $NewKey -ValueName $ValueName -Type $NewType -value $NewData -EA 0
If($? -and $Null -ne $results)
{
#success
Write-Host "$(Get-Date): Successfully added: $($NewKey) $($ValueName) $($NewType) $($NewData)"
}
Else
{
#failure
Write-Warning "$(Get-Date): Problem adding: $($NewKey) $($ValueName) $($NewType) $($NewData)"
}
}
}
#endregion
Write-Host "Processing $($PolicyName) Group Policy Object"
$results = Get-GPO -Name $PolicyName -EA 0
If($? -and $results -ne $Null)
{
#gpo already exists
Write-Host
Write-Host "$(Get-Date): $($PolicyName) exists and will be updated"
Write-Host
}
ElseIf(!($?) -and $results -eq $Null)
{
#gpo does not exist. Create it
$results = New-GPO -Name $PolicyName -EA 0
If($? -and $results -ne $null)
{
#success
Write-Host
Write-Host "$(Get-Date): $($PolicyName) does not exist and will be created"
Write-Host
}
Else
{
#something went wrong
Write-Error "$(Get-Date): Unable to create a GPO named $($PolicyName).`n`nScript cannot continue"
Exit
}
}
Else
{
#error
Write-Error "$(Get-Date): Error verifying if GPO $($PolicyName) exists or not.`n`nScript cannot continue"
Exit
}
Write-Host "$(Get-Date): Read in CSV file"
Write-Host
$Settings = Import-CSV $CSVFile
If($? -and $Settings -ne $Null)
{
#success
Write-Host "$(Get-Date): Setting policy settings"
Write-Host
ForEach($Setting in $Settings)
{
SetPolicySetting $Setting.'Registry Key' $Setting.'Registry Value' $Setting.'Value Type' $Setting.Data
}
}
ElseIf($? -and $Settings -eq $Null)
{
#success but no contents
Write-Warning "$(Get-Date): CSV file $($CSVFile) exists but has no contents.`n`nScript cannot continue"
Exit
}
Else
{
#failure
Write-Error "$(Get-Date): Error importing CSV file $($CSVFile).`n`nScript cannot continue"
Exit
}
Write-Host
Write-Host "$(Get-Date): Successfully created/updated GPO $($PolicyName)"
Write-Host
Get-GPO -Name $PolicyName

Thanks

Webster

8 Comments

  1. Steve

    Hey Carl, this script is excellent. Great way to add 500+ exclusions to Windows Defender configuration via GPO. Thanks, Steve

    • Carl Webster

      Thanks for the shout out. I am glad you find the script as useful as I do.

      Thanks

      Webster

  2. Junz Tan

    Hi Webster,

    Excellent work and script. Actually i am looking for a solution to import the settings from a test GPO into existing GPO (production) and ofcourse it should not remove existing settings, just insert new settings. Is there any way can do that?

    The reason is I want to avoid someone incorrectly or wrongly edit for the existing GPO settings based on new Test GPO settings.

    • Carl Webster

      I have not found a way to do that. I created a test GPO and configured a few settings like event logs and Network List Manager Policies. I then imported the settings from my Lab Defaults GPO, and all that remained in the test GPO were the settings from the Lab Defaults GPO.

      Maybe the GPO PoSH cmdlets from SDM SOftware will allow you to do what you need.

      From the Microsoft docs on the Import Settings Wizard:

      “…Follow the instructions in the Import Settings Wizard to select a GPO backup, import its policy settings to replace those in the destination GPO…”

      Webster

  3. Vivek

    I am new for windows and working on a lab project, and this is very helpful in creating or updating a GPO from CSV. But I have a request, when I executed this script I found that security setting are not imported to new GPO only administrative template got imported. Is there any way to import security settings also

Comments are closed