How to Set the System Keyboard Layout in Batch Script
Changing the keyboard layout programmatically is a common requirement for multilingual environments, shared workstations, and automated provisioning of machines for international offices. Instead of asking each new user to manually navigate through the Windows Settings panel, a Batch Script can preconfigure the correct keyboard layout during initial login or machine setup.
In this guide, we will explore how to add, remove, and set keyboard layouts using Batch Script, primarily through registry manipulation and PowerShell integration.
Understanding Keyboard Layout Identifiers
Windows identifies keyboard layouts using a combination of a Language ID and a Keyboard Layout ID, expressed as an 8-character hexadecimal string.
The format is: LLLLKKKK
LLLL= Language ID (e.g.,0409for English US,0410for Italian)KKKK= Keyboard Layout ID (e.g.,00000409for US QWERTY,00000410for Italian Standard)
Common keyboard layout codes:
| Layout | Code |
|---|---|
| English (US) | 00000409 |
| English (UK) | 00000809 |
| French (France) | 0000040C |
| German (Germany) | 00000407 |
| Italian | 00000410 |
| Spanish (Spain) | 0000040A |
| Japanese | 00000411 |
| US International | 00020409 |
Method 1: Adding a Keyboard Layout via the Registry
The current user's installed keyboard layouts are stored in the registry at:
HKCU\Keyboard Layout\Preload
Each layout is numbered sequentially: 1 is the default (primary) layout, 2 is the secondary, and so on.
Adding a Secondary Layout
@echo off
setlocal
echo Adding German keyboard layout as secondary...
:: The German standard keyboard layout ID
set "layout_id=00000407"
set "reg_path=HKCU\Keyboard Layout\Preload"
:: Scan existing slots to check for duplicates and find the next available slot
set "slot=1"
:check_slots
reg query "%reg_path%" /v %slot% >nul 2>&1
if %errorlevel% neq 0 goto :slot_available
for /f "tokens=2*" %%A in ('reg query "%reg_path%" /v %slot% 2^>nul ^| findstr /i "REG_SZ"') do (
if /i "%%B"=="%layout_id%" (
echo [INFO] German layout is already installed in slot %slot%. No changes needed.
pause
exit /b 0
)
)
set /a slot+=1
goto :check_slots
:slot_available
:: Add the layout to the discovered slot
REG ADD "%reg_path%" /v %slot% /t REG_SZ /d "%layout_id%" /f >nul
echo [OK] German layout added in slot %slot%.
echo You may need to log off and back on for the language bar to update.
pause
Setting a New Default Layout
To change the primary (default) keyboard layout, you overwrite slot 1. The script must also handle the previous default to prevent it from being lost, and check for duplicates to prevent the new default from appearing in multiple slots.
@echo off
setlocal
echo Setting French keyboard as the default layout...
:: French standard layout
set "new_default=0000040C"
set "reg_path=HKCU\Keyboard Layout\Preload"
:: Read the current default (slot 1)
set "old_default="
for /f "tokens=2*" %%A in ('reg query "%reg_path%" /v 1 2^>nul ^| findstr /i "REG_SZ"') do set "old_default=%%B"
:: Check if French is already the default
if /i "%old_default%"=="%new_default%" (
echo [INFO] French layout is already the default. No changes needed.
pause
exit /b 0
)
:: Set French as the new default in slot 1
REG ADD "%reg_path%" /v 1 /t REG_SZ /d "%new_default%" /f >nul
:: Check if the new default was already in a secondary slot
:: If so, swap it with the old default to avoid duplicates
set "swapped=0"
set "scan_slot=2"
:scan_slots
reg query "%reg_path%" /v %scan_slot% >nul 2>&1
if %errorlevel% neq 0 goto :scan_done
for /f "tokens=2*" %%A in ('reg query "%reg_path%" /v %scan_slot% 2^>nul ^| findstr /i "REG_SZ"') do (
if /i "%%B"=="%new_default%" (
if defined old_default (
REG ADD "%reg_path%" /v %scan_slot% /t REG_SZ /d "%old_default%" /f >nul
echo Swapped slot %scan_slot%: replaced %new_default% with %old_default%.
) else (
REG DELETE "%reg_path%" /v %scan_slot% /f >nul 2>&1
)
set "swapped=1"
goto :scan_done
)
)
set /a scan_slot+=1
goto :scan_slots
:scan_done
:: If the new default was not found in any secondary slot,
:: the old default needs to be added to the next available slot
if "%swapped%"=="0" (
if defined old_default (
REG ADD "%reg_path%" /v %scan_slot% /t REG_SZ /d "%old_default%" /f >nul
echo Previous default ^(%old_default%^) moved to slot %scan_slot%.
)
)
echo [SUCCESS] Default keyboard set to French.
echo A logoff may be required for this to take full effect.
pause
Changing the Preload registry keys affects only the current user and only takes full effect after the user logs off and back on. For immediate changes within the active session, see Method 3 (PowerShell).
Method 2: Complete Keyboard Layout Reset Script
If the goal is to ensure a machine has exactly one keyboard layout (removing all extras), this cleanup script handles the complete process.
@echo off
setlocal enabledelayedexpansion
echo Resetting Keyboard Layouts to US English Only...
:: Desired layout
set "target=00000409"
set "reg_path=HKCU\Keyboard Layout\Preload"
:: 1. Delete all existing preload entries
:: Scan dynamically rather than assuming a fixed upper limit
set "slot=1"
:delete_loop
reg query "%reg_path%" /v !slot! >nul 2>&1
if !errorlevel! neq 0 goto :delete_done
REG DELETE "%reg_path%" /v !slot! /f >nul 2>&1
set /a slot+=1
goto :delete_loop
:delete_done
:: 2. Set US English as the sole layout
REG ADD "%reg_path%" /v 1 /t REG_SZ /d "%target%" /f >nul
:: 3. Clear any substitute layouts (used by some IMEs)
:: Delete the entire key and recreate it empty
REG DELETE "HKCU\Keyboard Layout\Substitutes" /f >nul 2>&1
REG ADD "HKCU\Keyboard Layout\Substitutes" /f >nul 2>&1
echo [OK] All keyboard layouts removed except US English.
echo Log off required for change to be reflected in the language bar.
pause
Why We Clean Substitutes
Some Input Method Editors (IMEs), especially for East Asian languages, register themselves not in the Preload key but in Keyboard Layout\Substitutes. Failing to clean this key can result in phantom Japanese or Chinese input methods appearing in the language bar even after you clear Preload.
Method 3: Immediate Layout Change via PowerShell (No Logoff)
For scripts that need the change applied to the current session immediately (e.g., during a live demonstration), we can use PowerShell to call the Windows international settings cmdlets.
@echo off
setlocal
echo Applying keyboard layout change immediately...
:: Add French layout and set it as default, effective immediately
powershell -NoProfile -Command ^
"$langList = New-WinUserLanguageList 'fr-FR';" ^
"$langList.Add('en-US');" ^
"Set-WinUserLanguageList $langList -Force"
if %errorlevel% neq 0 (
echo [ERROR] Failed to apply keyboard layout change.
echo Ensure you are running Windows 10 or later.
pause
exit /b 1
)
echo [OK] French set as primary, English as secondary.
echo Change is effective immediately in this session.
pause
How This Works
New-WinUserLanguageList 'fr-FR': Creates a new language list with French as the first (primary) entry..Add('en-US'): Appends English as a secondary language. PowerShell automatically converts the language tag string into aWinUserLanguageobject.Set-WinUserLanguageList: Applies the list instantly. The language bar reflects the change without logging off.
The Set-WinUserLanguageList cmdlet requires Windows 10 or later. It is not available on Windows 7 or early Windows 8 builds. On older systems, you must use the registry approach (Methods 1 and 2) and accept that a logoff is required for changes to take effect.
Method 4: Applying Layouts for All New Users (Default Profile)
To set the keyboard layout for users who have not yet logged into the machine (new accounts), you must modify the Default User profile's registry hive.
@echo off
setlocal
:: Verify Admin Rights
net session >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Administrator privileges are required to modify the default user profile.
pause
exit /b 1
)
echo Loading default user registry hive...
:: Determine the default profile path from the registry
set "default_profile="
for /f "usebackq tokens=2*" %%A in (`reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" /v Default 2^>nul ^| findstr /i "REG_SZ"`) do call set "default_profile=%%B"
if not defined default_profile (
echo [ERROR] Could not determine the default user profile path.
pause
exit /b 1
)
set "hive_path=%default_profile%\NTUSER.DAT"
set "hive_key=HKU\DefaultUserTemp"
if not exist "%hive_path%" (
echo [ERROR] Default user hive not found: %hive_path%
pause
exit /b 1
)
:: Load the default user's NTUSER.DAT under a temporary key name
REG LOAD "%hive_key%" "%hive_path%" >nul 2>&1
if %errorlevel% neq 0 (
echo [ERROR] Failed to load the default user registry hive.
echo The hive may already be loaded or locked by another process.
pause
exit /b 1
)
:: Set the keyboard layout for new users (Italian)
REG ADD "%hive_key%\Keyboard Layout\Preload" /v 1 /t REG_SZ /d "00000410" /f >nul
:: Unload the hive
REG UNLOAD "%hive_key%" >nul 2>&1
if %errorlevel% neq 0 (
echo [WARNING] Failed to unload the registry hive immediately.
echo This can happen if Registry Editor or another tool has the key open.
echo The hive will be released when those handles are closed.
) else (
echo [OK] Registry hive unloaded successfully.
)
echo [OK] New user accounts will default to the Italian keyboard layout.
pause
The temporary key name used with REG LOAD (in this case HKU\DefaultUserTemp) is arbitrary. Use a distinctive name to avoid conflicts with any subkeys that might already exist under HKU. If the script is interrupted between the REG LOAD and REG UNLOAD commands, the hive remains loaded and the NTUSER.DAT file stays locked. You can manually unload it by running REG UNLOAD HKU\DefaultUserTemp from an elevated command prompt.
Common Mistakes
The Wrong Way: Confusing Language ID with Layout ID
:: WRONG - 0409 is only a language ID (4 digits), not a full layout code
REG ADD "HKCU\Keyboard Layout\Preload" /v 1 /t REG_SZ /d "0409" /f
The Preload value expects an 8-character hex string (00000409). Using a truncated 4-character string (0409) may produce unpredictable behavior where Windows defaults to a random layout associated with that language code, or the entry is silently ignored.
The Wrong Way: Expecting Immediate Effect from Registry Changes
:: WRONG - The user expects the language bar to change instantly
REG ADD "HKCU\Keyboard Layout\Preload" /v 1 /t REG_SZ /d "0000040C" /f
echo French layout is now active. Start typing!
Registry modifications to the Preload key only take effect after a logoff/logon cycle. For immediate changes, use the PowerShell Set-WinUserLanguageList approach from Method 3.
The Wrong Way: Blindly Overwriting Existing Slots
:: WRONG - Overwrites whatever was in slot 2 without checking
REG ADD "HKCU\Keyboard Layout\Preload" /v 2 /t REG_SZ /d "00000407" /f
If the user already has a layout in slot 2, this command silently replaces it. Always scan the existing slots to find the next available number, and check whether the layout you are adding already exists in another slot to prevent duplicates.
The Wrong Way: Using Unreliable Filters When Parsing Registry Output
:: WRONG - findstr /i "1" matches any line containing the character "1"
for /f "tokens=3" %%A in ('reg query "HKCU\Keyboard Layout\Preload" /v 1 2^>nul ^| findstr /i "1"') do set "old_default=%%A"
The filter findstr /i "1" matches any line containing the digit 1, which can include registry path lines, headers, or data values. Use findstr /i "REG_SZ" to reliably match only the data line. Additionally, tokens=3 is fragile when the value data contains spaces. Use tokens=2* with %%B to capture the complete value regardless of spaces.
Best Practices
- Use full 8-character layout codes: Always specify the complete
LLLLKKKKhex string when writing to the registry. - Check for duplicates before adding: Always scan existing slots to verify the layout is not already installed before adding it, and when changing the default, handle the displaced layout to prevent duplicate entries.
- Use PowerShell for immediate changes: If a logoff is unacceptable, the
Set-WinUserLanguageListcmdlet provides instant session-level results on Windows 10 and later. - Clean the Substitutes key: When performing a full keyboard reset, always clear the
Keyboard Layout\Substitutesregistry key to prevent ghost IME entries. - Use
tokens=2*withfindstr /i "REG_SZ"for registry parsing: This combination reliably captures the value data fromreg queryoutput regardless of the value name or data containing digits or spaces. - Use the registry to resolve the default profile path: Do not hardcode
C:\Users\Default. QueryHKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileListfor theDefaultvalue to support non-standard installations.
Conclusion
Setting the system keyboard layout in Batch Script involves writing the correct 8-character hexadecimal layout identifier into the HKCU\Keyboard Layout\Preload registry key. While registry changes require a logoff to take effect, embedding PowerShell's Set-WinUserLanguageList cmdlet provides an immediate, session-level alternative for Windows 10 and later. By combining these approaches with default user profile modification, administrators can fully automate keyboard configuration for both existing and future user accounts on any machine.