Cleaning up corrupt Registry.pol files with Powershell
One ongoing issue that can occur across an predominately Windows/Group Policy heavy enterprise environment is the corruption of the Registry.pol file located in %windir%\system32\Group Policy\Machine\. This file contains all the machine-based Group Policy settings in Registry format and are loaded at Operating System startup.
For reasons not even known by Microsoft it seems, this file can occasionally get corrupt and centrally defined Group Policies are no longer updated/kept in sync.
So in a effort to be able to clean up such a corruption at scale, I created a Powershell script that:
- Takes a array of machines as input
- Confirms they are reachable over the network
- Confirms that it has permissions to the location of Registry.pol
- Check the Date Modified tag of the file and if older than 1 day (good sign of corruption), delete the file and force a Group Policy refresh
One of the caveats to this process was while there a many more cmdlets in Powershell V3+ that I could leverage, it still had to support Windows 7 machines at the time of writing and therefore leverage much less cleaner ways to kick of a Group Policy refresh.
Without further ado…
<# | |
.Synopsis | |
Clean up machines with bad (old/corrupt) machine Registry.pol files | |
.DESCRIPTION | |
Taking a array as input, this cmdlet assists in keeping machines in a healthy state to accept Group Policy driven changes | |
by confirming the last modified date of the machines Registry.pol and if older than a day , remove it, (or doesn't exist) | |
followed by a forced Machine Policy update. | |
To work against older WMF/Powershell environments, invoke-command + invoke-gpupdate have been avoided. | |
.EXAMPLE | |
Repair-RegistryPol -Computers workstation1,workstation2 | |
.EXAMPLE | |
Repair-RegistryPol -Computers (Import-Csv lotsofworkstations.csv) | |
.NOTES | |
Version: 1.0 | |
Author: James Pettigrove | |
#> | |
[CmdletBinding()] | |
Param ( | |
[Parameter(Mandatory=$True,Position=0)] | |
$Computers | |
) | |
foreach ($computer in $Computers) | |
{ | |
if (Test-NetConnection -ComputerName $computer -Hops 1 -InformationLevel Quiet -ErrorAction SilentlyContinue -WarningAction SilentlyContinue) | |
{ | |
if (Test-Path -Path \\$computer\c$\Windows\System32\GroupPolicy\Machine\Registry.pol -ErrorAction SilentlyContinue -WarningAction SilentlyContinue) | |
{ | |
$regpol= Get-Childitem \\$computer\c$\Windows\System32\GroupPolicy\Machine\Registry.pol | |
if ($regpol.LastWriteTime -lt (get-date).AddDays(-1)) | |
{ | |
Write-Host "$computer Registry.pol file is old ("$regpol.LastWriteTime"), deleting and forcing a GPUpdate" -ForegroundColor Magenta | |
Remove-Item $regpol | |
Invoke-WmiMethod -Name create -Path win32_process -ArgumentList "gpupdate /target:Computer /force /wait:0" -AsJob -ComputerName $computer | out-null | |
} | |
else | |
{ | |
Write-Host "$computer Registry.pol file is healthy ("$regpol.LastWriteTime")" -ForegroundColor Green | |
} | |
} | |
elseif (Test-Path -Path \\$computer\c$\Windows\System32\GroupPolicy\Machine\ -ErrorAction SilentlyContinue -WarningAction SilentlyContinue) | |
{ | |
Write-Host "$computer doesn't have a Registry.pol file, forcing a GPUpdate" -ForegroundColor Magenta | |
Invoke-WmiMethod -Name create -Path win32_process -ArgumentList "gpupdate /target:Computer /force /wait:0" -AsJob -ComputerName $computer | out-null | |
} | |
else | |
{ | |
Write-Warning "$computer does not have c:\Windows\System32\GroupPolicy\Machine\ or you don't have access" | |
} | |
} | |
else | |
{ | |
Write-Warning "Unable to find or contact $computer" | |
} | |
} |
Would love to see what improvements the readers out there could make. Maybe make use of job batching to do it in a much more parallel fashion? Let me know if you do give it a try in your environment.