HomeNewsletterCommunityMVP FeedToolsArchiveBlogToday's NewsAboutServicesQuick Links★ Pro Subscribe free
← Back to Blog
Windows Hello for Business Windows Hello for BusinessWHfBIntuneRegistryMicrosoft GraphTroubleshooting

Intune Says the Hello Policy Applied. Here Is How to Prove It on the Laptop.

IA
Imran Awan
29 September 2026

You assign a Windows Hello for Business policy in Intune. The console turns green and says Succeeded. Then someone asks you to prove it is actually on the laptop, so you remote in, open the registry where every other Intune CSP policy writes its values, and find nothing at all. No key. Not an empty key. The key does not exist.

At that point most people conclude the policy failed to apply and start troubleshooting delivery. That is the wrong conclusion, and chasing it wastes hours. The policy is almost certainly applied perfectly. It is simply not written where you are looking, because Windows Hello for Business is one of the few CSPs that does not use the standard PolicyManager location. This post shows where it really goes, how to read it three different ways, and how to diff the endpoint against what Intune actually holds so you can answer "is it applied?" with evidence instead of a screenshot of a green tick.

The short version

Windows Hello for Business does not write to PolicyManager\current\device like most CSP policies. It writes to a tenant-scoped path, HKLM\SOFTWARE\Microsoft\Policies\PassportForWork\{TenantId}\Device\Policies, because the CSP node itself contains the tenant GUID. Biometrics settings sit outside that tenant key, and AllowPINLogon is a different CSP again that stores the literal string <disabled/> under a third path and surfaces as AllowDomainPINLogon. Read the device with one PowerShell line, the Intune side across three separate Graph collections, and diff the two. As of the Intune 2607 release you can also collect those registry values natively into Device Inventory with no script at all.

The problem: the key you expect does not exist

Nearly every Intune Settings Catalog policy lands in one of two predictable places on the device. The delivered payload goes under PolicyManager\Providers\{EnrollmentId}, and the value Windows actually enforces appears under PolicyManager\current\device. Learn that pattern once and you can verify almost anything.

So you apply the same pattern to Windows Hello for Business, and this happens.

Windows PowerShell — checking the obvious place
# The location that works for almost every other CSP policy
Test-Path 'HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device\PassportForWork'

False

# Not a permissions problem - the neighbouring keys are all there
Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device' |
    Select-Object -ExpandProperty PSChildName

CredentialProviders
DeviceLock
Update
...
# PassportForWork is simply absent from this list

The user is signed in with Hello. Biometrics work. The PIN honours your minimum length. Everything behaves exactly as configured, and yet the key an experienced admin would check first is not there.

ⓘ Note: An absent PolicyManager\current\device\PassportForWork key is normal for Windows Hello for Business. It is not evidence of a delivery failure, and a detection script that treats it as one will report every healthy device in your fleet as broken.

Why it happens: the CSP node carries the tenant GUID

The registry layout is not arbitrary. It mirrors the CSP node tree almost exactly, and the PassportForWork CSP is unusual in that its policy nodes are scoped per tenant. Microsoft documents the node as:

./Device/Vendor/MSFT/PassportForWork/{TenantId}/Policies/UsePassportForWork

That {TenantId} segment is the whole explanation. Because the tenant GUID is part of the node path, it becomes part of the registry path too. The values land here instead:

HKLM\SOFTWARE\Microsoft\Policies\PassportForWork\{TenantId}\Device\Policies

The same documentation shows that the Biometrics nodes are not tenant-scoped — they sit at PassportForWork/Biometrics/... with no GUID. That asymmetry carries straight through to the registry, which is why a real device shows two sibling trees rather than one.

Registry Editor
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Policies\PassportForWork\{aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee}\Device\Policies
UsePassportForWork REG_DWORD 0x00000001
RequireSecurityDevice REG_DWORD 0x00000001
UseCloudTrustForOnPremAuth REG_DWORD 0x00000001
EnablePinRecovery REG_DWORD 0x00000001
DisablePostLogonProvisioning REG_DWORD 0x00000000
...\Device\Policies\PINComplexity
MinimumPINLength REG_DWORD 0x00000008
...\Device\Policies\ExcludeSecurityDevices
TPM12 REG_DWORD 0x00000001
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Policies\PassportForWork\Biometrics ← no tenant GUID
UseBiometrics REG_DWORD 0x00000001
FacialFeaturesUseEnhancedAntiSpoofing REG_DWORD 0x00000001

The setting that has three different names

There is a second trap hiding in the same Intune policy. Most WHfB profiles also set AllowPINLogon, which is not a PassportForWork setting at all — it belongs to the CredentialProviders area of the Policy CSP. It behaves differently in three ways at once.

First, it controls the legacy convenience PIN for domain users, not the Hello PIN. Microsoft's wording is explicit: it "allows you to control whether a domain user can sign in using a convenience PIN". Turning it off does not disable Windows Hello.

Second, it is an ADMX-backed policy. Those do not store a DWORD. They store the literal string <enabled/> or <disabled/>, which is why a value that reads <disabled/> is correct rather than corrupt.

Third, its ADMX mapping renames it. The CSP calls it AllowPINLogon; the registry value it ultimately drives is AllowDomainPINLogon under Software\Policies\Microsoft\Windows\System. One setting, three names, three locations.

⚠ Gotcha: If you search a device for AllowPINLogon and only look under PassportForWork, you will never find it and may wrongly report the setting as undelivered. Search PolicyManager\Providers for the raw <disabled/> value, and Software\Policies\Microsoft\Windows\System for the resulting AllowDomainPINLogon.

How to verify: three ways to read what landed

1. The one-line check

This walks the whole PassportForWork tree, including the sub-keys, and prints every value with its data. It is the fastest way to answer "did anything arrive?" on a single machine.

Windows PowerShell — read every delivered WHfB value
Get-ChildItem -Recurse 'HKLM:\SOFTWARE\Microsoft\Policies\PassportForWork' |
  ForEach-Object {
      $k = $_
      $k.GetValueNames() | ForEach-Object {
          "{0,-42} = {1}" -f $_, $k.GetValue($_)
      }
  }

DisablePostLogonProvisioning               = 0
UseCloudTrustForOnPremAuth                 = 1
EnablePinRecovery                          = 1
RequireSecurityDevice                      = 1
UsePassportForWork                         = 1
TPM12                                      = 1
MinimumPINLength                           = 8
UseBiometrics                              = 1
FacialFeaturesUseEnhancedAntiSpoofing      = 1

If that returns values, Intune delivered the policy, whatever the console says. If the key does not exist at all, it genuinely did not arrive.

The registry values worth knowing

Every value below lives under this parent key, where the GUID is your own tenant ID:

HKLM\SOFTWARE\Microsoft\Policies\PassportForWork\{TenantId}\Device\Policies\
Value nameHealthy valueIf wrong or missing
UsePassportForWork10 disables Hello entirely; absent means no policy arrived
RequireSecurityDevice10 permits software-backed keys with no TPM protection
UseCloudTrustForOnPremAuth1Absent means Cloud Kerberos Trust is off; on-prem SSO will use a different trust model
EnablePinRecovery10 means a forgotten PIN needs a destructive reset
DisablePostLogonProvisioning01 suppresses the enrolment prompt after sign-in, so users never get asked
PINComplexity\MinimumPINLengthyour standard, e.g. 8Mismatch here is the classic sign of a competing GPO
ExcludeSecurityDevices\TPM1210 allows TPM 1.2 devices to provision
Biometrics\UseBiometrics (no tenant GUID)10 forces PIN only, no face or fingerprint
Biometrics\FacialFeaturesUseEnhancedAntiSpoofing10 weakens face-spoofing protection

2. The device report script

Get-WHfBPolicyOnDevice.ps1 runs all of the above plus the enrolment state, the CredentialProviders values, any competing Group Policy keys, the MDM event history and dsregcmd output, then writes a single report file. It is read-only and needs no credentials.

✅ Tip: Run the report before you change anything, and keep the file. When someone asks in three weeks whether a setting was in place on a given date, a timestamped report answers it instantly.

3. Collect it fleet-wide with no script (Intune 2607 and later)

This is the newest option and the one most people have not noticed yet. Intune's properties catalog can now collect selected registry values into Device Inventory, so you can see WHfB policy state across the estate without deploying a script at all.

  1. Sign in to the Microsoft Intune admin center.
  2. Go to Devices › Windows.
  3. Under Manage devices, select Configuration › Create › New Policy.
  4. Set Platform to Windows 10 and later and Profile type to Properties catalog, then select Create.
  5. Give the profile a name, for example "Inventory — WHfB policy state", and select Next.
  6. Select Add properties, choose the Registry category, and add your PassportForWork key path. Add the PINComplexity and ExcludeSecurityDevices sub-keys as separate entries.
  7. Select Next, set any scope tags, then assign the profile to your Windows device group.
  8. Complete Review + create.
  9. To read the results, go to Devices › Windows, pick a device, and under Tools select Device Inventory.
Devices › Windows › Configuration › Properties catalog

Three limits matter for this use case. Collection is HKLM only, capped at 100 registry keys per device and 6 KB per value, and it is non-recursive — it reads values directly under a key, which is exactly why the two sub-keys need their own entries. Initial collection can take up to 24 hours because the full sync runs once a day.

⚠ Warning: Never "fix" a missing WHfB value by writing it into the registry by hand. These keys are owned by the MDM channel and will be overwritten on the next sync, and you will have hidden the real fault — a bad assignment, a filter, a licensing gap or a GPO conflict — instead of finding it.

The MDM events that tell you whether sync is healthy

Policy that never arrives usually leaves a trail. All of the events below are in one channel:

Event Viewer › Applications and Services Logs › Microsoft › Windows › DeviceManagement-Enterprise-Diagnostics-Provider › Admin
Event IDLevelMeaning
208InformationMDM session started — every scheduled or triggered sync begins with one
404ErrorA CSP command failed. The message names the exact CSP URI, which is how you tell a WHfB failure from an unrelated one
813WarningA setting was queued for retry rather than applied on this pass
819InformationNode value reported back to the service
865ErrorADMX ingestion failed, commonly with 0x80070005 access denied
873InformationADMX ingestion started for an app or policy area
881InformationRoutine PolicyManager activity; high counts here are normal, not a fault
2219InformationConfiguration source processing, logged heavily during a full sync
2900InformationA CSP node was processed during the sync
Event Viewer — DeviceManagement-Enterprise-Diagnostics-Provider/Admin
ⓘ 2026-09-29 08:56:29 Event 208 — MDM session started
ⓘ 2026-09-29 08:56:31 Event 2900 — CSP node processed (PassportForWork)
❌ 2026-09-29 08:56:33 Event 404 — Command failure, CSP URI: .../Policy/Config/Display/ScaleFactor
❌ 2026-09-29 08:56:33 Event 865 — ADMX ingestion failed (0x80070005 access denied)
ⓘ 2026-09-29 08:58:52 Event 208 — MDM session started (next cycle)

Read that carefully, because it is the single most common misreading of this log. Two errors are present, but neither is a WHfB failure — one is a broken display-scaling CSP and the other is an unrelated ADMX ingestion problem. A device can log dozens of Event 404s and still have perfect Hello policy. Always read the CSP URI in the message before attributing a failure.

The fix: diff the device against Intune

Reading the endpoint only tells you half the story. To prove the endpoint matches intent you need the tenant side too, and that is harder than it sounds because WHfB policy does not live in one place in Intune either.

One policy blade, three Graph collections

Depending on how each policy was created, it sits in a different Graph collection:

Graph collectionWhat it holdsWhy it gets missed
deviceManagement/configurationPoliciesSettings Catalog policiesUsually the only one people query
deviceManagement/deviceConfigurationsLegacy templates and custom OMA-URI profilesA custom OMA-URI setting is invisible to a Settings Catalog query
deviceManagement/intentsEndpoint security, including Account ProtectionSeparate API surface again

In a real tenant this bites. A profile setting DisablePostLogonProvisioning through a custom OMA-URI lives in deviceConfigurations, so a script that reads only configurationPolicies reports the setting as "not configured" while the device happily enforces it.

Settings Catalog values are nested several levels deep

The second obstacle is the shape of the data. Settings Catalog does not return flat name and value pairs. Real values hide inside groupSettingCollectionValue → children, and a naive dump returns parent definition IDs that tell you nothing.

Recursive expansion of a Settings Catalog policy
function Expand-SettingInstance {
    param($Instance, [int]$Depth = 0)

    $defId = $Instance.settingDefinitionId

    switch -Wildcard ($Instance.'@odata.type') {
        '*ChoiceSettingInstance' {
            # the chosen option is the definition id plus a suffix
            $val = $Instance.choiceSettingValue.value -replace [regex]::Escape($defId + '_'), ''
            "{0} = {1}" -f $defId, $val
            foreach ($c in $Instance.choiceSettingValue.children) { Expand-SettingInstance $c ($Depth+1) }
        }
        '*GroupSettingCollectionInstance' {
            foreach ($g in $Instance.groupSettingCollectionValue) {
                foreach ($c in $g.children) { Expand-SettingInstance $c ($Depth+1) }
            }
        }
        '*SimpleSettingInstance' {
            "{0} = {1}" -f $defId, $Instance.simpleSettingValue.value
        }
    }
}

Run that against a WHfB policy and the nesting resolves into something you can actually compare against a registry value:

Expanded output
[group] passportforwork_{tenantid}
  passportforwork_{tenantid}_policies_pincomplexity_minimumpinlength = 8
  passportforwork_{tenantid}_policies_enablepinrecovery              = true
  passportforwork_{tenantid}_policies_requiresecuritydevice          = true
  passportforwork_{tenantid}_policies_usepassportforwork             = true
passportforwork_biometrics_facialfeaturesuseenhancedantispoofing     = true

Which source actually won: MDM or Group Policy

Group Policy and Intune can both set the same WHfB values, and by default Group Policy wins. The device records the outcome, which means you never have to guess. Under PolicyManager\current\device\<Area> you get three companion values for an ADMX-backed setting:

Value suffixWhat it tells youHow to read it
_ProviderSetHow many sources configured this settingGreater than 1 means more than one source is competing
_WinningProviderWhich source wonAn enrolment GUID means MDM won; compare it to your Intune enrolment ID
_ADMXInstanceDataWhere the raw delivered payload sitsFollow it to the provider key to see the literal value

To find the competing GPO, check the Group Policy branch directly. It is a different hive path entirely from the MDM one:

HKLM\SOFTWARE\Policies\Microsoft\PassportForWork

If you need to change or remove that GPO, the console path is:

  1. Open Group Policy Management (gpmc.msc) on a management workstation.
  2. Find the GPO linked to the OU containing the affected devices, right-click it and select Edit.
  3. Navigate to Computer Configuration › Policies › Administrative Templates › Windows Components › Windows Hello for Business.
  4. Set the conflicting setting to Not Configured so the MDM value applies.
  5. Run gpupdate /force on a test device and re-read the registry to confirm the MDM value is now in place.
ⓘ Note: GPO winning is not automatically wrong. On a hybrid estate it is extremely common to have a GPO copy that agrees with Intune. The problem is only a disagreement. Treating mere presence as a fault will flag your entire fleet.

Deploy the check as an Intune Remediation

To answer the question across the fleet rather than one laptop, deploy the detection script. Microsoft's documentation is explicit that "a script package can contain a detection script only or both a detection script and a remediation script", which matters here because this check should be detection-only.

  1. Sign in to the Microsoft Intune admin center.
  2. Go to Devices › Manage devices › Scripts and remediations.
  3. Select Create script package and name it, for example "WHfB policy delivery — detect".
  4. On the Settings page, upload Detect-WHfBPolicyDelivery.ps1 as the Detection script file.
  5. Leave the Remediation script file empty.
  6. Set Run this script using the logged-on credentials to No, and Run script in 64-bit PowerShell to Yes.
  7. Select Next, apply any scope tags, then assign to your Windows device group.
  8. Set the schedule to Daily and complete Review + create.
Devices › Manage devices › Scripts and remediations › Create script package

There is deliberately no remediation script. WHfB policy is owned by the MDM channel: anything a script writes gets overwritten at the next sync, and the real fix — assignment, filter, licence or GPO — lives in the service, not on the endpoint. Detection finds the affected devices; you fix the cause centrally.

Two details make the difference between a detection people trust and one they mute. Count only the Event 404s whose CSP URI actually mentions PassportForWork or CredentialProviders, or unrelated ADMX failures will flag healthy machines. And raise an issue only when a GPO value differs from the MDM value, not merely because a GPO exists.

Proof it worked

Here is the comparison script against a real hybrid-joined laptop. Ten settings match across both sides, and the eleventh is a true negative worth understanding.

Compare-WHfBPolicyDeviceVsIntune.ps1
=== Reading WHfB policy from this device ===
  Found 10 WHfB-related value(s) on this device.

=== Reading WHfB policy from Intune ===
  Found 11 WHfB setting(s) configured in Intune.

=== Comparison ===

SETTING                                  STATUS     INTUNE     DEVICE
AllowPINLogon                            MATCH      0          0
DisablePostLogonProvisioning             MATCH      False      0
EnablePinRecovery                        MATCH      true       1
FacialFeaturesUseEnhancedAntiSpoofing    MATCH      true       1
MinimumPINLength                         MATCH      8          8
RequireSecurityDevice                    MATCH      true       1
TPM12                                    MATCH      true       1
UseBiometrics                            MATCH      true       1
UseCloudTrustForOnPremAuth               MATCH      true       1
UsePassportForWork                       MATCH      true       1
enablewebsignin                          MISSING    1          (absent)

  MATCH 10   MISMATCH 0   MISSING 1   EXTRA 0

Note how the normalisation works. Intune reports booleans as true and false; the registry stores 1 and 0. A naive string comparison would report ten mismatches on a perfectly healthy device, so both sides are normalised before comparing.

The MISSING row is not a fault either. enablewebsignin belongs to a separate Web Sign-in policy that this device is not assigned, so it is correctly absent. That is why the output distinguishes MISSING (Intune has it, the device does not) from MISMATCH (both have it, they disagree) — only the second is unambiguously a problem.

The detection script reduces the same picture to one line per device, small enough for Intune's 2,048-character output limit:

Detect-WHfBPolicyDelivery.ps1 — healthy device
OK Computer=LAPTOP-01;PolicyDelivered=Yes;UsePassportForWork=1;MinimumPINLength=8;
CloudTrust=1;RequireSecurityDevice=1;GPOPresent=Yes;NgcSet=YES;
WHfBCsp404Last3d=0;AllCsp404Last3d=24

That single line is the whole argument of this post. GPOPresent=Yes but no conflict, so no issue is raised. AllCsp404Last3d=24 looks alarming until you see WHfBCsp404Last3d=0 next to it — two dozen CSP failures on this machine, none of them WHfB. And NgcSet=YES confirms the policy did not merely arrive, it produced a working Hello credential.

That last distinction matters more than anything else here. Policy delivery and Hello provisioning are separate outcomes. A device can have every value correct and still show NgcSet : NO because the user has not enrolled yet. Check both, and the green tick in the console stops being the thing you have to trust.

PowerShell Scripts — WHfB policy verification

Download these from Imran76Awan/Daily-Tasks — public, no sign-in required. All four are read-only: they read the registry, the event log and Microsoft Graph, and change nothing. The Graph scripts take tenant, client and certificate thumbprint as mandatory parameters and also support device code sign-in. Validate them in your own environment before fleet use.

● Get-WHfBPolicyOnDevice.ps1 — full device-side report across enrolment, registry, GPO, MDM events and dsregcmd
● Compare-WHfBPolicyDeviceVsIntune.ps1 — diffs the device registry against the policy Intune actually holds
● Get-IntuneWHfBPolicy.ps1 — inventories WHfB policy across all three Graph collections, with nested settings expanded
● Detect-WHfBPolicyDelivery.ps1 — Intune Remediation detection script, detection only by design
View all scripts on GitHub

References

Related reading on this site

Microsoft MVP community deep-dives

AuthorPostWhat it adds
Rudy Ooms (MVP)Intune and troubleshooting Settings Catalog profilesWorks through PolicyManager\Providers to establish which provider won a contested setting, and shows a real case where the Settings Catalog wrote a malformed value
Joymalya Basu Roy (MVP)Track Intune MDM policy information on the endpointIndependently documents the same two PolicyManager paths and argues the DeviceManagement-Enterprise-Diagnostics-Provider channel should be the first place you look for delivery failures
Was this post helpful?
React below — no account needed
Share this post
LinkedIn X / Twitter Reddit Bluesky

More from EndpointWeekly

Windows Hello for Business
Event ID 360: Every Prerequisite That Blocks Windows Hello for…
Event 360 in User Device Registration/Admin means WHfB provisioning will not launch.…
Autopilot
Reading AutopilotConfigurationFile.json: Every Documented Field…
Microsoft documents exactly nine properties for AutopilotConfigurationFile.json, and none…
Windows Hello for Business
Windows Hello for Business Not Working on a Hybrid-Joined Device…
WHfB signs in with a PIN but Event 360 keeps firing? This walkthrough traces the real…