Skip to content

Instantly share code, notes, and snippets.

@asheroto
Last active August 1, 2026 21:35
Show Gist options
  • Select an option

  • Save asheroto/5087d2a38b311b0c92be2a4f23f92d3e to your computer and use it in GitHub Desktop.

Select an option

Save asheroto/5087d2a38b311b0c92be2a4f23f92d3e to your computer and use it in GitHub Desktop.
Bypass Windows 11 Upgrade Assistant / PC Health Check / TPM and CPU Settings. Ignore PC Health Check results.

Bypass Windows 11 Upgrade Assistant / Setup Hardware Checks (TPM, CPU, RAM)

This PowerShell script allows you to bypass TPM 2.0, unsupported CPU, and memory checks enforced by the Windows 11 Upgrade Assistant and setup.exe from Windows installation media. It eliminates common upgrade blocks such as:

  • This PC doesn't currently meet Windows 11 system requirements.
  • TPM 2.0 must be supported and enabled on this PC.
  • The processor isn't currently supported for Windows 11.

What It Does

This script:

  • Deletes legacy upgrade failure registry keys that may block future attempts.
  • Simulates hardware compatibility by setting known override values (e.g., TPM, RAM, Secure Boot).
  • Enables Microsoft's official upgrade bypass by setting AllowUpgradesWithUnsupportedTPMOrCPU to 1.
  • Enables Upgrade Assistant to proceed by setting UpgradeEligibility to 1 under the current user.

Registry Keys Modified or Removed

Purpose Registry Path Action / Value
Clear upgrade failure flags HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\CompatMarkers Deleted (if exists)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Shared Deleted (if exists)
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\TargetVersionUpgradeExperienceIndicators Deleted (if exists)
Simulate compatibility HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\HwReqChk HwReqChkVars = MultiString (TPM, RAM, etc.)
Bypass TPM/CPU check HKLM\SYSTEM\Setup\MoSetup AllowUpgradesWithUnsupportedTPMOrCPU = 1
Enable Upgrade Assistant flow HKCU\Software\Microsoft\PCHC UpgradeEligibility = 1

How to Use

Option 1: Save and Execute Locally

  1. Save the script as: Windows11-Enable-Upgrade.ps1

  2. Open PowerShell as Administrator.

  3. Run the script:

.\Windows11-Enable-Upgrade.ps1

Option 2: Run Directly from the Web

  1. Click the "Raw" button at the top right of the script to view it as plain text.

  2. Copy the full Raw URL from your browser’s address bar.

  3. In Administrator PowerShell, run:

irm "<paste raw url here>" | iex

✅ This lets you execute the script immediately without saving it to disk.


Disclaimer

This script is provided as-is with no warranties. Use only in test environments, labs, or situations where your device policy allows. Bypassing Windows hardware requirements may result in reduced support, compatibility issues, or failed future updates. Proceed at your own risk.

<#
.SYNOPSIS
Bypasses Windows 11 hardware requirements for in-place upgrades.
.DESCRIPTION
This script modifies specific registry values to override system compatibility checks performed during
Windows 11 upgrades. It removes legacy upgrade failure entries, simulates compatible hardware state,
enables Microsoft's documented bypass policy for unsupported TPM or CPU configurations, and sets the
UpgradeEligibility flag required by the Windows 11 Upgrade Assistant.
This is intended for lab, evaluation, or controlled environments where hardware policy allows.
.NOTES
Author: asheroto
Source: https://gist.github.com/asheroto/5087d2a38b311b0c92be2a4f23f92d3e
Required: Run as Administrator
.LICENSE
Use at your own risk. No warranty expressed or implied.
#>
function Write-Section {
<#
.SYNOPSIS
Displays a section header with borders using Write-Host and optional color.
.DESCRIPTION
Prints multi-line text surrounded by a hash border for readability.
Supports output coloring via the Color parameter.
.PARAMETER Text
The text to display. Can include multiple lines.
.PARAMETER Color
(Optional) The color to use for the text and border. Defaults to White.
.EXAMPLE
Write-Section -Text "Starting Process"
.EXAMPLE
Write-Section -Text "Line 1`nLine 2" -Color Green
#>
param (
[Parameter(Mandatory)]
[string]$Text,
[string]$Color = "White"
)
$lines = $Text -split "`n"
$maxLength = ($lines | Measure-Object -Property Length -Maximum).Maximum
$border = "#" * ($maxLength + 4)
Write-Host ""
Write-Host $border -ForegroundColor $Color
foreach ($line in $lines) {
Write-Host ("# " + $line.PadRight($maxLength) + " #") -ForegroundColor $Color
}
Write-Host $border -ForegroundColor $Color
Write-Host ""
}
function Set-RegistryValueForced {
<#
.SYNOPSIS
Adds or updates a registry value with error handling.
.DESCRIPTION
Creates the specified registry key if it does not exist and sets the provided value.
Supports String, DWord, QWord, Binary, and MultiString types.
Outputs an error message if the operation fails.
.PARAMETER Path
The full registry path (e.g., HKLM:\Software\Example).
.PARAMETER Name
The name of the registry value to create or update.
.PARAMETER Type
The type of the registry value (String, DWord, QWord, Binary, MultiString).
.PARAMETER Value
The value to set. For MultiString, provide an array of strings.
.EXAMPLE
Set-RegistryValueForced -Path "HKLM:\Software\Test" -Name "TestValue" -Type String -Value "OK"
.EXAMPLE
Set-RegistryValueForced -Path "HKLM:\Software\Test" -Name "Flags" -Type DWord -Value 1
#>
param (
[string]$Path,
[string]$Name,
[string]$Type,
[object]$Value
)
try {
# Ensure the key exists
if (-not (Test-Path -Path $Path)) {
New-Item -Path $Path -Force | Out-Null
}
# Set the registry value
Set-ItemProperty -Path $Path -Name $Name -Value $Value -Type $Type -Force
} catch {
Write-Output "Failed to set $Name in ${Path}: $($_.Exception.Message)"
}
}
# Step 1: Clear old upgrade failure records
Write-Host "Step 1: Clearing old upgrade failure records..." -ForegroundColor Yellow
Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\CompatMarkers" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Shared" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\TargetVersionUpgradeExperienceIndicators" -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Cleanup complete." -ForegroundColor Green
# Step 2: Simulating hardware compatibility
Write-Host "Step 2: Simulating hardware compatibility..." -ForegroundColor Yellow
Set-RegistryValueForced -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\HwReqChk" -Name "HwReqChkVars" -Type MultiString -Value @(
"SQ_SecureBootCapable=TRUE",
"SQ_SecureBootEnabled=TRUE",
"SQ_TpmVersion=2",
"SQ_RamMB=8192"
)
Write-Host "Hardware compatibility values applied." -ForegroundColor Green
# Step 3: Allow upgrades on unsupported TPM or CPU
Write-Host "Step 3: Allowing upgrades on unsupported TPM or CPU..." -ForegroundColor Yellow
Set-RegistryValueForced -Path "HKLM:\SYSTEM\Setup\MoSetup" -Name "AllowUpgradesWithUnsupportedTPMOrCPU" -Type DWord -Value 1
Write-Host "Upgrade policy for unsupported hardware enabled." -ForegroundColor Green
# Step 4: Set Upgrade Eligibility flag in HKCU
Write-Host "Step 4: Setting upgrade eligibility flag..." -ForegroundColor Yellow
Set-RegistryValueForced -Path "HKCU:\Software\Microsoft\PCHC" -Name "UpgradeEligibility" -Type DWord -Value 1
Write-Host "Eligibility flag set." -ForegroundColor Green
# Done
Write-Section -Text "All operations completed successfully!`nYou can now upgrade using the Windows 11 Upgrade Assistant or setup.exe from installation media.`nNo restart required." -Color Cyan
@playblusocial-lab

playblusocial-lab commented Aug 27, 2025

Copy link
Copy Markdown

Your script worked Perfectly to prep and then Just downloaded and ran Create installation media for Windows 11 found > https://support.microsoft.com/en-us/windows/create-installation-media-for-windows-99a58364-8c02-206f-aa6f-40c3b507420d <<< Just used this in hopes it may not get cleaned out because of filers. >>> to create the USB stick needed for win 11 install. After flash sick created ne reboot required and just run the setup.exe from the flash stick and accepted any warnings about not going to supported but installed Win 11 and all seems windows 11 works well from there.

Some games still may not work because needing either TPM 2.0 or Secure boot, but not my problem as I do not have time for games anyway.

@blinkblinktwo

blinkblinktwo commented Aug 30, 2025

Copy link
Copy Markdown

@blinkblinktwo gotcha, sorry I didn't see that before. I'll work on implementing when I get a chance.

No worries.
If it helps for reference, I just added a new function in the original script, and then modified step #4 with parameters to call it.

Thanks again, take care.

function Set-RegistryValueAllUsers {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [string]$SubKey,   # e.g. "Software\Microsoft\PCHC"

        [Parameter(Mandatory=$true)]
        [string]$Name,     # e.g. "UpgradeEligibility"

        [Parameter(Mandatory=$true)]
        [ValidateSet("String","ExpandString","Binary","DWord","QWord","MultiString")]
        [string]$Type,     # e.g. "DWord"

        [Parameter(Mandatory=$true)]
        [object]$Value     # e.g. 1
    )

    # Path to desired user-type registry key
    $regSubKey = "Software\Microsoft\PCHC"
    $regName   = "UpgradeEligibility"
    $regType   = "DWORD"
    $regValue  = 1


    # Get all Windows "NTUSER.DAT" local user profiles registry hives (skip system account)
    $profiles = Get-CimInstance Win32_UserProfile | Where-Object {
        ($_.Special -eq $false) -and (Test-Path $_.LocalPath)
    }


    foreach ($profile in $profiles) {
        $sid  = $profile.SID
        $path = "$($profile.LocalPath)\NTUSER.DAT"


        if ($profile.Loaded) {
            # User reg hive is already mounted (user is logged in -- write value to path HKEY_USERS, no unmount!)
            $fullKeyPath = "Registry::HKEY_USERS\$sid\$regSubKey"

            if (-not (Test-Path $fullKeyPath)) {
                New-Item -Path $fullKeyPath -Force | Out-Null
            }

            New-ItemProperty -Path $fullKeyPath `
                             -Name $regName `
                             -PropertyType $regType `
                             -Value $regValue -Force | Out-Null

            Write-Host "Set for logged-IN user $($profile.LocalPath)"
        }


        else {
            # User reg hive is NOT loaded (load manually in HKEY_USERS, write value, then unmount!)
            Write-Host "Loading hive for logged-out user $($profile.LocalPath)"

            reg load "HKU\$sid" $path | Out-Null
            try {
                $fullKeyPath = "Registry::HKEY_USERS\$sid\$regSubKey"

                if (-not (Test-Path $fullKeyPath)) {
                    New-Item -Path $fullKeyPath -Force | Out-Null
                }

                New-ItemProperty -Path $fullKeyPath `
                                 -Name $regName `
                                 -PropertyType $regType `
                                 -Value $regValue -Force | Out-Null

                Write-Host "Set for logged-OUT user $($profile.LocalPath)"
            }


            finally {
                reg unload "HKU\$sid" | Out-Null
            }
    
        }

    }

}
# Step 4: Set Upgrade Eligibility flag in HKCU/HKEY_USER for ALL logged in and out local users.
Write-Host "Step 4: Setting upgrade eligibility flag..." -ForegroundColor Yellow
Set-RegistryValueAllUsers -SubKey "Software\Microsoft\PCHC" -Name "UpgradeEligibility" -Type DWord -Value 1
Write-Host "Eligibility flag set on ALL users." -ForegroundColor Green

@sdcoil

sdcoil commented Sep 24, 2025

Copy link
Copy Markdown

Thank you!

In case anyone uses Ansible I wrote a simple play.

- name: Bypass Windows 11 Upgrade Assistant
  ansible.windows.win_regedit:
    path: "{{ item.path }}"
    name: "{{ item.name }}"
    data: "{{ item.data | default(omit) }}"
    type: "{{ item.type | default(omit) }}"
    state: "{{ item.state | default('present') }}"
  loop:
    - { path: 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags', name: 'CompatMarkers', state: 'absent' }
    - { path: 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags', name: 'Shared', state: 'absent' }
    - { path: 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags', name: 'TargetVersionUpgradeExperienceIndicators', state: 'absent' }
    - { path: 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\HwReqChk', name: 'HwReqChkVars', type: 'multistring', data: [ 'SQ_SecureBootCapable=TRUE', 'SQ_SecureBootEnabled=TRUE', 'SQ_TpmVersion=2', 'SQ_RamMB=8192' ] }
    - { path: 'HKLM:\SYSTEM\Setup\MoSetup', name: 'AllowUpgradesWithUnsupportedTPMOrCPU', type: 'dword', data: '1' }
    - { path: 'HKCU:\Software\Microsoft\PCHC', name: 'UpgradeEligibility', type: 'dword', data: '1' }

@gmits-tim

Copy link
Copy Markdown

Here is a function I created to also edit HKCU for all users, expanding on @blinkblinktwo 's work.

https://github.com/greenmtnit/windows-scripts/tree/main/Set-HKCUAllUsersRegistryValue

My main improvement is mine will also set the registry values for any future users who log into the system, by editing C:\Users\Default\NTUSER.DAT.

Hope this helps someone.

@chowdaBeast

Copy link
Copy Markdown

This appears to no longer work - after running the Windows 11 setup after it restarts the program it rechecks the PC and comes up with the "This PC doesn't currently meet Windows 11 system requirements."

It allows me to run the program (which it didn't before because of the PC Health app it forces you to use), but doesn't allow the install of Windows 11 any more.

@asheroto

Copy link
Copy Markdown
Author

@chowdaBeast can you please run WhyNotWin11 and post the results to help determine which compatibility check is failing?

@chowdaBeast

chowdaBeast commented Jan 26, 2026

Copy link
Copy Markdown

@chowdaBeast can you please run WhyNotWin11 and post the results to help determine which compatibility check is failing?

So I ran this first and then ran WhyNotWin11, it's getting CPU Compatibility, CPU Frequency, and TPM Version as incompatible. The PC is already Windows 11, but I am trying to update to 25H2 as it's stuck on 21H2.

EDIT: CPU is an Xeon 2699 V4, Machinist X99 motherboard (TPM module on the way now)

@asheroto

Copy link
Copy Markdown
Author

The X99 motherboard is from around 2016. I tried it on a computer from 2015 a few days ago and also experienced issues with 25H2 upgrade from 24H2. After some digging, I found that 25H2 reverifies compatibility live, not just believing what the upgrade assistant says. Not sure if there's a way around this yet. There were two suggested workarounds I found, but have not tried.

Use a 25H2 ISO and mount it, then run this in Command Prompt after changing directories to it:

setup.exe /product server

and

setup.exe /Compat IgnoreWarning

@WiredWonder

Copy link
Copy Markdown

The enablement package should also allow an upgrade.

@asheroto

asheroto commented Jan 27, 2026

Copy link
Copy Markdown
Author

@fanchon7730-ctrl

Copy link
Copy Markdown

Thank you so much

@kvalivk

kvalivk commented Mar 13, 2026

Copy link
Copy Markdown

Thanks a lot. I had upgraded w/o TPM by pretending my computer is a server (as proposed by some people), everything went well until there was an update glitch, so Microsoft attempted to do a "repair" - which was obviously not possible b/c the Win 11 repair set refused to work on my computer after it found out I had no TPM. Now this registry change worked wonder.

@leesiha

leesiha commented Mar 27, 2026

Copy link
Copy Markdown

Thank you so much for sharing this!

I was trying to do an in-place upgrade from Windows 10 to Windows 11 25H2 on my Mac via Boot Camp. The setupprep.exe /product server workaround kept greying out the "Keep personal files and apps" option, which was a dealbreaker since I didn't want to wipe my Boot Camp setup.

However, applying both of registry edits (HwReqChk and AllowUpgradesWithUnsupportedTPMOrCPU) completely solved the issue. The installer finally let me keep all my files, settings, and apps, and the 25H2 upgrade went perfectly.

@ElsonM

ElsonM commented May 8, 2026

Copy link
Copy Markdown

I tried the script on a HP ELITEBOOK 850 G3 and it worked for me 🥇

@m01001101-01010110

m01001101-01010110 commented May 25, 2026

Copy link
Copy Markdown

The X99 motherboard is from around 2016. I tried it on a computer from 2015 a few days ago and also experienced issues with 25H2 upgrade from 24H2. After some digging, I found that 25H2 reverifies compatibility live, not just believing what the upgrade assistant says. Not sure if there's a way around this yet. There were two suggested workarounds I found, but have not tried.

Use a 25H2 ISO and mount it, then run this in Command Prompt after changing directories to it:

setup.exe /product server

and

setup.exe /Compat IgnoreWarning

@asheroto Same problem here. Have you found a solution?

@asheroto

asheroto commented May 26, 2026

Copy link
Copy Markdown
Author

@m01001101-01010110 I haven't tested it since then. Can you try using the enablement package first, then running the update?

https://pureinfotech.com/windows-11-25h2-enablement-package-iso-direct-download/

Are you already on 24H2?

@kay-tid

This comment was marked as spam.

@nhantrichuyenanh

Copy link
Copy Markdown

TYSM!! I googled and tried all kinds of methods from many websites but none worked until I found this, though I had to use Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass so that I run the script

@Saykitu0

Saykitu0 commented Aug 1, 2026

Copy link
Copy Markdown

Thank you so much!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment