HomeNewsletterCommunityMVP FeedToolsArchiveBlogToday's NewsAboutServicesQuick Links★ Pro Subscribe free
← Back to Blog
Windows Hello for Business Windows Hello for BusinessEvent 4625Event 7001NTSTATUScertutilSecurity logReporting

Windows Hello for Business sign-in failures: reading event 7001, 4625 and their codes

IA
Imran Awan
31 October 2026

A fleet report said nearly four in ten laptops had "Windows Hello failures". It sounded like an outage. Most of it was people typing their PIN wrong.

The report was not lying. It counted devices with at least one Windows Hello for Business (WHfB) error event. That is a real number. It just answers the wrong question. This post shows where Hello sign-in failure data comes from, how to decode the codes without guessing, and how to report numbers that survive the question "what does that mean?".

The short version

Two events matter. Event 7001 in Microsoft-Windows-HelloForBusiness/Operational records a Hello sign-in error and, on the devices I examined, a status code. Event 4625 in the Security log says a sign-in really failed, with a Status and Sub Status. Decode every code with certutil -error and Microsoft's NTSTATUS list. The most common one, 0xC0000380 STATUS_SMARTCARD_WRONG_PIN, is a mistyped PIN, not a fault. Count devices with real failed sign-ins and repeated failures. Always state how many days of Security log each device held, because the log is size-limited and overwrites itself.

The problem: "Hello failures" is mostly mistyped PINs

The usual fleet query is simple. Look for Hello error events on each device in the last 30 days. Flag the device if there is at least one. Divide by the number of devices.

That gives a big, scary percentage. Here is what the same estate looks like when you ask sharper questions. The numbers are invented for this post.

Question (illustrative fleet of 10,000 devices)DevicesWhat it really means
At least one Hello event 7001 in the window3,900Someone had a Hello sign-in error once. Mostly wrong PINs.
At least one real failed sign-in (Security 4625)260Windows refused a sign-in at least once. Still includes typos.
More than 10 failed sign-ins in the window14A user who keeps failing. This is the list to work.
Security log covers the full 30 days3,100Only these devices can be counted for the whole window.

Illustrative numbers only. They show the shape of the problem, not any real estate.

The first row is the one that reaches leadership, as "39% of devices have a Hello fault". The third row is the one a service desk can act on. Fourteen laptops is a work queue. Thirty-nine per cent is a panic.

The last row is the trap nobody prints. If a device holds only 16 days of Security log, its "30-day" count is really a 16-day count. Every number above it is an undercount, by a different amount on every device.

Why it happens: two logs answer two different questions

Hello sign-in data sits in two places. They are written by different parts of Windows and they mean different things.

PIN or biometric entered→7001: did Hello hit an error?→4625: did Windows refuse the sign-in?→decode the code, then count

Ask both questions. A 7001 on its own does not tell you the user was kept out.

Event 7001: Hello reports an error

Event 7001 is written to Applications and Services Logs › Microsoft-Windows-HelloForBusiness › Operational. Microsoft shows it in its article on Hello sign-in failures on captive-portal Wi-Fi, next to a 4625. Its example has Task Category Logon, Level Error, and two fields: Credential Type (Software Key) and Deployment Type (Cloud).

I could not find a Microsoft field-by-field reference for 7001. On the laptops I examined, it also carried a status code saying why Hello's part of the sign-in did not succeed. Treat that as an observation, and read the event XML on your own build before you parse it.

The key point: a 7001 does not mean the user could not sign in. On the laptops I examined, a user who typed the PIN wrong, then right, got a 7001 and a desktop.

Event 4625: Windows refused the sign-in

Event 4625 is in the Security log. Microsoft's 4625 reference says: "This event is logged for any logon failure." It is written on the device where the attempt was made, so a laptop logs its own failures. Three fields do the work:

For the meaning of the codes, the same page points to Microsoft's NTSTATUS Values page, part of MS-ERREF. That is the name list I use below.

📋 Note: don't trust the Failure Reason text. Microsoft's captive-portal article shows a 4625 with Failure Reason "Unknown user name or bad password" and Status 0xC000005E. The 4625 page describes that code as "There are currently no logon servers available to service the logon request." The cause was the network, not the password. Read the Status code, not the sentence next to it.

The codes, decoded

These codes dominated the Hello data on the estate I worked on. Each name and description is copied from Microsoft's NTSTATUS Values page.

CodeMicrosoft nameMicrosoft descriptionPlain English, and owner
0xC0000380STATUS_SMARTCARD_WRONG_PIN"An incorrect PIN was presented to the smart card."The user typed the PIN wrong. Not a fault, unless it repeats.
0xC0000072STATUS_ACCOUNT_DISABLED"The referenced account is currently disabled and cannot be logged on to."The account is switched off. Identity team.
0xC000023CSTATUS_NETWORK_UNREACHABLE"The remote network is not reachable by the transport."No usable network at sign-in. Network team, or retry.
0xC0000321STATUS_SMARTCARD_SUBSYSTEM_FAILURE"The Kerberos protocol encountered an error while attempting to use the smart card subsystem."The sign-in key path broke. Rare. Needs hands-on triage.

Why smart card names appear when there is no smart card

Two of those four names say "smart card". The laptops had no smart card reader.

Microsoft's Windows Hello for Business FAQ gives the background. It describes "Windows Hello for Business used as a smart card (smart card emulation that is enabled by default)", and says: "The smart card emulation feature of Windows Hello for Business verifies the PIN and then discards the PIN in exchange for a ticket."

The authentication flow page shows the same resemblance. With key trust, the Kerberos provider sends the user's public key "(in the form of a self-signed certificate)" to the domain controller. That is certificate-style sign-in, the kind a smart card does.

What Microsoft does not say, anywhere I could find, is which status a wrong Hello PIN produces. On the devices I examined, it was 0xC0000380 STATUS_SMARTCARD_WRONG_PIN. Treat that as observed. Confirm it by typing a wrong PIN on a test laptop and reading the events.

⚠ Gotcha: "smartcard" in a code name is not a hardware fault. Don't send these devices for a card reader check. 0xC0000380 is a typo. 0xC0000321 is the one smart card code worth a closer look.

Codes that do not decode

Some 7001 codes will not decode. certutil -error returns no name, and the value is not on the NTSTATUS page. On the estate I worked on, a few codes behaved like this.

Don't invent a meaning. A guessed name in a report gets repeated, then believed, then acted on. Write "does not decode" and treat it as a question for Microsoft. The fix section says what to send.

How to verify: read, decode and date the evidence on one device

Start with one device. Everything here only reads. Run PowerShell as an administrator: Microsoft's Get-WinEvent page warns, "If you're not running PowerShell as an Administrator, you might see error messages that you can't retrieve information about a log."

Step 1: read the Hello events

This prints the last five 7001 events as raw XML, so you can see where the status code sits on your build. It queries by log name and event ID, not by the Source text.

PowerShell - read Hello event 7001, read-only
$filter = @{ LogName = 'Microsoft-Windows-HelloForBusiness/Operational'; Id = 7001 } Get-WinEvent -FilterHashtable $filter -MaxEvents 5 -ErrorAction Stop | ForEach-Object { $_.TimeCreated; $_.ToXml() }

Good looks like: a few events, around times the user signed in. Bad looks like: dozens a day, or the same code on every event for a week. If the command errors, read the error. A log you could not read is not a log with nothing in it.

Step 2: read the real failures

This reads 4625 events from the last 30 days and pulls out the fields that matter. The names Status, SubStatus, LogonType and TargetUserName come from the event XML on Microsoft's 4625 page.

PowerShell - read Security 4625, read-only, elevated
$filter = @{ LogName = 'Security'; Id = 4625; StartTime = (Get-Date).AddDays(-30) } Get-WinEvent -FilterHashtable $filter -ErrorAction Stop | ForEach-Object { $d = @{} foreach ($n in ([xml]$_.ToXml()).Event.EventData.Data) { $d[$n.Name] = $n.'#text' } [pscustomobject]@{ Time = $_.TimeCreated; LogonType = $d['LogonType'] Status = $d['Status']; SubStatus = $d['SubStatus']; User = $d['TargetUserName'] } } | Format-Table -AutoSize
Example output (illustrative)
Time LogonType Status SubStatus User ---- --------- ------ --------- ---- 28/10/2026 08:41:07 2 0xc000005e 0x0 avery.lee 14/10/2026 09:15:12 2 0xc0000072 0x0 jordan.kim

Illustrative, for fictional users on a fictional device (DESKTOP-A1B2C3). The first row copies the Status pair from Microsoft's captive-portal example. There is no wrong-PIN row, because I could not find Microsoft documentation of the Status pair it carries. Read your own.

Good looks like: nothing, or a couple of rows on different days. Bad looks like: many rows for one user, or a Status that is not a typo. Check both Status and Sub Status: Microsoft's monitoring table on the 4625 page looks for codes in either field.

Step 3: decode every code, never guess

Microsoft's certutil reference describes -error as: "Displays the message text associated with an error code." The syntax is certutil [options] -error ErrorCode. It looks up text and touches nothing else.

Command Prompt - decode a status code (illustrative output)
certutil -error 0xC0000380 0xc0000380 (NT: 0xc0000380 STATUS_SMARTCARD_WRONG_PIN) -- 3221226368 (-1073740928) Error message text: An incorrect PIN was presented to the smart card. CertUtil: -error command completed successfully.

Illustrative. The layout of certutil's output can vary between builds. The name and text match Microsoft's NTSTATUS Values page.

Good looks like: a symbolic name and a message. Check the name against the NTSTATUS page. Bad looks like: no symbolic name, only the number repeated back. That code does not decode. Write that down. Do not fill the gap.

✅ Tip: decode once, then keep a lookup table. Decode each distinct code, copy the Microsoft name and description into a small table, and join your fleet data to it. Ten codes can cover thousands of events, and nobody has to remember what 0xC000023C means.

Step 4: date the evidence

A count only means something if you know how far back the log goes. This reads the Security log's size limit and mode, and the time of its oldest event.

PowerShell - how many days does the Security log hold? read-only, elevated
Get-WinEvent -ListLog Security | Select-Object LogMode, MaximumSizeInBytes, FileSize, RecordCount $oldest = Get-WinEvent -LogName Security -MaxEvents 1 -Oldest -ErrorAction Stop "Oldest: {0} Days held: {1:N1}" -f $oldest.TimeCreated, ((Get-Date) - $oldest.TimeCreated).TotalDays
Example output (illustrative)
LogMode MaximumSizeInBytes FileSize RecordCount ------- ------------------ -------- ----------- Circular 20971520 20975616 41237 Oldest: 13/10/2026 07:58:31 Days held: 18.2

Good looks like: days held at least as long as your reporting window. Bad looks like: Circular, a file at its maximum size, and fewer days than the window. That device has already overwritten part of your reporting period.

Microsoft's Policy CSP page says the Security log size "defaults to 20 megabytes". When a log is full and the retention setting is not configured, "new events overwrite old events". On the laptops I examined, most held less than 30 days.

⚠ Warning: a wrong PIN is not a reason to reset Hello. Don't answer 0xC0000380 with certutil -deletehellocontainer. Microsoft's FAQ warns that on the latest Windows 11 versions it "clears not only Windows Hello for Business, but also any passkeys stored on that Windows device". The user loses PIN, biometrics and passkeys to fix a typo. For a real fault it is a manual, one-device step with the user present. Never run it from an unattended remediation.

The fix: count failures, not events, and state the retention

Nothing on the devices needs changing. The report does.

1. Define each number before you count it

Report lineDefinitionUse it for
Devices with Hello errorsAt least one 7001 in the windowContext only. Never a fault rate.
Devices with a real failed sign-inAt least one 4625 with Logon Type 2, 7 or 11The user-facing problem, typos included.
Devices with repeated failuresMore than 10 such 4625 events (pick your threshold and print it)The work queue.
Failures by decoded codeGrouped by code, joined to the Microsoft nameRouting: identity, network, service desk or Microsoft.
Days of Security log heldNow minus the oldest Security event, per deviceThe caveat on every line above.

Why more than 10? Microsoft's FAQ says that after three wrong PINs "the credential provider will display the following message" asking for a challenge phrase, and that continued failures lead to longer lockouts. A user who fails more than 10 times in a month is struggling with the PIN or hitting a real fault. Both deserve a call.

2. Collect one line per device

This read-only snippet collects the per-device facts in one line. Run it elevated or as SYSTEM through the tool you already use, such as an Intune remediation detection script, and parse the line centrally.

PowerShell - per-device sign-in summary, read-only
$windowDays = 30 $since = (Get-Date).AddDays(-$windowDays) function Get-EventsOrNone($filter) { try { @(Get-WinEvent -FilterHashtable $filter -ErrorAction Stop) } catch { # On the devices I tested, "nothing matched" raised NoMatchingEventsFound. # Anything else is a real read failure: rethrow, never count it as zero. if ($_.FullyQualifiedErrorId -like 'NoMatchingEventsFound*') { @() } else { throw } } } try { $oldest = Get-WinEvent -LogName Security -MaxEvents 1 -Oldest -ErrorAction Stop $held = [math]::Round(((Get-Date) - $oldest.TimeCreated).TotalDays, 1) $fails = Get-EventsOrNone @{ LogName = 'Security'; Id = 4625; StartTime = $since } | Where-Object { (([xml]$_.ToXml()).Event.EventData.Data | Where-Object Name -eq 'LogonType').'#text' -in '2', '7', '11' } $hello = Get-EventsOrNone @{ LogName = 'Microsoft-Windows-HelloForBusiness/Operational'; Id = 7001; StartTime = $since } # On the builds I examined, the 7001 code appears as hex in the message. Check yours (step 1). $codes = $hello | ForEach-Object { if ($_.Message -match '0x([0-9A-Fa-f]{8})') { '0x' + $Matches[1].ToUpper() } } | Group-Object | Sort-Object Count -Descending | ForEach-Object { "$($_.Name)x$($_.Count)" } "SIGNIN window={0}d held={1}d fail4625={2} ev7001={3} codes={4}" -f $windowDays, $held, @($fails).Count, @($hello).Count, ($codes -join ',') } catch { "SIGNIN-ERROR $($_.Exception.Message)" } exit 0
Example output from three devices (illustrative)
SIGNIN window=30d held=18.2d fail4625=2 ev7001=9 codes=0xC0000380x9 SIGNIN window=30d held=41.0d fail4625=0 ev7001=1 codes=0xC000023Cx1 SIGNIN window=30d held=11.6d fail4625=23 ev7001=27 codes=0xC0000380x21,0xC0000321x6

Illustrative. Three fictional devices.

The first is a user who mistypes now and then. The second had one sign-in with no network. The third is the one to call: 23 real failures in under 12 days of log, and six 0xC0000321 codes as well as typos. Scaled to 30 days, that is about 60 failures. A fixed "30-day" label would hide it.

3. Give the Security log enough room

If most devices hold less than your reporting window, raise the Security log size. It is a policy change, so use your normal change process. It does not touch Hello.

Computer Configuration › Administrative Templates › Windows Components › Event Log Service › Security › Specify the maximum log file size (KB)
State: Enabled
Maximum log size (KB): enough to hold your reporting window on your busiest devices
CSP: EventLogService/SpecifyMaximumFileSizeSecurityLog

Simulated view. Path and setting name are from Microsoft's EventLogService Policy CSP page. Size the value from your own "days held" data.

4. Send the codes that do not decode to Microsoft

A code that neither certutil -error nor the NTSTATUS page can name is Microsoft's to explain. Open a Microsoft support case. Include:

  1. The code exactly as logged, and how you tried to decode it.
  2. The full 7001 XML from one affected device (step 1), and any 4625 at the same time.
  3. The build (CurrentBuild and UBR) of affected and unaffected devices.
  4. The pattern: does the share of affected devices change with build, trust model or network? Call it a correlation, not a proven cause.

Until Microsoft answers, report the code as "does not decode, case open". That line is honest, and reviewers respect it.

Proof it worked: a report that survives the first question

Rebuild the report with the definitions above. It should look like this. Every number is invented.

Line (illustrative)ValueNote printed with it
Devices reporting10,000Window: 30 days
Devices with a real failed sign-in2604625, Logon Type 2, 7 or 11
Devices with more than 10 failures14Work queue, sent to the service desk
Top code0xC0000380 STATUS_SMARTCARD_WRONG_PINMistyped PIN. Not a fault.
Account disabled22 devices0xC0000072, sent to the identity team
Codes that do not decode1 code, 40 devicesMicrosoft case open
Median days of Security log held1669% of devices hold less than 30 days. All counts are undercounts.

Illustrative numbers only.

Test it the way a sceptical manager would:

  1. Every number has a definition next to it. Nobody can read "260" as a fault rate.
  2. Every code has a Microsoft name, or says it has none. No line says "probably TPM".
  3. The retention caveat is in the same table.

Then spot-check the work queue. Pick two devices from the "more than 10 failures" list and run steps 2 and 3 on them by hand. Their 4625 events should match the report. If they don't, fix the query before anyone acts on the list.

For the 0xC000023C devices, the companion post on "credentials could not be verified" covers the network-not-ready pattern.

References

Related reading on EndpointWeekly

Microsoft facts were checked against the pages above on 31 October 2026. The wrong PIN as 0xC0000380 and the 7001 status code are observations from enterprise laptops, not Microsoft documentation. Everything marked illustrative is invented data.

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

More from EndpointWeekly

Windows Hello for Business
WHfB "Your credentials could not be verified": two causes, one…
One Hello sign-in error, two unrelated causes: a network that is not ready yet, or a key…
Windows Hello for Business
AADSTS130004: the Hello key works on the laptop but is missing…
Every device check passes, yet Hello sign-in fails days later with AADSTS130004. Why…
Windows Hello for Business
Check Windows Hello for Business Keys in Entra ID With Microsoft…
NgcSet : YES only proves the laptop has a Hello key. Read the cloud half with Microsoft…