G’day. Today I want to show you how to configure regional settings through Intune proactive remediation scripts: UK date formats, the pound sign, the right country, and a sensible clock.
The reason this needs a script at all is simple enough. Regional settings aren’t in the Settings Catalog. There’s no policy to pick, no toggle to flip, nothing to assign. Yet they’re one of the more visible things a user notices on a new device, and if you’re migrating away from Group Policy Preferences, you’re probably wondering “how do I do this within Intune 🤔”.
This post walks through it end to end. More usefully, it covers the part nobody writes down: how to work out which registry values you actually need, rather than copying a blog post (this one included) and hoping.
📝 Note
Remediations require the users of the devices to hold one of: Windows Enterprise E3 or E5 (included in Microsoft 365 F3, E3 or E5), Windows Education A3 or A5 (included in Microsoft 365 A3 or A5), or Windows Virtual Desktop Access (VDA) per user. The devices need to be Entra joined or Entra hybrid joined, and either Intune enrolled running Windows Enterprise, Professional or Education, or co-managed. If you’re on Business Premium this isn’t available to you, though the registry values below still apply if you deliver them another way, e.g Win32 App or Platform script.
What we’re actually changing
Worth being precise here, because “regional settings” covers three different things in Windows and people conflate them constantly.
The display language is what the interface is written in. That’s a language pack, and it’s delivered through a different mechanism entirely.
The system locale is the non-Unicode legacy codepage, set per device. It affects the sign-in screen and services running before anyone logs on.
The regional format is the per-user set of preferences deciding how dates, times, numbers and currency are displayed, along with the country or region the user is in. This is what users see in Excel, Outlook and the taskbar clock. It lives under HKCU\Control Panel\International, and it’s the one that generates the tickets.
We’re after the third. Since it’s per-user and lives in HKCU, a proactive remediation running in the logged-on user context is a natural fit: it checks the values on a schedule, corrects them if they drift, and reports compliance in the console.
Finding the registry values yourself
This is the bit worth learning, because it applies to far more than regional settings. There are three ways to work out what a Windows setting writes to the registry, in increasing order of effort.
Method one: just look
HKCU\Control Panel\International is unusually readable. Open it in Registry Editor, and the values are more or less self-describing:

Two things live here, and the second is easy to miss. The values sitting directly on International cover formats: dates, times, numbers, currency. Then there’s a Geo subkey holding the country or region, which is a separate concept and doesn’t show up in the parent key at all.
That distinction bites if you dump the values the obvious way, because Get-ItemProperty reads a single key and doesn’t recurse:
# The format values
Get-ItemProperty 'HKCU:\Control Panel\International' |
Select-Object -Property * -ExcludeProperty PS* |
Format-List
# The country/region, in a subkey of its own
Get-ItemProperty 'HKCU:\Control Panel\International\Geo' |
Select-Object -Property * -ExcludeProperty PS* |
Format-ListPowerShellOr walk both in one go, which is a habit worth forming when you’re exploring an unfamiliar key. Note that Get-ChildItem -Recurse returns the subkeys and not the parent, so the parent has to be added back explicitly:
$key = 'HKCU:\Control Panel\International'
@(Get-Item $key) + @(Get-ChildItem $key -Recurse) | ForEach-Object {
"`n[{0}]" -f $_.Name
$_ | Get-ItemProperty | Select-Object -Property * -ExcludeProperty PS* | Format-List
}PowerShellThe naming convention helps once you spot it. Values beginning s are strings (sCurrency, sShortDate, sShortTime), values beginning i are integers stored as strings (iTime, iTLZero, iFirstDayOfWeek). Microsoft documents the full set under the locale information constants, and the format strings are the same ones .NET uses, so dd/MM/yyyy means exactly what you’d expect. The Geo subkey follows none of that convention, which is a decent clue that it was bolted on later.
Method two: change it and diff it
When you’re not sure which value a given checkbox drives, export the key, change the setting through the interface, export again, and compare. Two lines and a diff:
# Before
reg export "HKCU\Control Panel\International" "$env:TEMP\intl-before.reg" /y
# ...now change the setting in Settings > Time & language > Language & region...
# After
reg export "HKCU\Control Panel\International" "$env:TEMP\intl-after.reg" /y
Compare-Object (Get-Content "$env:TEMP\intl-before.reg") (Get-Content "$env:TEMP\intl-after.reg")PowerShellreg export is recursive, so this picks up the Geo subkey without you asking. That’s precisely why it’s the better method: change the country in Settings and the diff shows both Geo\Name and Geo\Nation moving, whereas a Get-ItemProperty on the parent key would have shown you nothing at all and left you wondering where the setting went.
This is how I confirmed the time format values below, and it takes about ninety seconds. It’s also the technique that saves you when a setting turns out to write to two keys, or writes somewhere you didn’t expect.
💡 Tip
The old intl.cpl Control Panel applet still exists in Windows 11 and is far better than the modern Settings app for this. Run intl.cpl, click Additional settings, and you get every format string laid out on tabs. It maps almost one to one onto the registry values, so it’s the fastest way to see what’s available.
Method three: Process Monitor
For anything genuinely obscure, Process Monitor is the answer. Filter on Operation is RegSetValue, change the setting, and watch what gets written. Overkill for regional settings, indispensable for third-party applications that hide their configuration somewhere unhelpful.
The values you need for en-GB
Here’s the working set. Everything is REG_SZ, including the values that look like numbers.
| Key | Value | Data | What it does |
|---|---|---|---|
| HKCU\Control Panel\International | Locale | 00000809 | Locale ID (LCID) in hex, 0809 is English (UK) |
| HKCU\Control Panel\International | LocaleName | en-GB | The modern locale name |
| HKCU\Control Panel\International | sCurrency | £ | Currency symbol |
| HKCU\Control Panel\International | sShortDate | dd/MM/yyyy | Short date format |
| HKCU\Control Panel\International | sShortTime | HH:mm | Short time, drives the taskbar clock |
| HKCU\Control Panel\International | sTimeFormat | HH:mm:ss | Long time format |
| HKCU\Control Panel\International | iTime | 1 | Legacy 12/24 hour flag |
| HKCU\Control Panel\International | iTLZero | 1 | Leading zero on the hour |
| HKCU\Control Panel\International\Geo | Name | GB | Country/region, ISO code |
| HKCU\Control Panel\International\Geo | Nation | 242 | Country/region, GeoID |
Three of these deserve a proper explanation.
Locale and LocaleName are the same thing twice. Locale is the old hexadecimal LCID, and 00000809 decodes as 0x0809, which is English (United Kingdom). LocaleName is the modern BCP 47 name for the same locale. Set both. Older applications read the LCID, newer ones read the name, and a machine where the two disagree behaves strangely in ways that are miserable to diagnose.
Geo\Nation is not a phone code or a dialling prefix. It’s a Microsoft GeoID, and 242 is the United Kingdom. This value drives country-aware behaviour in Windows and some Store apps. There’s no logic to the numbering, so look it up rather than guessing. Geo\Name is the sane ISO 3166 equivalent, and again, set both.
The time format is decided by the case of the letters. HH is 24-hour, hh is 12-hour, so an sShortTime of HH:mm gives you 14:04 while h:mm tt gives you 2:04 pm. sTimeFormat does the same for the long format. iTLZero adds the leading zero so 9am renders as 09:04, and iTime is the legacy 12/24 flag, which modern Windows ignores but plenty of older line of business applications still read. If you’d rather keep a 12-hour clock, swap those for h:mm tt, h:mm:ss tt and 0; nothing else in the set changes.
I’ve deliberately left s1159 and s2359 alone. Those are the AM and PM designators, and there’s nothing to gain by touching them.
The detection script
Detection scripts follow one rule in proactive remediations: exit 0 means compliant, exit 1 means run the remediation. Anything written to standard output appears in the Intune console as the pre-remediation detection output, which makes it worth writing something readable rather than nothing at all.
The script below checks all ten values and bails out at the first mismatch. There’s no point continuing once you know the remediation needs to run.
<#
.SYNOPSIS
Detection - Default regional settings (en-GB).
.DESCRIPTION
Verifies the per-user regional format values under
HKCU\Control Panel\International (and \Geo) match the approved en-GB set.
If any value is missing or wrong the device is reported non-compliant so
the remediation runs.
The currency symbol is built from its character code ([char]0x00A3) so the
script is not affected by file encoding.
Runs in the logged-on user context (HKCU).
.NOTES
Author: Alex Durrant
Version: 1.0
Context: Run as logged-on user | 64-bit PowerShell: Yes
#>
$ErrorActionPreference = 'Stop'
$Settings = @(
@{ Path = 'HKCU:\Control Panel\International'; Name = 'Locale'; Value = '00000809' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'LocaleName'; Value = 'en-GB' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sCurrency'; Value = ([char]0x00A3).ToString() }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sShortDate'; Value = 'dd/MM/yyyy' }
# 24-hour clock. HH (uppercase) is 24-hour; hh is 12-hour.
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sShortTime'; Value = 'HH:mm' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sTimeFormat'; Value = 'HH:mm:ss' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'iTime'; Value = '1' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'iTLZero'; Value = '1' }
@{ Path = 'HKCU:\Control Panel\International\Geo'; Name = 'Name'; Value = 'GB' }
@{ Path = 'HKCU:\Control Panel\International\Geo'; Name = 'Nation'; Value = '242' }
)
try {
foreach ($s in $Settings) {
if (-not (Test-Path -LiteralPath $s.Path)) {
Write-Output "$($s.Path) missing - remediation required."
exit 1
}
$current = (Get-ItemProperty -LiteralPath $s.Path -Name $s.Name -ErrorAction SilentlyContinue).$($s.Name)
if ($current -ne $s.Value) {
Write-Output "$($s.Name) is '$current', expected '$($s.Value)' - remediation required."
exit 1
}
}
Write-Output "Regional settings compliant (en-GB)."
exit 0
}
catch {
Write-Output "Detection error: $($_.Exception.Message)"
exit 1
}PowerShellThat ([char]0x00A3).ToString() is not me being clever for the sake of it. It’s a pound sign, built from its Unicode code point rather than typed as a literal. Here’s why that matters.
💡 Tip
If you paste a literal £ into a script and save it as ANSI, or upload it and something along the way re-encodes it, the character arrives at the device as £. Your detection script then reports non-compliant forever, your remediation writes the mangled value, and users get £100.00 in Excel. Building the character from its code point sidesteps the entire problem. The same trick works for €, and for any accented character in a script you’re handing to a system you don’t control.
The remediation script
Same array, so the two scripts stay in step. Keep them adjacent when you edit them, because a detection script checking nine values and a remediation writing ten is a bug that hides for weeks.
<#
.SYNOPSIS
Remediation - Default regional settings (en-GB).
.DESCRIPTION
Writes the approved en-GB regional format values under
HKCU\Control Panel\International (and \Geo). All values are REG_SZ.
Sign out and back in for all format changes to fully apply. The taskbar
clock in particular does not refresh until Explorer restarts.
Runs in the logged-on user context (HKCU).
.NOTES
Author: Alex Durrant
Version: 1.0
Context: Run as logged-on user | 64-bit PowerShell: Yes
#>
$ErrorActionPreference = 'Stop'
$Settings = @(
@{ Path = 'HKCU:\Control Panel\International'; Name = 'Locale'; Value = '00000809' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'LocaleName'; Value = 'en-GB' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sCurrency'; Value = ([char]0x00A3).ToString() }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sShortDate'; Value = 'dd/MM/yyyy' }
# 24-hour clock. HH (uppercase) is 24-hour; hh is 12-hour.
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sShortTime'; Value = 'HH:mm' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'sTimeFormat'; Value = 'HH:mm:ss' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'iTime'; Value = '1' }
@{ Path = 'HKCU:\Control Panel\International'; Name = 'iTLZero'; Value = '1' }
@{ Path = 'HKCU:\Control Panel\International\Geo'; Name = 'Name'; Value = 'GB' }
@{ Path = 'HKCU:\Control Panel\International\Geo'; Name = 'Nation'; Value = '242' }
)
try {
foreach ($s in $Settings) {
if (-not (Test-Path -LiteralPath $s.Path)) {
New-Item -Path $s.Path -Force | Out-Null
}
New-ItemProperty -LiteralPath $s.Path -Name $s.Name -PropertyType String -Value $s.Value -Force | Out-Null
}
Write-Output "Regional settings applied (en-GB). Sign out and back in to fully apply."
exit 0
}
catch {
Write-Output "Remediation error: $($_.Exception.Message)"
exit 1
}PowerShellNew-ItemProperty with -Force creates the value if it’s missing and overwrites it if it exists, so there’s no need to test first. The Geo subkey gets created if a device somehow doesn’t have it, which happens more often than you’d think on freshly imaged machines.
Creating it in Intune
Devices > Manage devices > Scripts and remediations > Create script package. The settings that matter:
| Setting | Value |
|---|---|
| Name | PROD – Regional Settings (en-GB) |
| Description | Sets the per-user regional format to United Kingdom (en-GB) under HKCU\Control Panel\International and \Geo. |
| Detection Script | Detect-RegionalSettings-enGB.ps1 |
| Remediation Script | Remediate-RegionalSettings-enGB.ps1 |
| Run this script using the logged-on credentials | Yes |
| Enforce script signature check | No |
| Run script in 64-bit PowerShell | Yes |
| Schedule | Daily (but up to you!) |

Run as logged-on credentials is the setting to get right. Leave it at No and the script runs as SYSTEM, which has its own HKCU: the SYSTEM account’s profile. The script will report success, Intune will show a healthy green, and not one user’s settings will have changed. It’s a genuinely confusing failure because nothing errors.
⚠️ Important
Upload your scripts as .ps1 files rather than pasting them into the browser, and make sure they’re saved as UTF-8. If Enforce script signature check is enabled they must be UTF-8 without a BOM. This is Microsoft’s requirement; it’s the same encoding issue the pound sign tip warned about earlier, arriving from a different direction. Also worth knowing: script output in the console is capped at 2,048 characters, and you can have up to 200 script packages per tenant.
📝 Note
Naming convention is a personal preference, but prefixing with the ring (PROD, PILOT, DEV) pays off the moment you have thirty remediations and need to find the one you’re pushing to a test group.
Assign to a pilot group first. Daily is the right schedule here: these values don’t drift often, but when a user changes them by hand or a new profile is created, a daily check picks it up without hammering anything.
One mechanism worth understanding, because it explains why nothing appears to happen for a while: the client pulls remediation policy after a restart, after a user signs in, and otherwise once every eight hours. Reporting is lazier still. Recurring scripts only report back when something changes, plus a guaranteed report every seven days. So a freshly assigned remediation that shows no data yet is usually working exactly as designed.
Testing before you roll out
Run the detection script in the user context. Exit code 1 means non-compliant, so the remediation would fire. Exit 0 means compliant. Check it explicitly:
.\Detect-RegionalSettings-enGB.ps1
$LASTEXITCODEPowerShellThen run the remediation, re-run detection, and confirm you get 0. After signing out and back in, Get-Culture should agree with you:
Get-Culture | Select-Object Name, DisplayName
(Get-Culture).DateTimeFormat.ShortTimePattern # HH:mm
(Get-Culture).NumberFormat.CurrencySymbol # £PowerShell
⚠️ Important
Don’t judge the result by the taskbar clock. Explorer caches the time format on startup, so straight after the remediation runs the registry will be correct while the clock still shows the old format. Sign out and back in, or restart Explorer. This looks like the script has failed when it hasn’t.
What this deliberately doesn’t do
Scope matters, and this remediation has a narrow one. It sets the regional format for the user who is currently signed in. It does not touch:
The system locale. That’s device-wide, lives in HKLM, and needs Set-WinSystemLocale from an elevated context. Changing it requires a reboot.
The sign-in screen and new user profiles. Windows copies the current user’s regional settings into HKU\.DEFAULT and the default profile only when you tick “Copy your current settings to the welcome screen and system accounts” in intl.cpl. Doing that programmatically means writing to HKU\.DEFAULT\Control Panel\International and loading the default profile hive, both of which need SYSTEM context. It’s a separate, device-targeted remediation, and worth building if you’re managing shared devices or AVD session hosts where every logon creates a fresh profile.
The display language. Language packs are a different mechanism entirely and aren’t something you’d script this way.
If you’re doing this on Azure Virtual Desktop or Windows 365 with FSLogix profiles, the per-user approach here is usually all you need, since the profile persists. On non-persistent hosts without profile containers, you want the default profile variant instead.
Frequently asked questions
What licences do I need for remediations? The users of the devices need Windows Enterprise E3 or E5, Windows Education A3 or A5, or Windows VDA per user. Note that this is a Windows entitlement, not an Intune add-on: remediations are not part of Intune Advanced Analytics or Intune Plan 2, despite the two often being mentioned in the same breath. Without the right licence, the same registry values can be delivered by a platform script or a Win32 app with a detection rule, though you lose the compliance reporting.
Why not just use a Settings Catalog policy? Because there isn’t one. The per-user regional format values simply aren’t exposed in the Settings Catalog, so there’s nothing to assign. A script is the way to deliver them.
Will this stop users changing their own settings? No, and that’s intentional. This is a remediation, not a lock. A user can change the format, and the next daily run will put it back. If you need it genuinely enforced, you’d look at policy hive keys or a stricter approach, but for most estates a daily correction is exactly the right amount of force.
Why does the taskbar clock still show 12-hour time? Explorer caches the format on startup. Sign out and back in, or restart Explorer. The registry values will already be correct if the remediation ran.
Can I adapt this for another locale? Yes, and it’s mostly a case of changing four values: Locale (the hex LCID), LocaleName, Geo\Name and Geo\Nation. Look up the LCID and the GeoID rather than guessing. The format strings (sShortDate, sShortTime) are then whatever that region conventionally uses.
Where do the remediation logs go? Output appears in the Intune console against the remediation, both pre-remediation detection output and post-remediation output, and there’s an Export button to pull it out as CSV. On the device, everything lives in C:\ProgramData\Microsoft\IntuneManagementExtension\Logs. Three files matter: HealthScripts.log is the component that runs detection and remediation scripts on schedule, AgentExecutor.log records the actual PowerShell execution and exit codes, and IntuneManagementExtension.log covers policy retrieval and check-in, which is where to look when a script isn’t arriving at all. The scripts themselves are cached on the device under C:\Windows\IMECache\HealthScripts, which is handy when you want to confirm what actually landed.
Wrapping up
Regional settings are a small thing that produces a disproportionate number of tickets, and they’re one of the more satisfying Group Policy leftovers to retire properly. A detection script, a remediation script, and a daily schedule replaces a logon-time GPP with something that reports its own compliance and fixes drift without anyone noticing.
The technique generalises well beyond this. The pattern of “export the key, change the setting, diff the export” is how you convert almost any Group Policy Preference into a proactive remediation, and once you’ve done two or three, the rest of a GPO migration stops being intimidating.
If you’re working through the same migration, I’ve written before about replacing Group Policy with Intune configuration on this blog. Same principle throughout: find what the setting actually writes, then write it yourself.
Got a locale variant working, or hit something the above doesn’t cover? Let me know in the comments.
Happy Intuning! 👌



