Demystifying Windows 10 Feature Update Blocks


Disclaimer - if you manually bypass Feature Update blocks, you risk causing issues with your device. The blocks exist for a reason and should be respected. This information is provided for educational purposes only. Proceed with caution.


Windows 10 Feature Updates are released twice per year. For each release, Microsoft has the ability to block the update from being installed or even showing up in Widows Update for applications/drivers/devices that have known compatibility issues. This is a pretty great feature since it helps prevent unnecessary failures for already known issues that Microsoft is possibly already working to address. The flaw in this feature is the lack of visibility into what is being blocked and how/when it should be unblocked. Microsoft has gotten a little better with this area by keeping this site updated https://docs.microsoft.com/windows/release-information/status-windows-10-2004, however from a client installation perspective, it is often difficult or even impossible to match up an error message/code with anything published on that site (or any other Microsoft site). When Windows 10 2004 was released, there was a block in place for certain hardware models including the Surface line. When your boss has a Surface Pro 7 that can’t upgrade to the latest feature update, you’re not going to have a good time. This post is a deep dive into my experience with identifying Hard Blocks and making sense out of generic error messages like the one below. It will also contain some best guesses for how some things work where I may not have a 100% clear understanding.

Last things First

After writing this, I realized that I have crammed a lot if stuff in here. I want to highlight the main points to keep things from getting lost in the pile.

  1. Gain a better understanding of Feature Update blocks that prevent devices from upgrading - sometimes blocking the update from even showing up on the device as available.
  2. Understand how to manually convert Appraiser results to XML then compare to the Windows Compatibility Database (appraiser.sdb).
  3. Automate the collection and assessment of Feature Update blocks using custom PowerShell module FU.WhyAmIBlocked.

Blocked Upgrade Messages

When Windows 10 2004 shipped, the internet filled up with reports of people getting messages indicating that their devices couldn’t be upgraded. Everyone was asking - ‘Why am I blocked?’. Presenting a message telling us that we are blocked, but providing no actionable information is less than helpful. This needs to improve.

This PC can’t be upgraded to Windows 10

Let’s start with this message. It is very generic and less than helpful. It can appear in the setup UI if you are manually running setup.exe or in c:\$WINDOWS.~BT\Sources\Panther\ActionableReport.html.

A Square Dozen Image

1
2
3
This PC can't be upgraded to Windows 10.
Your PC settings aren't supported yet on this version of Windows 10. Microsoft is working to support your settings soon. No action is needed. Windows Update will offer this version of Windows 10 automatically when these settings are supported.
Learn More (https://docs.microsoft.com/windows/release-information/status-windows-10-2004)

…Your device isn’t quite ready for it…

On these same devices, if you attempt to pull the feature update from Windows Update, you may see a message like this one that showed up for Windows 10 2004.

1
2
3
Feature update to Windows 10, version 2004

The Windows 10 May 2020 Update is on its way. We're offering this update to compatible devices, but your device isn't quite ready for it. Once your device is ready, you'll see the update available on this page. There's nothing you need to do at this time.

CompatData Hard Block

When a Feature Update fails to install, you can generally check in the last CompatData_*.xml file for information about the failure. Unfortunately, sometimes the information is vague.

A Square Dozen Image

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<CompatReport xmlns="http://www.microsoft.com/ApplicationExperience/UpgradeAdvisor/01012009" MigXmlFile="P6MUWe3Hb0aa0MLV.9.8.0.0_APPRAISER_Migration.xml"><System X64Capable="True" X64Running="True"/><Hardware><HardwareItem HardwareType="Setup_BitlockerNoTargetSupport"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Setup_TargetIsNonStagedBuild"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Setup_LanguagePackDetected"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Setup_LicenseActivation"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Setup_FeaturesOnDemandDetected"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Setup_PendingFirmwareUpdateWithPower"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Setup_FlightSigningEnabled"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Setup_SecureBoot"><CompatibilityInfo BlockingType="None"/></HardwareItem><HardwareItem HardwareType="Generic">
			<CompatibilityInfo BlockingType="Hard" Message="Your PC isn't supported yet on this version of Windows 10. No action is needed. Windows Update will offer this version of Windows 10 automatically once the issue has been resolved." Title="This PC can't be upgraded to Windows 10."/>
			<Link Target="https://go.microsoft.com/fwlink/?LinkId=2128961" Value="Learn More"/>
		</HardwareItem>
	</Hardware><SystemInfo UplevelEdition="Windows 10" OSMajorVersion="10" OSMinorVersion="0"/>
	<Devices/>

ConfigMgr and Desktop Analytics

If you are an enterprise customer and are fortunate enough to use ConfigMgr, you can leverage Desktop Analytics to assess device and app compatibility BEFORE attempting to install feature updates. We have been using this (And Windows Analytics before DA) since it was released and it has almost eliminated the need for testing ALL of our applications before deploying the latest Feature Update - we still test critical apps. The shortcoming with DA is that is simply reports back what the Microsoft Compatibility Appraiser reports. It doesn’t include details specific to the blocking app. Work is still being done with DA, so I think there’s hope for integrating more data in the future.

Microsoft Compatibility Appraiser

So, I mentioned the Microsoft Compatibility Appraiser in the previous section. Whether you are aware of it or not, your Windows 10 device is actively assessing your device’s compatibility with Windows releases (possibly other monthly updates as well). I’ll break down the pieces that I have put together, but I still feel like this a ‘black box’ that I don’t fully understand.

CompatTelRunner Scheduled Task

Open Task Scheduler and you will find the Microsoft Compatibility Appraiser task under Task Scheduler Library>Microsoft>Windows>Application Experience

Microsoft Compatibility Appraiser scheduled task
Microsoft Compatibility Appraiser scheduled task

This task launches:

%windir%\system32\compattelrunner.exe

which in turn launches:

%windir%\system32\CompatTelRunner.exe -m:appraiser.dll -f:DoScheduledTelemetryRun

The output of this task produces a set of registry entries as well as some output files (possibly others that I’ve missed):

1
2
3
4
5
registry:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags

files:
C:\Windows\appcompat\appraiser\*.bin

These .bin files that are generated contain a list of compatibility assessment results. Portions of the results are also listed in the registry. For example, if there are hard blocks, a SdbAppGUID will be listed in the .bin file and a corresponding entry will be listed in the registry:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Appraiser\GWX\SdbEntries

Since the entries are in the registry, you can easily use ConfigMgr’s CMPivot tool to query the values to determine which SdbAppGUIDs are causing blocks using this CMPivot query:

1
Registry('HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Appraiser\\GWX') | where Property == 'SdbEntries' and Value != ''

Compattelrunner.exe also checked for any policies you may have enabled that prevent updates.

1
2
3
4
5
#Lists the policy locations for Windows Updates
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PolicyManager\default\Update

#One of the locations where the policies may reside
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UpdatePolicy

Appraiser.sdb and Alternate Appraiser Data

The appraiser consumes a database of info from Appraiser.sdb and uses a task list file Appraiser_TelemetryRunList.xml to tell it what to process. The default location of these files is C:\Windows\System32\appraiser.

If a machine is not on the latest Feature Update, compattelrunner.exe will download an Alternate_AppraiserData.cab file to c:\Windows\appcompat\appraiser from http://adl.windows.com/appraiseradl/YYYY_DD_MM_??_??_ARCH.CAB

Here’s a list of cab files that I’ve been able to find by looking at setupact.log files and searching the internet for other people’s logs. I don’t know where the current URL comes from to tell the client which file to get nor do I know what the last 2 sets of numbers stand for. I was thinking they may be HH_MM but that doesn’t seem to line up every time.

1
2
3
4
5
6
7
8
http://adl.windows.com/appraiseradl/2019_12_05_03_05_AMD64.cab
http://adl.windows.com/appraiseradl/2020_01_09_04_05_AMD64.cab
http://adl.windows.com/appraiseradl/2020_03_27_03_52_AMD64.cab
http://adl.windows.com/appraiseradl/2020_04_02_05_51_AMD64.cab
http://adl.windows.com/appraiseradl/2020_06_17_03_51_AMD64.cab
http://adl.windows.com/appraiseradl/2020_06_26_06_52_AMD64.cab
http://adl.windows.com/appraiseradl/2020_07_09_05_51_AMD64.cab
http://adl.windows.com/appraiseradl/2020_07_23_05_02_AMD64.cab

You can read more about data sharing and this URL here: https://docs.microsoft.com/mem/configmgr/desktop-analytics/enable-data-sharing. Be sure that you allow clients to access the listed URLs or you may experience issues with updates not having the latest compatibility information. When you expand the cab files using, you will get the following contents:

1
2
3
4
C:\Windows\appcompat\appraiser\Alternate_AppraiserData.cab - Contents
appraiser.sdb
Appraiser_Data.ini
Appraiser_TelemetryRunList.xml

These files are the key to understanding why machines will be blocked one day then unblocked the next and why you may experience different results on the same devices.

Dynamic Updates

If you disable Dynamic Updates or prevent your devices from going to the URLs listed above, you run the risk of preventing your devices from being able to install the latest Feature Update or install it properly. Whenever Windows setup runs, it will run a customized compatibility assessment and will download the latest Alternate_AppraiserData.cab files. This ensure that it has the latest compatibility information to assess a device against and provides a list of current migration shims that may mean the difference between success or failure of the upgrade.

Setupact.log

During or after a Feature Update, the setupact.log shows where it goes out to get the latest cab then runs a compatibility assessment. This one of several compatibility checks that are performed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
MOUPG  Setup Phase: [4]
MOUPG  Setup SubPhase: [8]
CONX   Windows::Compat::Appraiser::SetupAppraiser::GetAlternateData (3854):   Setup alternate data in use [1], Url [http://adl.windows.com/appraiseradl/2020_07_23_05_52_AMD64.cab], Result [0x0].
CONX   Windows::Compat::Appraiser::SdbUtils::SendSdbInfoTelemetry (1089):   Using Sdb Id: [{11111111-1111-1111-1111-111111111111}] Size: [13013088] Modified: [2020-07-23T23:29:39], at path C:\$WINDOWS.~BT\Sources\Panther\appraiser.sdb
CONX   Windows::Compat::Appraiser::WicaFactory::DoWicaRun (328):   WicaRun started.
CONX   Windows::Compat::Appraiser::WicaEngine::RunComponents (1340):   Engine starting.
CONX   Windows::Compat::Appraiser::SystemInventory::GetInventory (141):   Starting System Inventory.
CONX   Windows::Compat::Appraiser::WicaDeviceInventory::GetInventory (343):   Starting Device Inventory.
CONX   Windows::Compat::Appraiser::SystemInventory::GetInventory (168):   Finished System Inventory.
CONX   Windows::Compat::Appraiser::WicaDeviceInventory::GetInventory (368):   DevInv version is 10.0.18362
CONX   Windows::Compat::Appraiser::WicaDeviceInventory::GetInventory (369):   Processing Device Inventory File.
CONX   Windows::Compat::Appraiser::WicaDeviceInventory::GetInventory (409):   Finished reading Device Inventory. 0 Devices
CONX   Windows::Compat::Appraiser::WicaEngine::RunComponents (1345):   Tier complete: Inventory.
CONX   Windows::Compat::Appraiser::WicaEngine::RunComponents (1350):   Tier complete: Data Source.
CONX   Windows::Compat::Appraiser::WicaEngine::RunComponents (1355):   Tier complete: Decision Maker.
CONX   Windows::Compat::Appraiser::WicaEngine::RunComponents (1360):   Tier complete: Decision Aggregator.
CONX   Windows::Compat::Appraiser::WicaEngine::RunComponents (1366):   Engine finished.
CONX   Windows::Compat::Appraiser::SetupAppraiser::StartScan (159):   Start Scan Done
CONX   ConX::Compatibility::CCompatibilityHost::SerializeData: Provider wsc:wica: is serializing 580 bytes of data.

Just as the CompatTelRunner scheduled task will create new bin files, the process during Windows Setup will create a set of XML and BIN files in the Panther folder.

A Square Dozen Image

Appraiser_TelemetryRunList.xml

The Appraiser_TelemetryRunList.xml file tells the appraiser which actions to perform. It also tells it which sdb to use and where to output results of each scan. You could compare this xml to the xml files output during Windows setup and match up the components. I haven’t gotten that far into it. The module included at the end here has PowerShell to generate your own RunList.

A Square Dozen Image

Force a new Appraiser.sdb to process

During testing, I was able to replace the current Appraiser_AlternateData.cab file with an older version and run the scheduled task and the old file would be used. This is because the registry key logs which files were used last. If the key isn’t updated or deleted, a new file won’t be downloaded. Comparing Appraiser_Data.ini with the registry key you can determine if the device has used the current database.

I was also able to delete the Appraiser_AlternateData.cab from C:\Windows\appcompat\appraiser and re-run the scheduled task and it would pull down the latest version.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Appraiser
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Appraiser

Appraiser_Data.ini
Appraiser_Data.ini

Deserialize Appraiser BIN files

The output of the appraiser process will be a .bin file (and during a feature update an .xml file). The bin file is just a binary XML file that can be converted by using the appraiser process. It’s a configuration option built into the RunList XML. Here’s an example XML file that will take the file C:\Windows\appcompat\appraiser\APPRAISER_TelemetryBaseline_20H1.bin and deserialize it into the XML file APPRAISER_TelemetryBaseline_20H1_HUMANREADABLE.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<WicaRun>
  <RunInfos>
    <RunInfo>
      <Component TypeIdentifier="InventoryBinaryDeserializer" SpecificIdentifier="InventoryBinaryDeserializer" Type="Inventory">
        <Property Name="BinaryDeserializerTier" Value="Inventory" />
        <Property Name="BinaryDeserializerTier" Value="DataSource" />
        <Property Name="BinaryDeserializerTier" Value="DecisionMaker" />
        <Property Name="BinaryDeserializerTier" Value="DecisionAggregator" />
        <Property Name="BinaryDeserializerFilePath" Value="C:\Windows\appcompat\appraiser\APPRAISER_TelemetryBaseline_20H1.bin" />
      </Component>
      <Component TypeIdentifier="OutputEverything" SpecificIdentifier="OutputEverything" Type="Outputter">
        <Property Name="OutputFilePath" Value="APPRAISER_TelemetryBaseline_20H1_HumanReadable.xml" />
      </Component>
    </RunInfo>
  </RunInfos>
</WicaRun>

Run this in a cmd prompt and point to your RunList.

rundll32.exe appraiser.dll,RunTest MyRunList.xml

A Square Dozen Image

I used this script from Technet gallery (which will be going away soon) to get started down this process. It appears to be maintained by someone from the Microsoft CSS team but I’m not sure. https://gallery.technet.microsoft.com/scriptcenter/APPRAISE-APPRAISERbin-to-8399c0ee

*HumanReadable.XML

In the screenshot below of the Windows Panther folder, you’ll see bin and xml files. These files were generated during a Feature Update and you’ll see that they are already in XML format. From my experience, I’ve found that the second entry is the one that will generally contain block information. They correspond to the bin files that we see in the appraiser folder. There will be an *_UNV.bin and one that corresponds to the Windows release like *_20H1.bin. Likewise, the files created during setup appear to be broken out the same way.

A Square Dozen Image

An example of a device that’s blocked by an entry in one of these files would look like this. This is from the appraiser output folder, not a Feature Update. Search the file for the BlockingMatchingInfo property to find blocks.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<PropertyList Type="Inventory">
        <Property Name="AssetType" Value="BlockingMatchingInfo" />
      </PropertyList>
      <PropertyList Type="DataSource">
        <Property Name="ApplicableTargetVersion" Value="20H1" Ordinal="1" />
        <Property Name="ApplicableTargetVersion" Value="20H1" Ordinal="2" />
        <Property Name="SdbAppGuid" Value="{afb67a42-a10a-48a0-9677-77b4d80efecc}" Ordinal="1" />
        <Property Name="SdbAppGuid" Value="{afb67a42-a10a-48a0-9677-77b4d80efecc}" Ordinal="2" />
        <Property Name="SdbAppName" Value="OneDrive and Legacy filters" Ordinal="1" />
        <Property Name="SdbAppName" Value="OneDrive and Legacy filters" Ordinal="2" />
        <Property Name="SdbAppVendor" Value="Microsoft" Ordinal="1" />
        <Property Name="SdbAppVendor" Value="Microsoft" Ordinal="2" />
        <Property Name="SdbBlockOverrideType" Value="SDB_UX_BLOCKTYPE_OVERRIDE_UPGRADE_BLOCK" Ordinal="1" />
        <Property Name="SdbBlockOverrideType" Value="SDB_UX_BLOCKTYPE_OVERRIDE_UPGRADE_BLOCK" Ordinal="2" />
        <Property Name="SdbBlockType" Value="BlockUpgrade" Ordinal="1" />
        <Property Name="SdbBlockType" Value="BlockUpgrade" Ordinal="2" />
        <Property Name="SdbEntryGuid" Value="{b074d9ce-fc26-4e0b-9978-42e541e23388}" Ordinal="1" />
        <Property Name="SdbEntryGuid" Value="{19d3703c-f2f8-4d66-a480-078235f28797}" Ordinal="2" />
        <Property Name="SdbFwLink" Value="2133887" Ordinal="1" />
        <Property Name="SdbFwLink" Value="2133887" Ordinal="2" />
        <Property Name="SdbGenericMessageSummary" Value="Resource: 10028" Ordinal="1" />
        <Property Name="SdbGenericMessageSummary" Value="Resource: 10028" Ordinal="2" />
        <Property Name="SdbGenericMessageSummaryStringPresent" Value="TRUE" Ordinal="1" />
        <Property Name="SdbGenericMessageSummaryStringPresent" Value="TRUE" Ordinal="2" />
        <Property Name="SdbGenericMessageTitle" Value="Resource: 10026" Ordinal="1" />
        <Property Name="SdbGenericMessageTitle" Value="Resource: 10026" Ordinal="2" />
        <Property Name="SdbGenericMessageTitleStringPresent" Value="TRUE" Ordinal="1" />
        <Property Name="SdbGenericMessageTitleStringPresent" Value="TRUE" Ordinal="2" />
        <Property Name="SdbHyperlinkTarget" Value="https://go.microsoft.com/fwlink/?LinkId=2133887" Ordinal="1" />
        <Property Name="SdbHyperlinkTarget" Value="https://go.microsoft.com/fwlink/?LinkId=2133887" Ordinal="2" />
        <Property Name="SdbHyperlinkText" Value="Resource: 10041" Ordinal="1" />
        <Property Name="SdbHyperlinkText" Value="Resource: 10041" Ordinal="2" />
      </PropertyList>

A Square Dozen Image

Here’s another example of the block generated during a Feature Update. The main differences are 1) there are 2 blocks in the first example 2) the feature update blocks render out the GenericMessage text where the appraiser version just points to a Resource ID.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<PropertyList Type="Inventory">
        <Property Name="AssetType" Value="BlockingMatchingInfo" />
      </PropertyList>
      <PropertyList Type="DataSource">
        <Property Name="ApplicableTargetVersion" Value="20H1" Ordinal="1" />
        <Property Name="SdbAppGuid" Value="{afb67a42-a10a-48a0-9677-77b4d80efecc}" Ordinal="1" />
        <Property Name="SdbAppName" Value="OneDrive and Legacy filters" Ordinal="1" />
        <Property Name="SdbAppVendor" Value="Microsoft" Ordinal="1" />
        <Property Name="SdbBlockOverrideType" Value="SDB_UX_BLOCKTYPE_OVERRIDE_UPGRADE_BLOCK" Ordinal="1" />
        <Property Name="SdbBlockType" Value="BlockUpgrade" Ordinal="1" />
        <Property Name="SdbEntryGuid" Value="{b074d9ce-fc26-4e0b-9978-42e541e23388}" Ordinal="1" />
        <Property Name="SdbFwLink" Value="2133887" Ordinal="1" />
        <Property Name="SdbGenericMessageSummary" Value="Your PC settings aren't supported yet on this version of Windows 10. Microsoft is working to support your settings soon. No action is needed. Windows Update will offer this version of Windows 10 automatically when these settings are supported." Ordinal="1" />
        <Property Name="SdbGenericMessageSummaryStringPresent" Value="TRUE" Ordinal="1" />
        <Property Name="SdbGenericMessageTitle" Value="This PC can't be upgraded to Windows 10." Ordinal="1" />
        <Property Name="SdbGenericMessageTitleStringPresent" Value="TRUE" Ordinal="1" />
        <Property Name="SdbHyperlinkTarget" Value="https://go.microsoft.com/fwlink/?LinkId=2133887" Ordinal="1" />
        <Property Name="SdbHyperlinkText" Value="Learn More" Ordinal="1" />
      </PropertyList>

The entries are grouped by Name, so you have to follow the Ordinal values. All Ordinal = "1" entries belong to the same block. In this case we can see that this device has 2 blocks for OneDrive and Legacy filters. Not all entries listed in this section will be hard blocks but it’s a good place to start.

What the Heck is OneDrive and Legacy filters?!?

In my search to find answers, the OneDrive and Legacy filters block has been the thing that I just didn’t understand. If you list an app or hardware model in the block, that makes sense, but this one was so vague that it drove me to dig deeper.

I had a hunch that the info I needed would be in the appraiser.sdb files. After some digging around and lots of trial and error, I found 2 tools that ultimately helped convert the Compatibility Appraiser Database to XML.

https://github.com/TheEragon/SdbUnpacker - Python script to decompress the sdb.
https://devblogs.microsoft.com/setup/shim-database-to-xml - EXE to convert from sdb format to XML using the SDB API.

Once I had extracted the SDB into XML. I was able to match the GUIDs from the appraiser bin files with entries in the database. Each entry lists the files and registry keys that are used to determine if something should be blocked. In my case, there were 4 relevant entries related to OneDrive and Legacy filters.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<MATCHING_INFO_BLOCK>
      <NAME type="xs:string"></NAME>
      <APP_NAME type="xs:string">OneDrive and Legacy filters</APP_NAME>
      <VENDOR type="xs:string">Microsoft</VENDOR>
      <EXE_ID type="xs:string" baseType="xs:base64Binary">{b074d9ce-fc26-4e0b-9978-42e541e23388}</EXE_ID>
      <APP_ID type="xs:base64Binary" />
      <DEST_OS_GTE type="xs:string">20H1</DEST_OS_GTE>
      <DEST_OS_LT type="xs:string">21H1</DEST_OS_LT>
      <MATCHING_REG>
        <NAME type="xs:string">SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\BypassBlockUpgrade</NAME>
        <MATCH_LOGIC_NOT />
        <REG_VALUE_NAME type="xs:string">{B074D9CE-FC26-4E0B-9978-42E541E23388}</REG_VALUE_NAME>
        <REG_VALUE_TYPE type="xs:int">4</REG_VALUE_TYPE>
        <REG_VALUE_DATA_DWORD type="xs:int">1</REG_VALUE_DATA_DWORD>
      </MATCHING_REG>
      <PICK_ONE>
        <MATCH_PLUGIN>
          <NAME type="xs:string">RegistryMatchingPlugin</NAME>
          <COMMAND_LINE type="xs:string">"HKEY_USERS\*\Software\Microsoft\OneDrive\Accounts\Personal" ValueSearch FirstRun eq 1 REG_DWORD</COMMAND_LINE>
        </MATCH_PLUGIN>
        <MATCH_PLUGIN>
          <NAME type="xs:string">RegistryMatchingPlugin</NAME>
          <COMMAND_LINE type="xs:string">"HKEY_USERS\*\Software\Microsoft\OneDrive\Accounts\Business*" ValueSearch FirstRun eq 1 REG_DWORD</COMMAND_LINE>
        </MATCH_PLUGIN>
      </PICK_ONE>
      <BLOCK_UPGRADE>
        <BLOCK_UPGRADE_TYPE type="xs:int">3</BLOCK_UPGRADE_TYPE>
        <SUMMARY_MSG_RC_ID type="xs:int">10028</SUMMARY_MSG_RC_ID>
        <TITLE_MSG_RC_ID type="xs:int">10026</TITLE_MSG_RC_ID>
        <FW_LINK_ID type="xs:int">2133887</FW_LINK_ID>
        <LINK_TEXT_RC_ID type="xs:int">10041</LINK_TEXT_RC_ID>
      </BLOCK_UPGRADE>
    </MATCHING_INFO_BLOCK>

From this entry, we can see that the appraiser is looking for the existence of registry keys. If they exit, it will block the upgrade and display messaged tied to the IDs listed in the BLOCK_UPGRADE section. Once I removed the registry keys for all of the blocks and re-ran the appraiser, the blocks went away and I was able to apply the Feature Update.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<MATCHING_INFO_BLOCK>
      <NAME type="xs:string"></NAME>
      <APP_NAME type="xs:string">OneDrive and Legacy filters</APP_NAME>
      <VENDOR type="xs:string">Microsoft</VENDOR>
      <EXE_ID type="xs:string" baseType="xs:base64Binary">{b074d9ce-fc26-4e0b-9978-42e541e23388}</EXE_ID>
      <APP_ID type="xs:base64Binary" />
      <DEST_OS_GTE type="xs:string">20H1</DEST_OS_GTE>
      <DEST_OS_LT type="xs:string">21H1</DEST_OS_LT>
      <MATCHING_REG>
        <NAME type="xs:string">SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\BypassBlockUpgrade</NAME>
        <MATCH_LOGIC_NOT />
        <REG_VALUE_NAME type="xs:string">{B074D9CE-FC26-4E0B-9978-42E541E23388}</REG_VALUE_NAME>
        <REG_VALUE_TYPE type="xs:int">4</REG_VALUE_TYPE>
        <REG_VALUE_DATA_DWORD type="xs:int">1</REG_VALUE_DATA_DWORD>
      </MATCHING_REG>
      <PICK_ONE>
        <MATCH_PLUGIN>
          <NAME type="xs:string">RegistryMatchingPlugin</NAME>
          <COMMAND_LINE type="xs:string">"HKEY_USERS\*\Software\Microsoft\OneDrive\Accounts\Personal" ValueSearch FirstRun eq 1 REG_DWORD</COMMAND_LINE>
        </MATCH_PLUGIN>
        <MATCH_PLUGIN>
          <NAME type="xs:string">RegistryMatchingPlugin</NAME>
          <COMMAND_LINE type="xs:string">"HKEY_USERS\*\Software\Microsoft\OneDrive\Accounts\Business*" ValueSearch FirstRun eq 1 REG_DWORD</COMMAND_LINE>
        </MATCH_PLUGIN>
      </PICK_ONE>
      <BLOCK_UPGRADE>
        <BLOCK_UPGRADE_TYPE type="xs:int">3</BLOCK_UPGRADE_TYPE>
        <SUMMARY_MSG_RC_ID type="xs:int">10028</SUMMARY_MSG_RC_ID>
        <TITLE_MSG_RC_ID type="xs:int">10026</TITLE_MSG_RC_ID>
        <FW_LINK_ID type="xs:int">2133887</FW_LINK_ID>
        <LINK_TEXT_RC_ID type="xs:int">10041</LINK_TEXT_RC_ID>
      </BLOCK_UPGRADE>
    </MATCHING_INFO_BLOCK>

A Square Dozen Image

While I was in the sdb, I discovered another registry key that allowed me to bypass the block without actually deleting registry keys that may be critical to the app causing the block.

1
2
3
Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\BypassBlockUpgrade
Property: {B074D9CE-FC26-4E0B-9978-42E541E23388}
DWORD Value: 1

A Square Dozen Image

Once I created the regkeys and re-ran the appraiser, the blocks were still listed, but new entries appeared referencing the BypassBlockUpgrade keys.

A Square Dozen Image

Here’s another example where the Surface Pro 7 was blocked for 2004. This one gets a bit tricky. The first image show 2 GUIDs that match the GUIDs for a MACHINE_BLOCK in the 4th image. The second image shows the SdbEntryGuid that matches the MATCHING_INFO_BLOCK in the 3rd image. You’ll also see the registry key to bypass the block in the 3rd image. This whole time, we could have bypassed the Surface Pro 7 block!!!

*Appraiser_HumanReadable.xml
*Appraiser_HumanReadable.xml

*Appraiser_HumanReadable.xml
*Appraiser_HumanReadable.xml

Appraiser.sdb entries
Appraiser.sdb entries

Appraiser.sdb entries
Appraiser.sdb entries

FU.WhyAmIBlocked Powershell Module

FU is short for Feature Update

After going through all of this, I decided that this was too many steps to perform on a per-machine basis, so I took everything and created a new PowerShell module to help. Detailed usage info and updates can be found on the GitHub project site https://github.com/AdamGrossTX/FU.WhyAmIBlocked.
It has been published to the PowerShell Gallery (My first one, thanks Ben!) and you can install it directly on any machine you need to troubleshoot. https://www.powershellgallery.com/packages/FU.WhyAmIBlocked

In order to process the database SDB files, you will need Python installed. I have tested with Python 3.8 using the msi installer or the Windows Store app (which is pretty sweet!).

Also, I was limited on the block scenarios that I could replicate in my environment so results and match text files may not show everything. I suggest manually searching the appraiser.sdb.XML file for additional entries.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#Install and initialize
Install-Module FU.WhyAmIBlocked
Initialize-FUModule

#Get blocks on local device where the command is being run
Get-FUBlocks

#Get blocks from a remote device (Some limitations on features - registry key gathering and launching the appraiser)
Get-FUBlocks -DeviceName 'MyDevice'

#Process files from an alternate source path. Need .bin and Appraiser_AlternateData.cab files for this.
Get-FUBlocks -AlternateSourcePath 'C:\AltSource'

#Many more options available.

Assessing your Compatibility Blocks at Scale

Here’s what I did to assess my environment:

  • Collect SDB Block GUIDS and SDB Versions from the Registry using CMPivot
1
2
Registry('HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Appraiser\\GWX')
| where Property == 'SdbEntries' and Value != ''
  • Export results to CSV and get a distinct GUID list
  • Process GUIDs against Appraiser.sdb.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Import-Module FU.WhyAmIBlocked -Force

$BlockList = ('{62170609-e32b-4c80-a92a-a1025fd653af}',
'{1a55176d-2657-4b31-ba20-01721c9ab513}',
'{fa1d81f1-57b7-4907-970a-a37d80d41304}',
'{6c5378a1-aa13-4c12-95e8-11f90f27c528}',
'{691d652a-ea4b-4573-8c60-661049a36185}',
'{62170609-e32b-4c80-a92a-a1025fd653af}',
'{5e757e51-cc84-4a4a-ae70-d69a6a2b37f1}',
'{55350e5a-e423-48f8-8c4e-56c67315ec6f}',
'{1a55176d-2657-4b31-ba20-01721c9ab513}',
'{115791cb-3956-49d4-b375-30ec430137d3}',
'{0c65fb7b-65d4-48f1-80ce-eb0e2e49d43a}')


Extract-FUXMLFromSDB -AlternateSourcePath C:\FeatureUpdateBlocks\AltSrc -Path C:\FeatureUpdateBlocks\Output -SDBCab AltData.cab
Find-FUBlocksInSDB -Path C:\FeatureUpdateBlocks\Output -BlockList $BlockList

This should produce a Matches.txt file that you can use to review all of your enterprise’s blocks without having to collect any additional client information.

A Square Dozen Image

Summary

I feel like I’ve covered all of the pieces of the puzzle that I’ve put together at this point. I don’t think I’m finished with this process or the module, but needed to get this first round of info out of my head before I lose it. I’d love to hear your thoughts and get feedback on the module.

References

Addendum

After posting this, I got a message from Trevor Jones pointing me to a Microsoft doc with a buried registry key to bypass any data collection compatibly checks for Feature Updates. https://docs.microsoft.com/windows/deployment/update/update-compliance-feature-update-status#opting-out-of-compatibility-hold

Here’s the text from that post in case it ever goes away:

Compatibility holds

Microsoft uses diagnostic data to determine whether devices that use Windows Update are ready for a feature update in order to ensure a smooth experience. When Microsoft determines a device is not ready to update due to a known issue, a compatibility hold is generated to delay the device’s upgrade and safeguard the end-user experience. Holds are released over time as diagnostic data is analyzed and fixes are addressed. Details are provided on some, but not all compatibility holds on the Windows 10 release information page for any given release.

Opting out of compatibility hold

Microsoft will release a device from a compatibility hold when it has determined it can safely and smoothly install a feature update, but you are ultimately in control of your devices and can opt out if desired. To opt out, set the registry key HKLM\Software\Microsoft\Windows NT\CurrentVersion\502505fe-762c-4e80-911e-0c3fa4c63fb0 to a name of DataRequireGatedScanForFeatureUpdates and a value of ``.

Setting this registry key to 0 will force the device to opt out from all compatibility holds. Any other value, or deleting the key, will resume compatibility protection on the device.

I will test this when I get some time and see if how it behaves compared to the other options mentioned. Thanks Trevor!