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. Procced 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/en-us/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.

…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.

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.

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

This task launches:

which in turn launches”

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

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:

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:

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

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.

You can read more about data sharing and this URL here: https://docs.microsoft.com/en-us/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:

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.

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.

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.

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
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

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

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.

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.

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.

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.

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.

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.

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

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.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.

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
  • Export results to CSV and get a distinct GUID list
  • Process GUIDs against Appraiser.sdb.xml

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.

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/en-us/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 0.

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!

7 Comments

  • Reply
    Justen
    July 27, 2020 at 9:47 am

    Fantastic

  • Reply
    Daniele
    September 29, 2020 at 12:12 am

    Matching GatedBlock….FOUND!

    GatedBlock:

    Name Value Ordinal
    —- —– ——-
    SdbAppraiserData GatedBlock 1
    SdbAppName 2009C Manifest Regression (Wu Offer Block) 1
    SdbEntryGuid {d5cb328d-06d2-4839-9926-3f6eacd278f3} 1
    SdbAppGuid {a5653e78-2a71-4e16-b6d1-38f77a1b8990} 1

    Matching BlockUpgrade….FOUND!

    BlockUpgrade:

    Name Value Ordinal
    —- —– ——-
    SdbAppName 2009C Manifest Regression 1
    SdbEntryGuid {dbf458c4-d557-47ed-9fe0-5d5dbe1c68cf} 1
    SdbBlockType BlockUpgrade 1
    SdbAppGuid {a0dc7e6f-de58-427e-ac78-60b918dcde02} 1

    I googled a lot to find more info about “2009C Manifest Regression” but found nothing.
    Ani ideas?
    Thanks!!!

    • Reply
      Adam Gross
      September 29, 2020 at 6:40 am

      Check the matches txt files

      • Reply
        Daniele
        September 29, 2020 at 7:24 am

        Where? The only txt file I found in the folders is “Results.txt”…

  • Reply
    Chris
    January 27, 2021 at 2:06 am

    Hi,
    It’s a great tool.
    I Have the results.txt file.and the SdbEntries registry key.
    But the chapter “Assessing your Compatibility Blocks at Scale” not working:
    Extract-FUXMLFromSDB command is not recognized and I have not the forder AltSrc or Ouput

    Can you help me?

  • Comment

    This site uses Akismet to reduce spam. Learn how your comment data is processed.

    12,285

    Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://dc.services.visualstudio.com/v2/track` resulted in a `400 Invalid instrumentation key` response: {"itemsReceived":1,"itemsAccepted":0,"errors":[{"index":0,"statusCode":400,"message":"Invalid instrumentation key"}]} in /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113 Stack trace: #0 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/promises/src/Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/promises/src/Promise.php(156): Guzzle in /opt/bitnami/apps/wordpress/htdocs/wp-content/plugins/application-insights/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113