A few days ago my laptop started greeting me with a black screen and a message I had never seen before. No CPU change, no hardware work, nothing. Just this, on every single reboot:

New CPU installed, fTPM/PSP NV corrupted or fTPM/PSP NV structure changed..
Press Y to reset fTPM, if you have BitLocker or encryption enabled, the system will not boot without
a recovery key
Press N to keep previous fTPM record and continue system boot, fTPM will NOT enable in new CPU, you
can swap back to the old CPU to recover TPM related Keys and data.

I pressed N, and Windows asked me for the BitLocker recovery key. I typed it in, got to the desktop, and the next reboot did the exact same thing. Two days of this.

Fixing the prompt took about ten minutes. Finding out why it happened took a lot longer, and that part was more interesting. This post covers both, with every command I ran and the real output, so you can follow the same trail if it happens to you.

What the message actually means Link to heading

On AMD systems the TPM is usually not a separate chip. It is a firmware TPM (fTPM) running inside the AMD Platform Security Processor (PSP), and it keeps its state in the SPI flash, which is the “NV” (non-volatile) storage in the message.

When the firmware finds that storage corrupted, or its layout changed, it cannot tell the difference from a CPU swap. So it shows the “New CPU installed” text even though nothing physical changed.

Why the recovery key every time? Pressing N keeps the old record but leaves the fTPM disabled for that boot. BitLocker seals its key to the TPM, so with no working TPM it cannot unseal, and it falls back to asking for the recovery key. Press N forever and you type the key forever.

Common reasons for this:

  • A BIOS update that changes the fTPM NV layout
  • BIOS reset to defaults, or a drained CMOS/RTC battery
  • Motherboard replacement
  • The system losing power or hard-resetting while the firmware is writing TPM state (this turned out to be my case)

Part 1: Getting rid of the prompt Link to heading

Step 1: Back up the recovery key first Link to heading

Before touching anything TPM-related, make sure you actually have the recovery key. Check it at aka.ms/myrecoverykey or run:

manage-bde -protectors -get C:

Note the ID under Numerical Password and confirm the same ID shows in your Microsoft account.

Step 2: Suspend BitLocker Link to heading

manage-bde -protectors -disable C: -RebootCount 2

This keeps the drive encrypted but stops BitLocker from demanding the key for the next two reboots.

Step 3: Reboot and press Y Link to heading

This resets the fTPM and creates a fresh one. Everything stored in the old TPM is gone, which means:

  • Windows Hello PIN / fingerprint / face need to be set up again
  • Passkeys stored on the device are lost
  • If it is a work laptop joined to Entra ID / Intune, the device identity is TPM-bound too. Talk to IT before pressing Y.

After boot, check the TPM is healthy:

Get-Tpm

TpmPresent and TpmReady should both be True.

Step 4: Re-bind BitLocker to the new TPM (and the Home edition gotcha) Link to heading

The textbook way is to delete the old TPM protector and add a new one:

manage-bde -protectors -delete C: -type TPM
manage-bde -protectors -add C: -tpm

On my laptop that failed with:

ERROR: An error occurred while deleting the key protector.
This version of Windows does not support this feature of BitLocker Drive Encryption.
To use this feature, upgrade the operating system.

That error means you are on Windows Home. Home does not have full BitLocker, only Device Encryption, and it will not let you manage protectors manually. Check with winver if you are unsure.

What worked on Home was simply resuming protection, which re-seals the key to the current TPM:

manage-bde -protectors -enable C:
Key protectors are enabled for volume C:.

If that had not worked, the fallback is Settings > Privacy & security > Device encryption > Off, wait for full decryption (manage-bde -status C: shows “Fully Decrypted”), then turn it back On. That creates a new recovery key, so confirm the new one is saved to your Microsoft account.

Step 5: Verify Link to heading

Two reboots, no fTPM warning, no recovery screen. Then:

manage-bde -status C:
Volume C: [OS]
    Conversion Status:    Used Space Only Encrypted
    Percentage Encrypted: 100.0%
    Encryption Method:    XTS-AES 128
    Protection Status:    Protection On
    Lock Status:          Unlocked
    Key Protectors:
        Numerical Password
        TPM

Both protectors back: TPM for automatic unlock, Numerical Password as the recovery key. Fixed.

But fixed is not the same as understood. If I did not know what corrupted the fTPM, it could happen again next week.

Part 2: Finding out what actually happened Link to heading

Was it a BIOS update? Link to heading

First suspect. Open msinfo32 and look at BIOS Version/Date on the System Summary page. Mine had no recent change, so that was out.

Unexpected shutdowns Link to heading

Next I checked for unclean shutdowns. Event 41 (Kernel-Power) and 6008 (EventLog) both mean Windows did not shut down cleanly.

Get-WinEvent -FilterHashtable @{LogName='System'; Id=41,6008} -MaxEvents 10 |
  Select TimeCreated, Id, ProviderName | Format-Table -AutoSize
TimeCreated           Id ProviderName
-----------           -- ------------
24-09-2026 04:35:44   41 Microsoft-Windows-Kernel-Power
24-09-2026 04:36:14 6008 EventLog
22-09-2026 13:40:43   41 Microsoft-Windows-Kernel-Power
22-09-2026 13:41:08 6008 EventLog
21-09-2026 12:16:15   41 Microsoft-Windows-Kernel-Power
21-09-2026 12:16:22 6008 EventLog
21-09-2026 11:57:55   41 Microsoft-Windows-Kernel-Power
...

Lots of them. The laptop was on the charger the whole time, so I first assumed a power cut with a weak battery.

What kind of shutdown was it? Link to heading

Event 41 carries useful fields inside its XML. This pulls them out:

Get-WinEvent -FilterHashtable @{LogName='System'; Id=41} -MaxEvents 10 | % {
  $d = ([xml]$_.ToXml()).Event.EventData.Data
  [pscustomobject]@{
    Time        = $_.TimeCreated
    Bugcheck    = ($d | ? Name -eq 'BugcheckCode').'#text'
    PowerButton = ($d | ? Name -eq 'PowerButtonTimestamp').'#text'
    Sleep       = ($d | ? Name -eq 'SleepInProgress').'#text'
  }
} | Format-Table -AutoSize

How to read it:

BugcheckCodePowerButtonTimestampMeaning
00Sudden stop: power loss, hard reset, or thermal trip
non-zeroanyCrash (BSOD). Look up the code
0non-zeroSomeone held the power button

Every row came back 0 / 0 / 0. No crash, no power button, not mid-sleep. But the timestamps on 21 Sep were strange:

Time                Bugcheck PowerButton
----                -------- -----------
21-09-2026 12:16:15 0        0
21-09-2026 11:57:55 0        0
21-09-2026 11:39:30 0        0
21-09-2026 11:21:18 0        0
21-09-2026 11:02:54 0        0
21-09-2026 10:44:21 0        0
21-09-2026 10:25:45 0        0
21-09-2026 10:08:16 0        0

Roughly every 18 minutes, eight times in a row. Power cuts do not keep a schedule. Something on the machine was doing this.

Looking at what happened just before each reset Link to heading

I pulled every power-related event in that window. One tip here: my Windows uses Indian date format (dd-MM-yyyy), so I used ISO dates inside [datetime] to avoid PowerShell reading the day and month the wrong way round.

Get-WinEvent -FilterHashtable @{LogName='System'; StartTime=[datetime]'2026-09-21T09:50:00'; EndTime=[datetime]'2026-09-21T12:30:00'} |
  ? ProviderName -match 'Kernel-Power|Power-Troubleshooter|Processor-Power|ACPI' |
  Select TimeCreated, Id, ProviderName, @{n='Msg';e={($_.Message -split "`n")[0]}} |
  Format-Table -AutoSize -Wrap

Trimmed to one cycle, the pattern looked like this:

21-09-2026 10:08:16  41 Kernel-Power  The system has rebooted without cleanly shutting down first...
21-09-2026 10:22:30 187 Kernel-Power  User-mode process attempted to change the system state by
                                      calling SetSuspendState or SetSystemPowerState APIs.
21-09-2026 10:22:33 187 Kernel-Power  User-mode process attempted to change the system state...
21-09-2026 10:25:45  41 Kernel-Power  The system has rebooted without cleanly shutting down first...

Every cycle was identical:

  1. Boot
  2. About 14 minutes later, two Event 187s: a normal program asking Windows to change power state
  3. About 3 minutes later, the machine is back up after an unclean stop

So a program was requesting a power transition, the transition was failing, and the machine was hard-resetting. Over and over.

Event 187 tells you who did it Link to heading

Event 187 records the calling process. The name is not in the message text, it is in the event data:

Get-WinEvent -FilterHashtable @{LogName='System'; Id=187} -MaxEvents 30 | % {
  $d = ([xml]$_.ToXml()).Event.EventData.Data
  [pscustomobject]@{
    Time = $_.TimeCreated
    Data = ($d | % { "$($_.Name)=$($_.'#text')" }) -join '; '
  }
} | Format-Table -AutoSize -Wrap
21-09-2026 10:22:30 ApiCallerName=\Device\HarddiskVolume3\Windows\System32\DriverStore\FileRepository\
                    asussci2.inf_amd64_ec0a7aca8834d5bc\ASUSOptimization\AsusOptimization.exe;
                    SystemAction=3; LightestSystemState=2

There it was. AsusOptimization.exe, part of the ASUS System Control Interface driver package that comes with MyASUS.

SystemAction=3 is PowerActionHibernate in the Windows POWER_ACTION enum. So the ASUS service was asking Windows to hibernate.

This is where the fTPM connection comes in. Hibernate is one of the moments the firmware saves state, TPM included. Hard-reset the machine in the middle of that, a few dozen times, and a corrupted fTPM NV store is not a surprising result. I cannot prove the exact write that got corrupted, but the timeline fits far better than anything else.

Ruling out the battery Link to heading

The laptop was plugged in, but I still wanted to rule out a charging fault. If the battery was reading critical, ASUS might have been reacting to that.

The HTML battery report was hard to find in Explorer, so I read the XML version straight in PowerShell:

powercfg /batteryreport /xml /output "$env:TEMP\battery.xml" | Out-Null
$b = ([xml](Get-Content "$env:TEMP\battery.xml")).BatteryReport.Batteries.Battery
"Design: $($b.DesignCapacity) mWh | Full charge: $($b.FullChargeCapacity) mWh | Health: {0:N0}%" -f (100*$b.FullChargeCapacity/$b.DesignCapacity)
Design: 61998 mWh | Full charge: 38856 mWh | Health: 63%

Worn, but not dead. Then the usage history around the incident:

$x = [xml](Get-Content "$env:TEMP\battery.xml")
$x.BatteryReport.RecentUsage.UsageEntry |
  ? { $_.LocalTimestamp -like '2026-09-17*' } |
  Select LocalTimestamp, EntryType, Ac,
    @{n='Pct';e={ if ($_.FullChargeCapacity -gt 0) {[math]::Round(100*$_.ChargeCapacity/$_.FullChargeCapacity)} }} |
  Format-Table -AutoSize
LocalTimestamp      EntryType Ac Pct
--------------      --------- -- ---
2026-09-17T06:00:22 Active    1   99

On AC (Ac = 1) at 99%, right in the middle of the ASUS hibernate requests that morning. So the ASUS service was hibernating a fully charged laptop sitting on the charger. Battery and charger ruled out.

I also checked the Windows critical battery action, because it was set to Hibernate:

powercfg /q SCHEME_CURRENT SUB_BATTERY BATACTIONCRIT
    Current AC Power Setting Index: 0x00000002
    Current DC Power Setting Index: 0x00000002

2 = Hibernate. But when Windows itself acts on critical battery, the kernel does it. My Event 187s were a user-mode ASUS process making the call, so this setting was not the trigger.

Was it a bad ASUS driver update? Link to heading

Next obvious suspect: a recent ASUS driver pushed by Windows Update.

Get-WindowsDriver -Online | ? OriginalFileName -like '*asussci2*' |
  Select ProviderName, Version, Date | Format-Table -AutoSize
ProviderName          Version  Date
------------          -------  ----
ASUSTeK COMPUTER INC. 3.1.68.0 04-08-2026 00:00:00
ASUSTeK COMPUTER INC. 3.1.70.0 19-08-2026 00:00:00
ASUSTeK COMPUTER INC. 3.1.66.0 16-06-2026 00:00:00

That Date is the package build date, not when it was installed. The install date comes from the Windows Update log:

Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-WindowsUpdateClient'; Id=19} |
  ? Message -match 'ASUS' | Select TimeCreated, Message | Format-Table -AutoSize -Wrap
31-08-2026 15:02:01 Installation Successful: ... ASUSTeK COMPUTER INC. System Driver Update (3.1.70.0)

Installed 31 Aug. To see whether the problem started then, I counted events per day since August:

Get-WinEvent -FilterHashtable @{LogName='System'; Id=41,187; StartTime=[datetime]'2026-08-01'} |
  Group-Object { '{0:yyyy-MM-dd} ID{1}' -f $_.TimeCreated, $_.Id } |
  Sort Name | Select Name, Count | Format-Table -AutoSize

Summarised:

PeriodASUS hibernate requests (187)Unclean resets (41)
10 Aug to 7 Sep2 to 14 on some days0 to 6
15 Sep83
16 Sep21010
17 Sep4621
21 Sep2411
22 and 24 Sep01 each (the fTPM prompt boots)

This changed my theory. The ASUS hibernate calls started on 10 Aug, three weeks before driver 3.1.70 was installed. So the driver version was not the cause, and rolling it back would not have helped. Some of those earlier hibernates even worked fine: there are days with 187s and no 41s.

What changed is that around 15 to 16 Sep, the requests exploded and the failures piled up.

What changed on 15 September Link to heading

Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-WindowsUpdateClient'; Id=19; StartTime=[datetime]'2026-09-12'; EndTime=[datetime]'2026-09-17'} |
  Select TimeCreated, Message | Format-Table -AutoSize -Wrap

Most of it was Defender definitions and Store app updates. One line stood out:

15-09-2026 08:58:28 Installation Successful: ... 2026-09 Security Update (KB5129195) (26200.9457)

KB5129195 is the out-of-band update Microsoft pushed after the September Patch Tuesday. Among other fixes, it added further protection for CVE-2026-62721, a privilege escalation flaw in the Windows User-Mode Power Service, which could be abused by manipulating the service’s power management requests.

A user-mode process making power requests is exactly what AsusOptimization.exe does. If the hardened power service started handling those hibernate calls differently, it could explain both the retry storm and the failed transitions.

To be honest about it: this is a timing and mechanism match, not proof. I did not find anyone publicly tying this KB to ASUS hibernate problems. And I am not uninstalling a patch that closes a privilege escalation hole to find out. There is a cleaner fix.

Part 3: Making sure it does not happen again Link to heading

The goal is simple: make the failing hibernate impossible, and stop the thing that keeps asking for it.

1. Turn off hibernation Link to heading

powercfg /h off
powercfg /a

With hibernation off, ASUS can call the API all it wants and nothing happens. This also turns off Fast Startup, which honestly is good for BitLocker and TPM stability anyway.

2. Change the critical battery action to a clean shutdown Link to heading

With hibernate disabled, leaving critical battery set to Hibernate is risky. Set it to Shut down (3):

powercfg /setdcvalueindex SCHEME_CURRENT SUB_BATTERY BATACTIONCRIT 3
powercfg /setacvalueindex SCHEME_CURRENT SUB_BATTERY BATACTIONCRIT 3
powercfg /setactive SCHEME_CURRENT

3. Disable the ASUS Optimization service Link to heading

Set-Service -Name ASUSOptimization -StartupType Disabled
Stop-Service -Name ASUSOptimization
Get-Service ASUSOptimization

Test your Fn keys after this (brightness, volume, keyboard backlight). If something you need breaks, set it back to Automatic and rely on step 1 alone.

4. Update BIOS and the ASUS stack Link to heading

Get the latest BIOS, ASUS System Control Interface and AMD chipset driver from the ASUS support page for your model. Suspend BitLocker before any BIOS flash:

manage-bde -protectors -disable C: -RebootCount 1

5. Check back in a week Link to heading

Get-WinEvent -FilterHashtable @{LogName='System'; Id=41,187; StartTime=(Get-Date).AddDays(-7)} -ErrorAction SilentlyContinue |
  Group Id | Select Name, Count

The target is zero 41s. If you kept the ASUS service enabled, a few 187s are harmless now.

What I learned Link to heading

  • The fTPM message lies about the CPU. “New CPU installed” really means “I cannot trust my stored TPM state”. Look for firmware changes or unclean shutdowns, not hardware swaps.
  • Pressing N is not a fix. It just postpones the problem and makes you type the recovery key every boot.
  • Always check the recovery key before touching the TPM. The one time you do not, is the time you need it.
  • Windows Home is different. manage-bde protector management does not work there. Resume protection, or toggle Device Encryption.
  • Event 41 has more to say than “unexpected shutdown”. BugcheckCode, PowerButtonTimestamp and SleepInProgress narrow it down fast.
  • Look at the timing, not just the count. Eight resets 18 minutes apart told me more than any single event.
  • Event 187 names the process. If something is putting your machine to sleep or hibernate, this is where it confesses.
  • Correlation needs a timeline. The ASUS driver looked guilty until the daily counts showed the problem started weeks before it was installed.
  • OEM “optimisation” software runs with a lot of power. It is worth knowing what it is doing on your machine.

Cheat sheet: commands worth keeping Link to heading

BitLocker and TPM Link to heading

# Status and protectors
manage-bde -status C:
manage-bde -protectors -get C:

# Suspend for N reboots / resume
manage-bde -protectors -disable C: -RebootCount 2
manage-bde -protectors -enable C:

# TPM health
Get-Tpm
tpm.msc

# Windows edition (Home cannot manage protectors)
winver

Unexpected shutdowns Link to heading

# Last unclean shutdowns
Get-WinEvent -FilterHashtable @{LogName='System'; Id=41,6008} -MaxEvents 10 |
  Select TimeCreated, Id, ProviderName | Format-Table -AutoSize

# Decode Event 41
Get-WinEvent -FilterHashtable @{LogName='System'; Id=41} -MaxEvents 10 | % {
  $d = ([xml]$_.ToXml()).Event.EventData.Data
  [pscustomobject]@{
    Time        = $_.TimeCreated
    Bugcheck    = ($d | ? Name -eq 'BugcheckCode').'#text'
    PowerButton = ($d | ? Name -eq 'PowerButtonTimestamp').'#text'
    Sleep       = ($d | ? Name -eq 'SleepInProgress').'#text'
  }
} | Format-Table -AutoSize

# Daily count of resets and power-state requests
Get-WinEvent -FilterHashtable @{LogName='System'; Id=41,187; StartTime=(Get-Date).AddDays(-60)} |
  Group-Object { '{0:yyyy-MM-dd} ID{1}' -f $_.TimeCreated, $_.Id } |
  Sort Name | Select Name, Count | Format-Table -AutoSize

Who is putting my machine to sleep? Link to heading

# Event 187 with the calling process
Get-WinEvent -FilterHashtable @{LogName='System'; Id=187} -MaxEvents 30 | % {
  $d = ([xml]$_.ToXml()).Event.EventData.Data
  [pscustomobject]@{
    Time = $_.TimeCreated
    Data = ($d | % { "$($_.Name)=$($_.'#text')" }) -join '; '
  }
} | Format-Table -AutoSize -Wrap

# What is currently blocking sleep / asking for power changes
powercfg /requests
powercfg /lastwake

SystemAction values in Event 187: 2 = Sleep, 3 = Hibernate, 4 = Shutdown, 5 = Restart, 6 = Power off.

Power and battery Link to heading

# Battery health in one line
powercfg /batteryreport /xml /output "$env:TEMP\battery.xml" | Out-Null
$b = ([xml](Get-Content "$env:TEMP\battery.xml")).BatteryReport.Batteries.Battery
"Health: {0:N0}%" -f (100*$b.FullChargeCapacity/$b.DesignCapacity)

# Full HTML report, opened directly
powercfg /batteryreport /output "$env:USERPROFILE\Desktop\battery.html"
start "$env:USERPROFILE\Desktop\battery.html"

# Hibernate on/off and available sleep states
powercfg /h off
powercfg /a

# Critical battery action (0 nothing, 1 sleep, 2 hibernate, 3 shutdown)
powercfg /q SCHEME_CURRENT SUB_BATTERY BATACTIONCRIT

Updates and drivers Link to heading

# Everything Windows Update installed in a date range
Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-WindowsUpdateClient'; Id=19; StartTime=[datetime]'2026-09-01'} |
  Select TimeCreated, Message | Format-Table -AutoSize -Wrap

# All stored versions of a driver package
Get-WindowsDriver -Online | ? OriginalFileName -like '*asussci2*' |
  Select ProviderName, Version, Date

# How far back the System log goes
(Get-WinEvent -LogName System -Oldest -MaxEvents 1).TimeCreated

Got an ASUS laptop? Run this one check Link to heading

This shows whether AsusOptimization.exe has been asking your machine to hibernate or sleep:

Get-WinEvent -FilterHashtable @{LogName='System'; Id=187} -ErrorAction SilentlyContinue |
  ? { $_.ToXml() -match 'AsusOptimization' } |
  Group-Object { $_.TimeCreated.ToString('yyyy-MM-dd') } |
  Select Name, Count | Format-Table -AutoSize

If it returns a list of dates, cross-check them against Event 41. Requests with no matching resets are harmless. Requests followed by resets are the same problem I had, and the fixes in Part 3 apply.

Wrapping up Link to heading

The fix for the prompt was quick: back up the key, press Y, re-seal BitLocker. The real value was in the logs. An ASUS background service had been quietly hibernating my laptop since August, and after mid-September those hibernates started failing and hard-resetting the machine, which is the most likely reason the fTPM state got corrupted.

Next time a machine does something “random”, check Event 41 and Event 187 before blaming the hardware. The answer is usually already sitting in the System log.