HomeNewsletterCommunityMVP FeedToolsArchiveBlogToday's NewsAboutServicesQuick Links★ Pro Subscribe free
← Back to Blog
Group Policy Group PolicyGPOEvent 5312Event 5313Registry.polSYSVOLWindows Hello for BusinessIntuneTroubleshooting

Find Which GPO Sets a Registry Value: Events 5312, 5313 and Registry.pol

IA
Imran Awan
31 October 2026

A policy value keeps turning up on a laptop. You delete it, and it comes back. Every GPO with a matching name has been checked, and none of them sets it. So which GPO does?

I hit this during a Windows Hello for Business migration in a large estate. One Group Policy value held the whole move to Intune back. Two GPOs had "Hello" in their names, and all the work went into them. The value came from neither. It came from a general Windows configuration GPO that nobody had thought to open. This post is the read-only method I now use to find the real owner of a value, without the Remote Server Administration Tools (RSAT) on the laptop.

The short version

Never trust a GPO's name. Find the setting, not the policy. Read events 5312 and 5313 in the Group Policy Operational log to see which GPOs were applied and which were filtered out at each refresh. A GPO in neither list was not in play. Compare the registry key's last write time with the time Group Policy last ran: seconds apart means a GPO is writing the value now. Then search every GPO's Registry.pol in SYSVOL for the value name, and turn the folder GUID into a name through LDAP. Fix the setting inside that GPO. Deleting the value by hand only lasts until the next refresh, which Microsoft puts at every 90 minutes plus a random offset.

The problem: a value nobody owns

The worked example is the Windows Hello for Business setting Minimum PIN length. Intune set one value through the PassportForWork Configuration Service Provider (CSP). The laptop enforced a different value, and that value sat in the Group Policy part of the registry.

For Windows Hello for Business that matters. Microsoft's Configure Windows Hello for Business page lists Group Policy above the PassportForWork CSP in its precedence order. It also says: "If you mix GPO and CSP policy settings, the conflicting CSP settings aren't applied until the group policy settings are cleared." So while a GPO writes this one value, the Intune value for it waits.

This read shows the two values side by side. It only reads.

PowerShell - Group Policy value vs Intune value (illustrative)
# The Group Policy location for Windows Hello for Business settings reg query "HKLM\SOFTWARE\Policies\Microsoft\PassportForWork\PINComplexity" HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\PassportForWork\PINComplexity MinimumPINLength REG_DWORD 0x7 # The CSP location, under your Microsoft Entra tenant ID reg query "HKLM\SOFTWARE\Microsoft\Policies\PassportForWork\{aaaaaaaa-0b0b-1c1c-2d2d-333333333333}\Device\Policies\PINComplexity" HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Policies\PassportForWork\{aaaaaaaa-0b0b-1c1c-2d2d-333333333333}\Device\Policies\PINComplexity MinimumPINLength REG_DWORD 0xa

Illustrative values. The tenant ID is a fictional Microsoft-style placeholder. Microsoft documents the two root keys, SOFTWARE\Policies\Microsoft\PassportForWork for Group Policy and SOFTWARE\Microsoft\Policies\PassportForWork\<Tenant-ID>\Device\Policies for the CSP. The PINComplexity subkey is where I found the PIN values on the laptop I examined.

Good looks like this: the Group Policy key has no MinimumPINLength, and the CSP key holds the value Intune sends. Bad looks like the block above: a value under SOFTWARE\Policies that nobody can explain.

Here is what the team tried first, and why each step failed:

  1. They focused on the GPOs with "Hello" in the name. It turned out that neither one set Minimum PIN length at all.
  2. They denied one of those GPOs to the laptop. Nothing changed, because that GPO was not the source.
  3. They deleted the value by hand. It came back after the next Group Policy refresh. Any "after" evidence taken in that window was void.

The value was coming from a general Windows configuration GPO. In this post I call it Workstation Baseline - General. It carried one Hello setting among a lot of unrelated ones, and its name gave no hint.

Why it happens: a name is a label, Registry.pol is the truth

A Group Policy Object (GPO) is two things. Microsoft's MS-GPREG glossary defines it as "an object that resides in the Active Directory for the domain, and a corresponding file system subdirectory that resides on the sysvol DFS share". The Active Directory object holds the display name. The SYSVOL folder holds the settings.

The display name is free text that a person typed. Microsoft's Get-GPOReport page warns: "The display name is not guaranteed to be unique in the domain." It tells you what someone meant the GPO to do, years ago. It does not tell you what the GPO writes today.

What a GPO writes for Administrative Template settings lives in a registry policy file. MS-GPREG calls it "A file associated with a Group Policy Object (GPO) that contains a set of registry-based policy settings." For computer settings the client reads <gpo path>\Machine\Registry.pol. That file is the only honest answer to "does this GPO set this value?"

Three things make a value hard to trace:

value seen→5312 / 5313: which GPOs ran→key write time vs GP run time→search Registry.pol in SYSVOL→GUID to name, fix that GPO
⚠ Warning: don't delete the value, and don't deploy a script that does. While a GPO still writes it, a later refresh or restart puts it back. An Intune remediation that deletes it would fight Group Policy on every device, every refresh, forever, and the "fixed" reports in between would be false. Find the GPO first.

How to verify: four read-only checks, no RSAT needed

Every check below only reads. You need a domain-joined laptop that can reach a domain controller, and a PowerShell window. If a read returns access denied, use an elevated window. Elevation lets you read more; it doesn't make any of these commands write.

Check 1: which GPOs ran at each refresh (events 5312 and 5313)

The Group Policy service writes a detailed log of every refresh to this log:

Microsoft-Windows-GroupPolicy/Operational

Microsoft's Group Policy troubleshooting guidance says: "Events in this log include the list of applied GPOs and a list of denied GPOs that includes the reasons for the denials." Two event IDs carry those lists:

Event IDWhat it listsWhere this comes from
5312The GPOs the client will process at this refresh.Microsoft: "Event ID 5312 indicates that the Group Policy service detected that it has to process five GPOs on the working computer and three GPOs on the failing computer."
5313The GPOs that were in scope but filtered out, each with a reason.Observed on the laptop I examined. I could not find a Microsoft page that documents event 5313 by number, so treat this row as observation.

This query reads the last few of each. It changes nothing.

PowerShell - read events 5312 and 5313 (output illustrative)
$log = 'Microsoft-Windows-GroupPolicy/Operational' Get-WinEvent -FilterHashtable @{ LogName = $log; Id = 5312, 5313 } -MaxEvents 4 | Select-Object TimeCreated, Id, ActivityId, Message | Format-List TimeCreated : 31/10/2026 09:14:05 Id : 5313 ActivityId : 11111111-2222-3333-4444-555555555555 Message : The following Group Policy objects were not applicable because they were filtered out : Windows Hello for Business - Pilot Denied (Security) TimeCreated : 31/10/2026 09:14:05 Id : 5312 ActivityId : 11111111-2222-3333-4444-555555555555 Message : List of applicable Group Policy objects: Workstation Baseline - General Workstation Security Baseline Default Domain Policy

Illustrative: fictional GPO names and IDs, and the message text shows the shape of these events, not Microsoft's exact wording. Read the real text in your own log.

Read it like this:

Good looks like a short list in 5312 that you can work through. Bad looks like a 5312 list where none of the names relate to your setting. That is not a dead end. It is the normal case, and it is why check 3 exists.

⚠ Gotcha: gpresult and the event log can disagree. On the laptop I examined, gpresult /r /scope computer listed one of the Hello GPOs as filtered with Not Applied (Unknown Reason). No 5312 or 5313 event at any refresh in the log named that GPO at all. Microsoft describes gpresult as showing Resultant Set of Policy (RSoP) data: "the resulting set of policy settings that were enforced on the computer for the specified user when the user signed in". The event log is written at each refresh. When the two disagree, I believe the event log. I am not saying gpresult is always stale; I am saying it was on this device, and the event log was not.

This read-only command prints the RSoP summary for the computer. The misleading part looked like this (illustrative layout, fictional GPO name):

gpresult - the misleading line (illustrative)
gpresult /r /scope computer The following GPOs were not applied because they were filtered out ------------------------------------------------------------------- Windows Hello for Business - Cloud Trust Filtering: Not Applied (Unknown Reason) # The event log never listed this GPO in 5312 or 5313. It was not in scope.

Check 2: is the value live policy or a leftover?

A value under SOFTWARE\Policies is either written by a GPO that still applies, or left behind by something that no longer runs. Two timestamps tell them apart:

  1. When Group Policy last ran. The TimeCreated of the latest 5312 for the computer.
  2. When the registry key was last written. Windows keeps a last write time on every key.

On the laptop I examined, the key's write time landed a few seconds after the refresh started, at two different refreshes. That is not a leftover.

Regedit and Get-ItemProperty don't show the write time. The Win32 function RegQueryInfoKey does, through its lpftLastWriteTime parameter. Microsoft says it receives "the last time that the key or any of its value entries is modified". Note the word "key": the time covers every value in that key, not just yours.

This snippet calls RegQueryInfoKey from PowerShell. It opens the key with the one-argument OpenSubKey, which Microsoft describes as "Retrieves a subkey as read-only", and converts the result with DateTime.FromFileTime, which "Converts the specified Windows file time to an equivalent local time." It changes nothing.

PowerShell - key last write time vs last Group Policy run (output illustrative)
$sig = @' [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] public static extern int RegQueryInfoKey(IntPtr hKey, IntPtr lpClass, IntPtr lpcchClass, IntPtr lpReserved, IntPtr lpcSubKeys, IntPtr lpcbMaxSubKeyLen, IntPtr lpcbMaxClassLen, IntPtr lpcValues, IntPtr lpcbMaxValueNameLen, IntPtr lpcbMaxValueLen, IntPtr lpcbSecurityDescriptor, out long lpftLastWriteTime); '@ Add-Type -Namespace EW -Name RegInfo -MemberDefinition $sig # OpenSubKey with one argument opens the key read-only $path = 'SOFTWARE\Policies\Microsoft\PassportForWork\PINComplexity' $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($path) if ($null -eq $key) { throw "Key not found: HKLM\$path" } [long]$ft = 0 $z = [IntPtr]::Zero $rc = [EW.RegInfo]::RegQueryInfoKey($key.Handle.DangerousGetHandle(), $z, $z, $z, $z, $z, $z, $z, $z, $z, $z, [ref]$ft) $key.Close() if ($rc -ne 0) { throw "RegQueryInfoKey returned $rc" } 'Key last written : {0}' -f [DateTime]::FromFileTime($ft) # The latest Group Policy refresh, from the Operational log $gp = Get-WinEvent -FilterHashtable @{ LogName = 'Microsoft-Windows-GroupPolicy/Operational'; Id = 5312 } -MaxEvents 1 'GP last ran : {0}' -f $gp.TimeCreated Key last written : 31/10/2026 09:14:09 GP last ran : 31/10/2026 09:14:05

Good, for this check, means the answer is clear either way:

If you would rather watch than calculate, use Process Monitor from Microsoft Sysinternals. Microsoft describes it as a tool "that shows real-time file system, Registry and process/thread activity". Filter on the key path, then trigger or wait for a refresh. Each write shows the process, its command line and the time. That also catches a value written by a script or a scheduled task instead of Group Policy.

Check 3: search every GPO's Registry.pol in SYSVOL

Now ignore the names and search the settings. Microsoft's MS-GPREG glossary gives the path of every GPO as:

\\<dns domain name>\sysvol\<dns domain name>\policies\<gpo guid>\Machine\Registry.pol

The Registry Policy File Format page describes what is inside: a header, then entries in the form [key;value;type;size;data]. Microsoft calls it "a text file that consists of a header and a body", so the value name is in there as text and a plain search finds it. The laptop's Group Policy client reads these same files. A normal domain account can usually read them too; if yours gets access denied, ask a directory admin to run the same loop.

This loop reads every Registry.pol, computer and user side, and lists the GPO folders that mention the value name. It only reads files.

PowerShell - which GPO folders contain the value? (output illustrative)
$domain = 'contoso.com' # your Active Directory DNS domain name $value = 'MinimumPINLength' $root = "\\$domain\SYSVOL\$domain\Policies" Get-ChildItem -Path $root -Directory | ForEach-Object { foreach ($side in 'Machine', 'User') { $pol = Join-Path $_.FullName "$side\Registry.pol" if (-not (Test-Path -LiteralPath $pol)) { continue } $bytes = [System.IO.File]::ReadAllBytes($pol) $text = [System.Text.Encoding]::Unicode.GetString($bytes) + [System.Text.Encoding]::ASCII.GetString($bytes) if ($text -match [regex]::Escape($value)) { [pscustomobject]@{ Guid = $_.Name; Side = $side } } } } Guid Side ---- ---- {bbbbbbbb-1c1c-2d2d-3e3e-444444444444} Machine

The loop decodes each file two ways, as UTF-16 and as ASCII, so a match does not depend on the file's text encoding. It reads every GPO in the domain, so expect it to take longer over VPN.

Read the result carefully:

Check 4: turn the GUID into a GPO name

The folder name is the GPO's GUID. Microsoft's MS-GPOL data model says the GPO objects sit "under the LDAP path CN=Policies,CN=System,<DN for root of the domain>", that each one is a groupPolicyContainer, and that "the GUID in the GPO DN and the GPO path MUST be the same". So the SYSVOL folder name is also the object's common name. Its displayName attribute holds the name you see in the console.

Without RSAT, ask LDAP directly. The RootDSE attribute defaultNamingContext "Contains the distinguished name for the domain of which this directory server is a member", so the snippet works in any domain. It reads one attribute and writes nothing:

PowerShell - GPO name from GUID over LDAP (output illustrative)
$guid = '{bbbbbbbb-1c1c-2d2d-3e3e-444444444444}' $dn = ([ADSI]'LDAP://RootDSE').defaultNamingContext $gpo = [ADSI]"LDAP://CN=$guid,CN=Policies,CN=System,$dn" $gpo.displayName Workstation Baseline - General

Good looks like a name. Bad looks like an empty result. Check the GUID for a typo first, then check that the SYSVOL folder has a matching Active Directory object at all.

Where RSAT is installed, for example on an admin server, Get-GPOReport gives the full picture: "details, links, security filtering, Windows Management Instrumentation (WMI) filtering, delegation, and computer and user configurations". Use the GUID, not the name, because the name may not be unique:

PowerShell with RSAT - full report for one GPO
Get-GPOReport -Guid bbbbbbbb-1c1c-2d2d-3e3e-444444444444 -ReportType Html -Path C:\Temp\gpo-report.html

Open the report and find the setting in its Computer Configuration section. In my case it was the only Hello setting in the GPO, and it sat among telemetry and other general settings.

✅ Tip: search all GPOs, not the likely ones. The SYSVOL search costs the same whether you check five GPOs or five hundred. Checking only the GPOs whose names match is exactly how this value stayed hidden. From an admin machine, exporting and keyword-filtering every GPO finds the same thing.

The fix: change the setting inside the GPO that writes it

The fix is one setting in one GPO, not the GPO itself.

  1. First, make sure Intune holds the value you want. The CSP node is ./Device/Vendor/MSFT/PassportForWork/{TenantId}/Policies/PINComplexity/MinimumPINLength. Per Microsoft, the CSP setting applies once the Group Policy setting is cleared.
  2. Open the GPO that check 3 and check 4 named in the Group Policy Management Console, on a machine with RSAT.
  3. Go to the setting. For the example, that is Computer Configuration › Administrative Templates › System › PIN Complexity › Minimum PIN length.
  4. Set it to Not Configured. Leave every other setting in the GPO alone.
  5. Keep the GPO linked and applying. A general baseline carries unrelated settings that must keep working. Don't deny or unlink it to get rid of one value.
  6. Repeat for every other GPO that check 3 found, or the next one in processing order takes over.

Why keep the GPO applying? Because then the Group Policy client sees at its next refresh that the GPO has changed, and processes it again with the setting removed. What exactly happens to a value when a setting goes to Not Configured, and what happens when a whole GPO goes out of scope, is covered in the companion post on the GPO tattooing myth.

This is where the setting lives. It is a simulated view; the path is the one Microsoft lists for Minimum PIN length:

Workstation Baseline - General › Computer Configuration › Administrative Templates › System › PIN Complexity › Minimum PIN length
State: Not Configured
Intune / CSP: ./Device/Vendor/MSFT/PassportForWork/{TenantId}/Policies/PINComplexity/MinimumPINLength
📋 Note: precedence is per setting. Only a value that both Group Policy and Intune set is contested. In my case the general GPO set exactly one Hello value, so that was the only one Intune lost. Before you remove a GPO setting, check that Intune really sets the value you expect, or the device falls back to the Windows default. For Minimum PIN length, Microsoft says that if you "don't configure this policy setting, the PIN length must be greater than or equal to 6." The companion post Group Policy beats Intune, one setting at a time walks through that comparison.

Don't shorten the refresh interval to speed this up. The setting is Computer Configuration › Administrative Templates › System › Group Policy › Set Group Policy refresh interval for computers (CSP: ./Device/Vendor/MSFT/Policy/Config/ADMX_GroupPolicy/GroupPolicyRefreshRate), and Microsoft says shortening it "isn't recommended because of the potential increase in network traffic and more load placed on the domain controllers".

Proof it worked: the value is gone and the GPO still applies

Wait for the next refresh: 90 minutes plus up to 30. On a test device you can start one yourself with gpupdate /target:computer /force. Microsoft says /force "Reapplies all policy settings". That runs policy; it doesn't change any.

Then repeat the reads from the checks above:

PowerShell - after the fix (illustrative)
# 1. The Group Policy value is gone $gpKey = 'HKLM:\SOFTWARE\Policies\Microsoft\PassportForWork\PINComplexity' $v = Get-ItemProperty -Path $gpKey -Name MinimumPINLength -ErrorAction SilentlyContinue if ($null -eq $v) { 'Group Policy MinimumPINLength: absent' } else { 'Group Policy MinimumPINLength: ' + $v.MinimumPINLength } Group Policy MinimumPINLength: absent # 2. The GPO still applies, so its other settings are safe (Get-WinEvent -FilterHashtable @{ LogName = 'Microsoft-Windows-GroupPolicy/Operational'; Id = 5312 } -MaxEvents 1).Message List of applicable Group Policy objects: Workstation Baseline - General Workstation Security Baseline Default Domain Policy

Check four things:

  1. The Group Policy value is absent. If it is still there, another GPO writes it. Run the SYSVOL search again.
  2. The GPO is still in the 5312 list. You fixed one setting without taking out the rest of the baseline.
  3. It stays gone across two refreshes. Read it again after the next cycle. A value that returns means a second writer, a script or a task. Process Monitor will name it.
  4. The CSP value is the one in force. Read the CSP key from the first block. It should hold the value Intune sends, with nothing under SOFTWARE\Policies to contest it.

References

Related reading on EndpointWeekly

The method and the observations in this post (the gpresult mismatch, the write times seconds after a refresh, the value returning after a manual delete) come from one enterprise laptop in a large estate. All names, GUIDs, values and times shown are fictional. Microsoft facts were checked against the pages above on 31 October 2026.

Was this post helpful?
React below — no account needed
Share this post
LinkedIn X / Twitter Reddit Bluesky

More from EndpointWeekly

Group Policy
GPO Tattooing Myth: Administrative Templates, Not Configured and…
A value blamed on a denied GPO was being rewritten by a live one. What tattooing really…
Windows Hello for Business
Windows Hello for Business: Why Group Policy Beats Intune, One…
Intune says the Hello setting applied, but the device follows Group Policy. Microsoft's…
Windows Hello for Business
Move Windows Hello for Business Policy from Group Policy to…
Move Windows Hello for Business policy from Group Policy to Intune: find every GPO that…