HomeNewsletterCommunityMVP FeedToolsArchiveBlogToday's NewsAboutServicesQuick Links Subscribe free
← Back to Blog
Windows Update Windows UpdateFeatures on DemandLanguage PacksDISMGet-WindowsCapabilityFeature UpdateWindows 11Servicing

Features on Demand and language packs vanish after a feature update: why servicing drops them and how to detect it first

IA
Imran Awan
23 August 2026

The feature update finished. Compliance went green. Then the tickets started arriving.

Three said the keyboard layout had changed. Two said Server Manager had disappeared. One said the DNS snap-in was gone from a jump box that had had it for two years. Nobody reported an error, because nobody saw one.

Nothing on those devices is corrupt. sfc /scannow will come back clean. DISM /RestoreHealth will come back clean. The component store will report itself healthy, because it genuinely is healthy. What you are looking at is documented servicing behaviour around optional content, and it has a precise mechanism, a cause that depends entirely on how you deploy, and a detection method that does not involve waiting for your users to notice.

The short version

Features on Demand and language packs are not in the Windows image. Microsoft ships the metadata and leaves the payload out, so every FoD install is a fetch from somewhere. During an in-place upgrade, Windows Setup builds a second clean OS alongside the old one, enumerates the optional content you already had, and plans to reinstall the new version of it — but it "must look elsewhere to get the Windows packages". When it cannot find them, you get "an update that is missing features on the device". That is a source failure, not corruption, so SFC and DISM repair cannot help and cleanup did not cause it. Whether it happens at all depends on your deployment path: Windows Update and post-22H2 WSUS-with-UUP migrate optional content, while a media-based task sequence with Dynamic Update disabled does not. Inventory it with Get-WindowsCapability -Online before you upgrade, diff it after, and remember that Add-WindowsCapability "fails silently; no exceptions are thrown" — so a re-add script can report success while doing absolutely nothing.

The problem: the update succeeded and the features are gone

This failure has a signature that makes it hard to triage from a ticket queue. The tickets do not describe an update problem. They describe missing software.

What the user reportsWhat is actually missingThe name you need to search for
"My keyboard layout changed" / "Windows is in English now"A language pack or one of its language featuresLanguage.Basic~~~en-GB~0.0.1.0
"Handwriting stopped working on my pen device"The handwriting recognition language FoDLanguage.Handwriting~~~en-US~0.0.1.0
"Dictation and Narrator voices are gone"Speech and text-to-speech language FoDsLanguage.Speech~~~en-US~0.0.1.0
"My admin tools disappeared"RSAT capabilitiesRsat.ServerManager.Tools~~~~0.0.1.0
"The AD Users and Computers snap-in is gone"The AD DS and AD LDS tools capabilityRsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
"My scripts stopped working" (WMI command line)The WMIC capabilityWMIC~~~~
"ssh is not recognised"The OpenSSH client capabilityOpenSSH.Client~~~~0.0.1.0

Look at what is not in that table: an error code. No failed KB in update history, no rollback, no red banner in the Windows Update pane. From the fleet's point of view the upgrade was a clean success, which is exactly why this reaches you as seven unrelated application tickets rather than one patching incident.

It is worse than that. The evidence you need — what the device had installed before the upgrade — lived on the device, and the upgrade has already replaced it. By the time the first ticket lands, the baseline is gone unless you captured it.

Watch out: the reflex here is to run sfc /scannow, then DISM /Online /Cleanup-Image /RestoreHealth, then a component store cleanup "to tidy up". All three are wrong and the third is actively harmful to your investigation. The payload for a missing FoD is not damaged, it is absent by design — Microsoft documents that for Features on Demand "the metadata for Features on Demand is included. However, the binaries and other files associated with the feature are not included." A repair tool that fixes damaged files has nothing to fix. Meanwhile /StartComponentCleanup /ResetBase "removes all superseded versions of every component", which permanently narrows your rollback options while you are still trying to work out what changed.

The one thing worth doing in the first sixty seconds is the opposite of a repair: take a read-only inventory and write it down. Everything in the rest of this post depends on having that list.

Why it happens: optional content was never in the image

A capability is a request, not a component

Start with the thing most people get wrong. A Feature on Demand is not a Windows component that got deleted. It is a component that was never fully there.

Microsoft's definition is short: "Features on Demand (FODs) are Windows features that can be added at any time", and "when Windows 11 or Windows Server needs a new feature, it can request the feature package from Windows Update." The DISM reference is blunter — capabilities are "a Windows package type allows you to request services like .NET or languages without specifying the version". You ask for Rsat.Dns.Tools; the servicing stack works out which build matches this OS and fetches it. A normal component, by contrast, ships inside the image and is serviced in place from the component store.

The split between metadata and payload is where the trouble starts. The .NET Framework 3.5 support article states it plainly for the best-known FoD: "The metadata for Features on Demand is included. However, the binaries and other files associated with the feature are not included. When you enable a feature, Windows tries to contact Windows Update to download the missing information to install the feature."

So the device always knows the feature exists. It does not necessarily have the bits. Every FoD operation is a fetch, and every fetch can fail.

The capability name tells you which kind you are dealing with. It is four tilde-delimited fields after the feature name, and the third is the language:

Capability nameLanguage fieldWhat that means
Rsat.Dns.Tools~~~~0.0.1.0emptyLanguage-neutral capability; resources arrive as satellite packages
Language.OCR~~~en-GB~0.0.1.0en-GBA language FoD, scoped to one locale
WMIC~~~~empty, no versionLanguage-neutral, and per Microsoft it has satellites
Language.Fonts.Thai~~~und-THAI~0.0.1.0und-THAIScript-scoped font FoD, not locale-scoped

Satellites explain the duplicated package names in your logs

Microsoft documents two flavours of FoD. "FODs without satellite packages" are monolithic — one .cab with all language resources inside. "FODs with satellite packages" are language-neutral, with "language and/or architecture resources in separate packages (satellites)", and "only the packages that apply to the Windows image are installed, which reduces disk footprint".

This is why a single capability produces several package names in the Setup log, one per installed language. On the lab device I have in front of me — Windows 11 Enterprise 25H2, build 26200.9168 — the Setup log carries real Event 2 entries for exactly that pattern.

Setup log — Event 2, FoD packages reaching the Staged state
# Real Event 2 records captured read-only from the device. # Event 2 text is: "Package <name> was successfully changed to the Staged state." Microsoft-Windows-TerminalServices-AppServer-Client-FOD-en-US Microsoft-Windows-WMIC-FoD-en-US Microsoft-Windows-WMIC-FoD-en-GB Microsoft-Windows-WinOcr-FOD-en-US # Read the WMIC pair. One capability - WMIC~~~~ - two satellite packages, # because this device has both en-US and en-GB language resources installed. # "Staged" is not "Installed". Staged means the payload is present and # registered; it becomes Installed later, sometimes only after a reboot.

Two things are worth pulling out of that block. First, the en-US and en-GB pair for WMIC is not a duplicate or an error — it is the satellite model working as documented. Second, Microsoft-Windows-WinOcr-FOD-en-US is the payload behind the Language.OCR capability, which is the sort of thing nobody notices is gone until a document-scanning workflow quietly stops returning text.

Gotcha: because satellite FoDs need per-language packages, you cannot build a source for them by hand. Microsoft is explicit: "Don't hand-copy .cab files to a folder and try to use it as a repository. DISM requires additional metadata in the repository." A folder of the right .cab files will still fail. You need the Languages and Optional Features ISO, or a repository built with DISM /Export-Source.

What the upgrade actually does

Now the mechanism itself, because this is the part that turns a mystery into a diagnosis. Microsoft's own description of an in-place update is worth reading twice:

"When Windows Setup performs an in-place update, the new operating system is written to the user's disk alongside the old version in a temporary folder, where a second clean operating system is installed and prepared for the user to move into. When operation happens, Windows Setup enumerates optional content installed already in the current version and plans to install the new version of this content in the new operating system."

Setup does the right thing: it looks at what you had and intends to give it back. Then comes the sentence that explains every ticket in your queue:

"Windows Setup needs access to the optional content. Since optional content isn't in the Windows image by default, Windows Setup must look elsewhere to get the Windows packages, stage them, and then install them in the new operating system. When the content can't be found, the result is an update that is missing features on the device, a frustrated end user, and likely a help desk call."

Microsoft even has a name for it: "failure to migrate optional content during update". The feature was not dropped by a policy or eaten by a cleanup task. Setup asked for it, could not find a source, and moved on without it.

The reason it is absent by design is deliberate: optional content "isn't included by default in the Windows image file", because shipping it separately "reduces the disk footprint of Windows" and "reduces the time needed to service the operating system". Smaller image, faster servicing, and a hard dependency on reaching a source.

Whether it happens at all depends on how you deploy

This is the nuance to get right, and it is where a lot of blog advice overreaches. It is not true that a feature update always drops Features on Demand. Microsoft documents seven acquisition options with different migration behaviour. Condensed to what matters operationally:

Deployment pathMigrates optional content across the upgrade?Notes from the documentation
Windows Update / Windows Update client policiesYesMigration and acquisition "just work when the device is connected to an update service that uses the Unified Update Platform". A failing language pack rolls the update back.
WSUS or Configuration Manager with on-premises UUPYes, from Windows 11 22H2Since March 2023: "FODs and languages will automatically migrate for devices that perform an in-place update using an approved Windows 11, version 22H2 client feature update from WSUS."
Media-based upgrade with Dynamic Update enabledYesDynamic Update "acquires optional content during the update process", and Setup enables it by default.
Media-based upgrade with Dynamic Update disabledNoStated directly: "media-based upgrades don't migrate FOD and languages (unless Dynamic Update is enabled)".
Customised image (FODs injected before deployment)Yes, for what you injectedAnything a user added themselves is still lost.
Setup /InstallLangPacksPartialLanguage content only. "We treat InstallLangPacks failures as fatal, and roll back the entire upgrade."
Alternate source policy onlyNoAddresses user-initiated acquisition afterwards, not migration during the upgrade.

If your fleet upgrades through a Configuration Manager task sequence with Dynamic Update turned off — a very common choice, usually made to control bandwidth or to freeze the cumulative update level — then row four is your answer, and it is working exactly as documented.

There is one mercy worth knowing about. For media-based updates, "Windows will automatically try again once the new operating system boots. We call this latent acquisition." So some devices heal themselves a few hours later, once they have a route to a source. That is also why this failure can look intermittent across a ring: the devices that reached Windows Update recovered, the ones sitting behind a strict proxy did not.

Context: the WSUS story here has moved twice, and knowing the timeline stops you chasing stale advice. "Starting in Windows 10 version 1709, you can't use WSUS to host Features on Demand (FoDs) locally." Then "starting with Windows 10 version 1803, language packs can no longer be hosted on WSUS." The Add-WindowsCapability reference still carries the resulting hard line: "starting with Windows 10 version 1809, FOD and language packs can only be installed from Windows Update." But that note is now dated. "Starting in Windows 11, version 22H2, on-premises Unified Update Platform (UUP) updates were introduced. FoDs and language packs are available from WSUS again." If you are on 22H2 or later, the cmdlet's own note is describing a world you have left.
Gotcha: two popular explanations for this failure are wrong, and both send you down a dead end. First, disabling an optional feature on a client does not delete its payload — Microsoft states "beginning with Windows 10, the payload is not removed from Windows client editions in order to support Push-button reset. The payload is removed from Windows Server installations." On a client you only lose the payload if you explicitly run /Disable-Feature /Remove. Second, there is no Microsoft documentation linking /StartComponentCleanup or /ResetBase to FoD payload removal. Blaming your cleanup schedule is unverified; the documented removal route is /Disable-Feature /Remove.

One last piece of the design worth knowing, because it explains why FoDs usually do survive: Reserved Storage is sized with them in mind. Microsoft notes that FoD install sizes vary because the figure "accounts for growth in the Reserved Storage size to ensure there is enough disk space for all installed Feature on Demand packages to be preserved during updates." Preservation is the intent. Missing features mean the intent was defeated by a missing source.

How to verify: take the inventory before you touch anything

Here is the diagnostic path. It is deliberately read-only until step 7, and step 1 is the one that decides whether the rest is easy or guesswork.

  1. Capture a capability census on every device before the upgrade ring runs. Get-WindowsCapability -Online and store the result. Without this, you are reconstructing history from tickets.
  2. On an affected device, census again and diff. Anything that was Installed before and is NotPresent now is your loss list. This is the whole diagnosis in one comparison.
  3. Separate capabilities from packages. Language packs are packages, not capabilities. Get-WindowsCapability -Online will not show you a display language; Get-WindowsPackage -Online and Get-InstalledLanguage will.
  4. Check the language view per feature, not per language. A locale can be present with Basic and OCR but no handwriting or speech. "Language installed" is not one boolean.
  5. Read the Setup log for Event 2 entries naming FoD packages. If the packages were staged, the source was reachable and your problem is elsewhere. If they are absent, Setup never got the content.
  6. Determine which source the device would actually use. Read the repair-source policy value, and confirm whether the device can reach Windows Update at all. This is what decides whether your re-add can succeed.
  7. Only now re-add, one capability at a time, respecting dependencies.
  8. Re-census to prove it. Never trust the exit code — see the silent-failure trap below.

Step 1 and 2: the census

This is the single most useful command in the whole topic, and it is entirely read-only.

Real capability census — Windows 11 25H2, build 26200.9168
# Read-only. Enumerates every capability the OS knows about. PS> $c = Get-WindowsCapability -Online PS> $c.Count 425 PS> $c | Group-Object State | Select-Object Name, Count Name Count ---- ----- NotPresent 369 Installed 56 # 425 known capabilities, 56 actually present. That ratio is the point: # the overwhelming majority of "Windows features" on any device are # metadata with no payload. NotPresent is the normal state, not a fault. PS> $c | Where-Object Name -like 'Rsat.*' | Select-Object Name, State Name State ---- ----- Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 Installed Rsat.BitLocker.Recovery.Tools~~~~0.0.1.0 NotPresent Rsat.DHCP.Tools~~~~0.0.1.0 Installed Rsat.Dns.Tools~~~~0.0.1.0 Installed Rsat.GroupPolicy.Management.Tools~~~~0.0.1.0 NotPresent Rsat.ServerManager.Tools~~~~0.0.1.0 Installed Rsat.WSUS.Tools~~~~0.0.1.0 NotPresent # Four RSAT capabilities present. Note Rsat.ServerManager.Tools is there - # it is the documented dependency of Rsat.ActiveDirectory.DS-LDS.Tools, # so the dependency chain is visible in the real data. PS> $c | Where-Object Name -eq 'WMIC~~~~' | Select-Object Name, State WMIC~~~~ Installed # Worth flagging: Microsoft documents that "starting with Windows 11, # version 24H2, WMIC is not preinstalled." This 25H2 device has it. # That is consistent with the Setup log staging its FoD packages - # it was carried across, not shipped in the image.

The 369-to-56 ratio is the single most clarifying number in this post. When a colleague sends you a screenshot of Get-WindowsCapability output full of NotPresent and asks whether the device is broken, the answer is no. NotPresent is the default state of almost everything.

Step 3 and 4: the language view is a different view

Language packs live in a different namespace from capabilities, and they need different cmdlets. The LanguagePackManagement module handles the language-level picture; the DISM module handles the capability-level picture underneath it.

Real language-feature asymmetry on the same device
# Language-level view. Read-only. PS> Get-InstalledLanguage # Capability-level view of the same thing - the actual installed language FoDs: PS> $c | Where-Object { $_.Name -like 'Language.*' -and $_.State -eq 'Installed' } | >> Select-Object -ExpandProperty Name Language.Basic~~~en-AU~0.0.1.0 Language.Basic~~~en-GB~0.0.1.0 Language.Basic~~~en-US~0.0.1.0 Language.Handwriting~~~en-US~0.0.1.0 Language.OCR~~~en-GB~0.0.1.0 Language.OCR~~~en-US~0.0.1.0 Language.Speech~~~en-US~0.0.1.0 Language.TextToSpeech~~~en-US~0.0.1.0 # Read the asymmetry carefully. Three locales have Basic. Only two have OCR. # Only ONE - en-US - has handwriting, speech and text-to-speech. # en-AU has Basic and nothing else. # # So "the en-GB language pack is installed" is true and still tells you # nothing about whether that user's dictation works. If you monitor at # locale granularity you will miss the loss that generates the ticket. # Documented dependency order for language FoDs: Basic first, then the rest. # OCR, Handwriting and TextToSpeech each depend on Basic for the same # language; Speech depends on Basic AND TextToSpeech.

That asymmetry is the reason fleet-scale detection has to be done at capability granularity. A dashboard that reports "installed display languages" will show green on a device whose speech recognition vanished.

Tip: make the pre-upgrade census an artefact, not a command someone remembers to run. Export Get-WindowsCapability -Online to a per-device file keyed on hostname and OS build, ship it somewhere central, and have the post-upgrade run diff against it. The comparison is trivial once you have both sides; the entire difficulty of this problem is that most shops only ever have the "after" side. Add Get-WindowsPackage -Online and Get-InstalledLanguage to the same snapshot and you cover packages and locales too.

Step 6: which source would this device actually use?

The repair-source policy is registry-backed, and there is a real trap in reading it. All of these values live under one key:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing
ValueMeaningWhat to look for
LocalSourcePathThe "Alternate source file path" from the Specify settings for optional component installation and component repair policy. The only element the in-box Servicing.admx declares.Present and populated = an alternate source is configured. A fully qualified path; several separated by semicolons; a WIM needs the wim: prefix and an image index, e.g. wim:\\server\share\install.wim:3. Absent = no alternate source, so the device depends on Windows Update or WSUS.
CountryCodeAn unrelated value that happens to live in the same key. Nothing to do with the repair-source policy.The trap. On the lab device this key exists and contains only CountryCode. A script that does Test-Path on the key and concludes "policy configured" is wrong. Test for LocalSourcePath specifically.
RepairContentServerSourceCommunity-attributed to the "download directly from Windows Update instead of WSUS" option.Unverified. Not documented on Microsoft Learn and not declared in the shipped Servicing.admx. Treat as community lore. Microsoft documents that the corresponding policy option was removed starting in Windows 11, version 24H2.
UseWindowsUpdateCommunity-attributed to the same policy family.Unverified. Same caveat. Do not build fleet logic on either of these two without testing on your own build.

That last point deserves the evidence, because it is the sort of claim that gets repeated for years after it stops being true.

Real policy evidence — the shipped ADMX and the actual key
# What the in-box ADMX actually declares. Read-only. PS> Get-Item C:\Windows\PolicyDefinitions\Servicing.admx | >> Select-Object Name, Length, LastWriteTime Name Length LastWriteTime ---- ------ ------------- Servicing.admx 1321 01/04/2024 08:22 PS> Select-String C:\Windows\PolicyDefinitions\Servicing.admx -Pattern 'key=|valueName' key="Software\Microsoft\Windows\CurrentVersion\Policies\Servicing" <text id="LocalSourcePath_TextBox" valueName="LocalSourcePath" expandable="true"/> # 1,321 bytes, and exactly ONE element: LocalSourcePath. # That is not a truncated file. Microsoft documents that the policy # "was modified starting in Windows 11, version 24H2" and that two # options were REMOVED: "Never attempt to download payload from # Windows Update" and "Download repair content and optional features # directly from Windows Update instead of Windows Server Update # Services (WSUS)". On 24H2+ there is only the alternate path left. # Now the live key on the same device: PS> Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing' | >> Select-Object * -Exclude PS* CountryCode : GB # The key EXISTS. LocalSourcePath does NOT. So this device has no # alternate source configured at all - every FoD request goes to # Windows Update or WSUS. Test-Path on the key would have lied.

The event log view

All four of these are in the Setup log, provider Microsoft-Windows-Servicing.

Event IDMessageWhat it tells you
2Package <name> was successfully changed to the Staged state.The payload was found and registered. For an FoD package name, this is positive proof the source was reachable. Absence of these during an upgrade is the fingerprint of a migration failure.
4A reboot is necessary before package <name> can be changed to the Installed state.Staged but not finished. Do not diagnose a "missing" feature until the pending reboot has happened — you may be looking at an incomplete transition, not a loss.
1013Corruption detection started (provider Microsoft-Windows-Servicing).Component store corruption scanning. Present here only to rule it out: if you see no 1013/1014 pair, this is not a corruption story. "Detection Only: 1" in the payload distinguishes a ScanHealth from a RestoreHealth.
1014Corruption detection completed.Pairs with 1013. A clean pair alongside missing features is the confirmation that you have a source problem, not a damage problem.

Which binaries are actually doing this work

DISM is a thin host over pluggable providers, and knowing which provider owns which job tells you where to look when something misbehaves. All of the following were read off the lab device.

FileRoleWhere it lives
Dism.exe"Dism Image Servicing Utility" — the command-line host. Version 10.0.26100.8457 here.C:\Windows\System32\
DismCore.dll"DISM Core Framework" — loads and dispatches to the providers.C:\Windows\System32\Dism\
CbsProvider.dll"DISM Package Provider" — the provider behind /Get-Capabilities, /Add-Capability and the package options. 1,304,040 bytes, one of the largest, since it owns the whole CBS surface.C:\Windows\System32\Dism\
IntlProvider.dll"DISM International Provider" — 357,864 bytes. The half of DISM that handles language packs rather than capabilities.C:\Windows\System32\Dism\
Microsoft.Dism.PowerShell.dllDISM PowerShell module assembly, 649,216 bytes. Provides Get-WindowsCapability, Add-WindowsCapability, Get-WindowsPackage.C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Dism\
Microsoft.LanguagePackManagement.Powershell.Commands.dllLanguagePackManagement module assembly (v1.0), 27,648 bytes. Provides Get-InstalledLanguage and Install-Language....\WindowsPowerShell\v1.0\Modules\LanguagePackManagement\
TrustedInstaller.exe"Windows Modules Installer" — commits the change.C:\Windows\servicing\
CbsApi.dllThe CBS API surface TrustedInstaller exposes, 83,432 bytes.C:\Windows\servicing\
cbscore.dllThe servicing stack core, and widely mislocated: it is not in System32. This device runs stack 10.0.26100.9156.versioned WinSxS servicing-stack dir
Servicing.admxPolicy template for the repair-source setting. 1,321 bytes, declaring only LocalSourcePath.C:\Windows\PolicyDefinitions\

The fix: pick a source, re-add, then prove it happened

The source resolution order, which explains every failure

DISM and the capability cmdlets resolve a source in a fixed documented order. Memorise it, because every source-missing error is a statement about one of these three steps:

  1. If /Source is specified, DISM looks in the specified locations first. With multiple sources, "the files are gathered from the first location where they are found and the rest of the locations are ignored."
  2. If /Source is not specified, or the files were not found there, DISM checks the locations specified by Group Policy — that is LocalSourcePath.
  3. If the files are still not found, the image is online, and /LimitAccess was not specified, it looks on Windows Update.

Read step 2 again. A wrong /Source does not fail fast; it falls through to policy and then to Windows Update. That is why the same command behaves differently on two devices in the same ring.

The trap that makes re-add scripts lie

This is the single most important operational detail in the post, and it is documented in one sentence in the Add-WindowsCapability reference under the -Source parameter:

"If you do not specify a Source, the default location set by Group Policy is used. If that fails, Windows Update is also used for online images, unless LimitAccess is specified. When all fail, the cmdlet fails silently; no exceptions are thrown."

A remediation script that wraps Add-WindowsCapability in a try/catch and reports success on no exception will report success on every device in your fleet while installing nothing on any of them. There is a second, quieter version of the same problem: "if the package specified by the Name parameter is already installed, this command does not return an error message, regardless of whether the required files are present."

The only safe pattern is to verify state afterwards, from the same source of truth you used to detect the loss.

The verify-after-add pattern (documented behaviour)
# WRONG - this reports success on a device that installed nothing. try { Add-WindowsCapability -Online -Name 'Rsat.Dns.Tools~~~~0.0.1.0' Write-Output 'Installed' # no exception is not evidence } catch { Write-Output 'Failed' } # RIGHT - state before, act, state after, compare. $name = 'Rsat.Dns.Tools~~~~0.0.1.0' $before = (Get-WindowsCapability -Online -Name $name).State Add-WindowsCapability -Online -Name $name | Out-Null $after = (Get-WindowsCapability -Online -Name $name).State if ($after -eq 'Installed') { Write-Output "OK $name : $before -> $after" } else { Write-Output "FAIL $name : still $after - no source was reachable" } # Dependencies matter and are documented. Install parents first: # Rsat.ServerManager.Tools # -> Rsat.ActiveDirectory.DS-LDS.Tools (depends on ServerManager) # -> Rsat.BitLocker.Recovery.Tools (depends on AD DS-LDS) # Adding a child pulls its dependents anyway - for example adding Speech # also brings Text-to-speech and Basic - but ordering keeps failures legible.

Language packs take a different route

Do not try to fix a missing display language with Add-WindowsCapability alone. Use the language module, which handles the pack and its associated FoDs together:

Install-Language -Language en-GB "downloads and installs the available language components for the specified language onto a device". Two switches matter operationally: -CopyToSettings also sets the system and default device settings, and -ExcludeFeatures means "the associated language Features on Demand won't be installed" — which is almost certainly not what you want when you are recovering from exactly that loss. -AsJob runs it asynchronously, useful at scale.

There is a hard constraint to plan around. The alternate-source policy "doesn't support installing language packs from an alternate source file path, only Features on Demand. If the policy is configured to acquire content from Windows Update, language packs will be acquired." A network share fixes FoDs. It does not fix language packs.

Watch out: on Windows 10 2004 through Windows 11 21H2 there is a documented policy conflict that produces exactly this failure with no obvious cause. Clients "can't download FoDs or language packs when Specify settings for optional component installation and component repair is set to Windows Update and Specify source service for specific classes of Windows Updates for either feature or quality updates is set to WSUS." Two policies that each look correct in isolation combine to block optional content. Microsoft's fix is to point feature and quality updates at Windows Update too, or to leave the source selections unconfigured so everything comes from WSUS. Check both policies before you conclude the network is at fault.

When the re-add fails with a source error

If step 3 of the resolution order is unavailable — no configured LocalSourcePath, no route to Windows Update, WSUS not serving optional content — the re-add fails with a source error rather than doing nothing. The one you will see most is 0x800F081F, documented as CBS_E_SOURCE_MISSING, "the source files could not be found". Microsoft lists three conditions behind it: the path does not contain the required files, the user lacks at least READ access to the location and files, or the file set is "corrupted, incomplete, or invalid for the version of Windows that you are running".

That third condition catches people constantly with FoDs specifically, because the ISO must match the OS release — "make sure you're using the ISO that matches your Windows image version". A 24H2 Languages and Optional Features ISO against a 25H2 device is an invalid file set, not a network problem. A sibling post covers 0x800F081F and the /Source mechanics in depth, so I will not duplicate it here.

Two neighbours are worth recognising on sight, since they point somewhere different: 0x800F0906 is CBS_E_DOWNLOAD_FAILURE — "the computer cannot download the required files from Windows Update", so look at proxy and firewall. 0x800F0907 is CBS_E_GROUPPOLICY_DISALLOWED, which Microsoft ties to the policy being configured to never attempt a download from Windows Update. Given that this policy option was removed in 24H2, seeing 0x800F0907 on a modern build is a strong hint about leftover configuration.

The structural fix

Re-adding capabilities device by device is remediation, not a fix. The fix is to remove the source dependency from the upgrade path, and there are only three durable ways to do that: move feature updates onto Windows Update client policies, adopt on-premises UUP with WSUS or Configuration Manager on 22H2 or later, or leave Dynamic Update enabled on media-based upgrades. Microsoft's own framing of the first option is unambiguous — optional content migration "just works" on a UUP-connected service. Everything else in this post is a workaround for not having done one of those three.

Proof it worked: a real read-only capability census

Every number below was read off one live Windows 11 Enterprise 25H2 device, build 26200.9168, servicing stack 10.0.26100.9156, without changing anything on it.

MeasurementResultWhat it proves
Get-WindowsCapability -Online total425 capabilitiesThe catalogue of what a device could have is large, and enumerating it is cheap and read-only.
State breakdown369 NotPresent / 56 InstalledNotPresent is the normal state for 87% of capabilities. A screenshot full of it is not a broken device.
RSAT capabilities installed4 of 21 (ServerManager, ActiveDirectory.DS-LDS, Dns, DHCP)The documented dependency chain is visible in live data: the AD DS-LDS tools are present and so is their parent, Rsat.ServerManager.Tools.
Language FoDs installedBasic for en-AU, en-GB, en-US; OCR for en-GB and en-US; Handwriting, Speech and TextToSpeech for en-US onlyCoverage is per feature, not per locale. Monitoring at locale granularity would have missed three of these.
WMIC~~~~Installed on a 25H2 deviceDocumented as not preinstalled from 24H2. Its presence, plus the Setup log staging ...WMIC-FoD-en-US and -en-GB, is the satellite model and content migration both working.
Setup log Event 2 FoD packages...TerminalServices-AppServer-Client-FOD-en-US, ...WMIC-FoD-en-US, ...WMIC-FoD-en-GB, ...WinOcr-FOD-en-USStaging succeeded, so a source was reachable. On a device that lost features, these entries are what is missing.
Servicing.admx1,321 bytes, one element: LocalSourcePathConfirms the 24H2 policy change first-hand — the two Windows Update options really are gone from the shipped template.
Repair-source policy keyKey exists, contains only CountryCodeNo alternate source configured, and proof the Test-Path trap is real: key presence is not policy configuration.
DISM providersCbsProvider.dll 1,304,040 bytes; IntlProvider.dll 357,864 bytesCapability work and language work run through different providers behind the same Dism.exe.

The pattern to take away is small. Optional content is a fetch, not a file. An upgrade that loses it did not break anything — it failed to find a source, quietly, at the one moment it needed one. Capture the census before the ring runs, diff it after, verify every re-add against state rather than exit code, and this stops being a ticket wave and becomes a report you read on Tuesday morning.

References

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

More from EndpointWeekly

Windows Update
Error 0x800f081f is not a verdict: find the missing payload in…
CBS_E_SOURCE_MISSING means servicing wanted a payload and could not find it - not that…
Windows Update
"Component Store Cleanup Recommended: Yes" - decide with…
DISM says cleanup is recommended and admins either ignore it for years or /ResetBase the…
Windows Update
Reserved storage: prove it is actually enabled before you blame…
Reserved storage is set at deployment time, not toggled at will, and an unelevated DISM…