You set Language (Region) to German (Germany) in the Windows Autopilot deployment profile. You set Automatically configure keyboard to Yes. A brand new laptop runs through the out-of-box experience, or OOBE, and the language screens really do disappear. Then the user reaches the desktop and Windows is in English. The Start menu is English. The clock shows an American date format. And the keyboard produces the wrong characters. Nothing failed. Nothing errored. The profile did exactly what Microsoft documents it to do, which is a good deal less than most of us assume.
The Autopilot profile carries one documented locale value, exposed in Microsoft Graph as locale, plus a Boolean called keyboardSelectionPageSkipped. Microsoft documents these as controls that skip OOBE pages, not as controls that install anything. Windows can only display a language whose resources already exist on the disk, so a profile pointing at a language that was never installed leaves you on the factory display language. A genuinely localised device needs a language pack or Local Experience Pack, plus a step that copies the result into the system and new-user settings. The offline Autopilot JSON file has no documented language or region property at all.
The problem: the profile says de-DE and the desktop is still English
The symptom arrives as a ticket that reads like a bug. The Autopilot profile is configured for one country. The device that comes out the other end behaves like a different country. What makes it maddening is that the configuration blade gave you exactly one dropdown. One dropdown feels like it should mean one setting.
In practice the complaints split into distinct flavours. Each flavour is a different layer of Windows misbehaving, and each has a different fix.
Flavour one
OOBE skipped the language and keyboard pages, but Windows is displayed in English on the desktop.
Flavour two
The display language is correct, but the date, number and currency formats are still American.
Flavour three
Everything looks right for the first user. The sign-in screen and the next user are still English.
Flavour four
The keyboard page was skipped and the wrong physical layout was applied anyway.
Flavour four has a documented cause, so deal with it first. Microsoft lists a known issue titled "Setting up keyboard automatically doesn't accurately update keyboard language". The documented wording is that the profile setting "might fail to apply during provisioning due to a known OS issue". The documented resolution is to install KB5072033 or later. If you are chasing a keyboard layout on an unpatched image, stop chasing and patch.
The multi-region reality makes this worse. Most enterprises run one Autopilot profile, or a small handful, across a dozen countries. The profile is a service-side object assigned to a group. A single profile therefore hands the same single locale value to every device in every country that group covers. There is no per-device or per-country variable inside it.
Why it happens: five settings, five mechanisms, one profile field
What we casually call "the language of the device" is not one setting. Microsoft's own language documentation names the pieces separately. The Language Pack Management documentation lists them as the distinct things a language installation can touch. Reading that list is the moment the fog clears.
| Layer | What it actually controls | Set by |
|---|---|---|
| OOBE language selection | Which language the setup screens are drawn in, and which pages the user is shown or not shown. | The image contents, the manufacturer's Oobe.xml defaults, and the Autopilot profile page-skip settings. |
| System Preferred UI Language | The Windows display language: menus, dialogs, Settings, Start. Needs the matching language resources installed. | Set from the OOBE choice on commercial editions. Changed later by Set-SystemPreferredUILanguage or the CSP node. |
| System locale | The code page used by non-Unicode, legacy applications. Nothing to do with the display language. | Set-WinSystemLocale, or a language install run with -CopyToSettings. |
| Input method (keyboard layout) | Which physical key produces which character. This is a per-user setting. | Set-WinUserLanguageList and Set-WinDefaultInputMethodOverride, inside a user profile. |
| Locale and home location | Regional format for dates, numbers and currency, plus the GeoID that identifies the user's country or region. | Set-Culture and Set-WinHomeLocation, also per user. |
Five layers. Three of them are per-user. A per-user setting lives inside a user profile, and that profile does not exist yet when the Autopilot deployment profile is being read. That is the structural reason a service-side profile cannot fully localise a device.
What the profile field genuinely is
The deployment profile object is documented in Microsoft Graph. Its locale-related surface is small, and it is worth naming precisely. Inventing a field name here is how bad runbooks get written.
| Documented property | Where it lives | Documented meaning |
|---|---|---|
locale | windowsAutopilotDeploymentProfile | "The locale (language) to be used when configuring the device. E.g. en-US. The default value is os-default." |
language | windowsAutopilotDeploymentProfile | The older language-code property. Microsoft marks it read-only, and states that from May 2024 it is no longer supported and is deprecated in favour of locale. |
keyboardSelectionPageSkipped | outOfBoxExperienceSetting | "When TRUE, the keyboard selection page is hidden to the end user during OOBE if Language and Region are set." |
skipKeyboardSelectionPage | outOfBoxExperienceSettings | The same Boolean on the older settings complex type. Microsoft directs new work at outOfBoxExperienceSetting instead. |
Notice what is not in that list. There is no keyboard layout identifier. There is no separate region property. There is no language pack reference. The documented default is literally os-default, which means "whatever the image already is".
AutopilotConfigurationFile.json, the offline profile used by Autopilot for existing devices, lists exactly nine properties: Version, CloudAssignedTenantId, CloudAssignedTenantDomain, CloudAssignedOobeConfig, CloudAssignedDomainJoinMethod, CloudAssignedForcedEnrollment, ZtdCorrelationId, CloudAssignedAadServerData and CloudAssignedDeviceName. None of them is a language or region property. Community tooling does emit language-shaped keys into that file, and it may well work, but it is undocumented. Hand-editing the file is genuinely destructive. Microsoft states the file must be named AutopilotConfigurationFile.json and encoded as ASCII or ANSI, and that OOBE will not follow the Autopilot experience if the file is saved as Unicode or UTF-8. An editor that quietly writes UTF-8 turns a working deployment into a plain retail OOBE.Why the display language falls back to English
Here is the mechanism behind flavour one. Microsoft's languages overview states that on all commercial editions, the language chosen during OOBE is set as the System Preferred UI language, and that Windows is displayed in that language. That sounds like the profile should be enough. The catch is the word chosen. A language can only be chosen if its resources exist on the device.
Windows ships language resources for a limited set of languages in any given image. Microsoft documents 43 languages available as full language packs. Those are delivered as a .cab file, for example Microsoft-Windows-Client-Language-Pack_x64_es-es.cab. A further 47 language interface pack, or LIP, languages are documented as available only as .appx packages. Those are acquired through the Settings app after signing in, and Microsoft states explicitly that they cannot be used for system imaging. Those .appx packages are the Local Experience Packs, or LXPs.
If the language in your profile has no resources on the device, there is nothing to switch to. The display language simply stays where it was. Windows does not report this as a failure. It is the absence of an option, not an error.
Microsoft\Windows\MUI\LPRemove, that removes language packs which are not actively used. That includes languages not selected during OOBE. The languages overview puts it plainly: "Some time after OOBE, any pre-installed languages that haven't been used are removed automatically." A device can therefore be localisable on day one and not localisable on day thirty.Two more documented constraints worth knowing
The first is a network requirement. The profiles documentation carries a note that language and keyboard settings require Ethernet connectivity. Wi-Fi is documented as unsupported, because selecting a language, locale and keyboard is a prerequisite for making the Wi-Fi connection in the first place. A device provisioned over wireless will show you the pages regardless of the profile.
The second is a Group Policy conflict. Microsoft's Autopilot troubleshooting guidance lists Disallow changing of language/region/keyboard as a known conflicting policy. The documented reason is that the Group Policy Object, or GPO, is not supported during the OOBE flow because it affects the automatic sign-in experience. The documented advice is to hide those pages in the Autopilot profile instead of blocking them with policy.
Finally, check your expectations if you have moved to Windows Autopilot device preparation. Microsoft's documented capability list for device preparation covers the deployment flow, standard-user enforcement, application and script selection, the simplified OOBE progress view, and the deployment report. A Language (Region) control is not in that list.
How to verify: read the locale stack one layer at a time
Because there are five layers, no single command answers "is this device localised". You have to read each layer and compare them. Start with what the profile says, then read what the device actually did.
Step one: read the profile in the portal
Confirm two things on that blade. Check the Language (Region) value, and check whether Automatically configure keyboard is Yes. If Language (Region) is left at the operating system default, the keyboard setting has nothing to derive a layout from.
Step two: read the profile through Graph
The portal shows one dropdown. Graph shows the real property names. That is what you want when you are writing a runbook or comparing profiles across regions.
Step three: read the device's own locale stack
This is the step almost nobody runs, and it is the one that identifies which of the five layers is wrong. Run it on a device that came out of Autopilot looking wrong.
The decision rule is simple. If Get-InstalledLanguage does not list your target language tag, this was never a profile problem. It was a missing language pack.
Step four: read the Autopilot event log
Windows Autopilot writes its profile acquisition and OOBE setting activity to a dedicated event channel. Events 101, 103 and 109 are the interesting ones here. Those are the events that show numeric and string OOBE settings being retrieved and processed.
The full documented catalogue for that channel is below. Read it as a profile-delivery diagnostic, not a localisation diagnostic. It will tell you the settings arrived. It will not tell you the display language changed.
| Event ID | Type | Documented meaning |
|---|---|---|
| 100 | Warning | Autopilot policy not found. Typically temporary, while the device waits for a profile download. |
| 101 | Info | AutopilotGetPolicyDwordByName succeeded. Autopilot retrieving and processing numeric OOBE settings. |
| 103 | Info | AutopilotGetPolicyStringByName succeeded. Autopilot processing OOBE setting strings, such as the tenant name. |
| 109 | Info | AutopilotGetOobeSettingsOverride succeeded. Autopilot processing state-related OOBE settings. |
| 111 | Info | AutopilotRetrieveSettings succeeded. The profile settings that control OOBE behaviour were retrieved. |
| 153 | Info | State change reported, usually ProfileState_Unknown to ProfileState_Available. |
| 160 | Info | AutopilotRetrieveSettings beginning acquisition. |
| 161 | Info | AutopilotManager retrieve settings succeeded. The profile downloaded. |
| 163 | Info | Download not required, the device is already provisioned. Clean or reset the device to change this. |
| 164 | Info | AutopilotManager determined internet is available to attempt policy download. |
| 171 | Error | Failed to set TPM identity confirmed. Indicates a TPM attestation problem. |
| 172 | Error | Failed to set Autopilot profile as available. Typically related to event 171. |
| 807 | Error | ZtdDeviceIsNotRegistered. Validate the hardware hash upload and the profile assignment. |
| 809 | Error | ZtdDeviceHasNoAssignedProfile. The assigned profile no longer exists. |
| 815 | Error | ZtdDeviceHasNoAssignedProfile. No profile assigned, and no default profile in the tenant. |
| 908 | Error | SerialNumberMismatch or ProductKeyIdMismatch. Re-register the device. |
The one place the region value is actually visible
Event 103 is the most useful event in that whole catalogue, and almost nobody reads it. It prints the name and value of every string OOBE setting the device received from the deployment service. That includes the region value, under an internal policy name.
CloudAssignedRegion line is the closest thing to a direct read-out of what the service actually sent. Be precise about its status though. It is an internal policy name that the Autopilot event provider logs, observed here on a live device. It is not one of the nine documented AutopilotConfigurationFile.json properties, and Microsoft does not publish a reference for it. Read it as evidence, and never write it into a hand-crafted JSON file on the strength of a log line. In this capture the value is os-default, which is precisely the "the profile is not setting anything" state described earlier.Step five: read the cached profile in the registry
Autopilot caches the settings it received from the deployment service. The documented values are worth looking at precisely because of what is missing from them.
Microsoft documents CloudAssignedOobeConfig as a bitmap showing which Autopilot settings were configured. The documented values are: SkipCortanaOptIn is 1, OobeUserNotLocalAdmin is 2, SkipExpressSettings is 4, SkipOemRegistration is 8 and SkipEula is 16. There is no language bit and no keyboard bit. Do not go looking in this key for proof that your locale landed, because Microsoft does not document one there.
Step six: collect the cab from OOBE
If the device is still sitting in OOBE, grab the documented diagnostic package before it reboots.
The fix: the profile skips a screen, a language pack localises a device
Split the work in two. Use the Autopilot profile to control the OOBE experience. Use a language pack plus a policy to control the operating system. Trying to do the second job with the first tool is the whole reason this article exists.
Part one: set the profile correctly
- Sign in to the Microsoft Intune admin center.
- Select Devices in the left hand pane.
- Under By platform, select Windows.
- Under Device onboarding, select Enrollment.
- Under Windows Autopilot, select Deployment Profiles.
- Select your profile, then select Settings.
- Set Language (Region) to the target language. Microsoft documents this option as available in all deployment modes.
- Set Automatically configure keyboard to Yes to skip the keyboard selection page.
- Select Save.
There is no Group Policy equivalent for the Autopilot profile itself, so do not go looking for one. The profile is a cloud object in the Autopilot deployment service. Microsoft documents three ways to create it: the Intune admin center, the Microsoft 365 admin center, and the Intune Graph API. If you want it in code, use the windowsAutopilotDeploymentProfiles Graph resource.
Part two: install the language resources
This is the part that actually localises the device. Microsoft ships a supported PowerShell module for it. The module is documented as client-only, and Install-Language is documented as needing an elevated session.
Copy-UserInternationalSettingsToSystem is the cmdlet that fixes flavour three, the "correct for me, English for everyone else" complaint. Microsoft documents it as copying the Windows display language, input language, regional format and location or GeoID into the Welcome screen and system accounts, into new user accounts, or both. It is documented as available only on Windows 11 and later, it requires administrator permissions, and the changes take effect after the computer is restarted.Deliver that sequence as an Intune platform script or a Win32 app, and assign it to a device group rather than a user group. Assigning to a device group is what lets the Enrollment Status Page, or ESP, track it during provisioning. Signal the reboot requirement through the app's return code rather than forcing a restart mid-OOBE.
Part three: stop Windows from deleting your work
Remember LPRemove. If you pre-install languages in an image, or install extras that a given user never selects, Windows will clean them up. Microsoft documents a Group Policy route, a registry route and an equivalent MDM policy.
| Subkey under that parent | Value | What Microsoft documents it doing |
|---|---|---|
Policies\Microsoft\Control Panel\International | BlockCleanupOfUnusedPreinstalledLangPacks, REG_DWORD 0x1 | Blocks the LPRemove task from removing image-installed language packs that no user is using. |
Microsoft\Windows\CurrentVersion\Policies\TextInput | AllowLanguageFeaturesUninstall, REG_DWORD 0x0 | Blocks the language Features on Demand cleanup task from removing unused language feature packages. |
Policies\Microsoft\MUI\Settings | MachineUILock | Backs the "Force selected system UI language to overwrite the user UI language" policy, from Globalization.admx. |
Microsoft\Provisioning\Diagnostics\Autopilot | CloudAssignedOobeConfig and the related values | Read-only diagnostic cache of the Autopilot profile settings. No documented language or keyboard value. |
The Group Policy paths for the first three are documented, so prefer them over raw registry writes. For the cleanup block, the policy is Computer Configuration › Control Panel › Regional and Language Options › Block clean-up of unused language packs, set to Enabled. For the UI language lock, the same node holds Force selected system UI language to overwrite the user UI language. Both settings come from Globalization.admx. The Features on Demand block lives at Computer Configuration › Windows Components › Text Input › AllowLanguageFeaturesUninstall, set to Not allowed.
Through Intune, the same controls are available as MDM policies in the TimeLanguageSettings area of the Policy configuration service provider, or CSP.
./Device/Vendor/MSFT/Policy/Config/TimeLanguageSettings/MachineUILanguageOverwrite
./Device/Vendor/MSFT/Policy/Config/TimeLanguageSettings/RestrictLanguagePacksAndFeaturesInstall
./Device/Vendor/MSFT/Policy/Config/TimeLanguageSettings/ConfigureTimeZone
Microsoft documents the first three for Windows 11 version 21H2 and later. ConfigureTimeZone is documented from Windows 10 version 1903. Watch RestrictLanguagePacksAndFeaturesInstall in particular. Set to 1 it restricts the install of language packs and language features, which is precisely what your localisation script is trying to do.
The CSP route, and its documented status
There is a purpose-built CSP for this. Microsoft documents LanguagePackManagement with an Install node per language tag, an InstalledLanguages inventory node, and a LanguageSettings/SystemPreferredUILanguages node. The documented install sequence adds the language node, replaces CopyToDeviceInternationalSettings with true, then executes StartInstallation.
./Device/Vendor/MSFT/LanguagePackManagement/Install/{Language ID}/CopyToDeviceInternationalSettings
./Device/Vendor/MSFT/LanguagePackManagement/InstalledLanguages/{Language ID}/Providers
./Device/Vendor/MSFT/LanguagePackManagement/LanguageSettings/SystemPreferredUILanguages
The Providers node is genuinely useful diagnostics, and its values are documented. A value of 1 means only the language pack cab is installed. A value of 2 means only the LXP is installed. A value of 3 means both are installed. That single integer answers the question "did this device get a real language pack or a Store LXP".
Part four: the multi-region decision
One profile cannot serve several locales. So pick a model deliberately, rather than arriving at one by accident.
| Model | How it works | What it costs |
|---|---|---|
| One profile per locale | A profile per country, each with its own Language (Region) value, assigned to a country device group. Microsoft documents a limit of 350 profiles per tenant. | Profile sprawl and group hygiene. Devices must land in the right group before OOBE, or they receive the default profile. |
| One neutral profile, localise by policy | Leave the profile at the operating system default. Show the OOBE language pages. Localise afterwards with a per-country language app targeted at device groups. | Users see the language screens during setup. The device ends up fully localised, including the sign-in screen. |
| Hybrid | A profile per major region for the OOBE experience, plus a language app per country for the whole stack. | The most work to build, and the only model that delivers both a clean OOBE and a correct desktop. |
Oobe.xml into the factory image, that is a fourth mechanism in play. Microsoft documents that Oobe.xml sets the default language, location and keyboard layout, and that these become "the default values the user sees on the Language, Region, and Keyboard layout selection screens during OOBE". The user's own selection overrides them. Microsoft also documents authoring multiple Oobe.xml files for multi-language and multi-region deployments. That is why two devices from the same purchase order can behave differently.Proof it worked: every layer reporting the same tag
The proof is not "the screens were skipped". The proof is all five layers agreeing. The companion script for this article walks the whole stack read-only and prints one report. That lets you compare a good device against a bad one without remembering six cmdlets.
The script is Get-AutopilotLocaleReport.ps1. It is local only, needs no Microsoft Graph connection, and changes nothing.
That is a genuine run against a live Windows 11 Enterprise device, with the identifiers redacted. Layer 4 says British and layers 2, 3 and 5 say American. The GeoID home location says United Kingdom while the regional format says United States, which is exactly the split that produces "my dates are wrong" tickets. Note also that en-GB has both a language pack cab and an LXP installed while en-US has only the cab, so the raw materials were there all along.
After the localisation app runs, the same script gives you a single-value verdict.
Run it before and after your language app. A healthy result is boring, with the same tag on every line. A broken result is obvious at a glance, and it points you at the layer to fix rather than sending you back to the deployment profile.
One last sanity check on the mental model. A profile that skips a screen is a user-experience feature. A language pack is an operating system change. They are configured in different places, they take effect at different times, and neither will ever do the other's job.
References
| Source | What it establishes |
|---|---|
| Configure Windows Autopilot profiles | The documented wording for Language (Region) and Automatically configure keyboard, the Ethernet requirement, the 350-profile limit, and the reset-before-reapply behaviour. |
| windowsAutopilotDeploymentProfile resource type | The locale property, the deprecation of language, and the shape of the OOBE settings complex types. |
| outOfBoxExperienceSetting resource type | The exact documented name and meaning of keyboardSelectionPageSkipped. |
| Windows Autopilot known issues | The keyboard auto-configuration known issue and its KB5072033 resolution. |
| Windows Autopilot troubleshooting FAQ | The Autopilot event channel and Event ID catalogue, the profile registry cache, the OobeConfig bitmap, and the language/region/keyboard GPO conflict. |
| Windows Autopilot for existing devices | The complete documented property table for AutopilotConfigurationFile.json, and the ASCII or ANSI encoding requirement. |
| Languages overview | Language pack versus LXP delivery, the OOBE language becoming the System Preferred UI language, and the LPRemove cleanup behaviour. |
| Available language packs for Windows | Which languages exist as full language packs and which exist only as language interface packs. |
| LanguagePackManagement CSP | The node tree, the install sequence, the Providers values, and the Insider Preview applicability banner. |
| TimeLanguageSettings Policy CSP | The four OMA-URIs, their allowed values, and their Globalization.admx registry mappings. |
| Install-Language | The -CopyToSettings and -ExcludeFeatures parameters, and what each one does. |
| Copy-UserInternationalSettingsToSystem | The Welcome screen and new-user copy behaviour, the Windows 11 requirement, and the restart requirement. |
| Oobe.xml configuration file | That manufacturer image defaults set the values the user sees on the Language, Region and Keyboard layout screens. |
| Windows Autopilot device preparation overview | The documented capability list, which contains no Language (Region) control. |
Community deep-dives
| Author | Post | Why it is worth reading |
|---|---|---|
| Sandy Zeng, MSEndpointMgr | Managing Windows 11 languages and region settings (Part 1) | Walks the same layered problem end to end with Install-Language, Set-WinUILanguageOverride and Copy-UserInternationalSettingsToSystem. Also covers packaging it as a Win32 app with a soft-reboot exit code so the Enrollment Status Page can track it. |
| Rudy Ooms, Call4Cloud | Autopilot Device Preparation and the Return of OOBE Controls | Tracks the OOBE controls, keyboard skip among them, that device preparation policies do not yet expose. Useful context if you are migrating off classic Autopilot profiles. |