Set keyboard layouts available on logon screen in Windows 8.1

While we worked on Windows 8.1 deployment, we were required to make multiple keyboard layouts available on the Windows logon screen. All our computers came pre-staged with standardized corporate image, so we were not able to put these settings directly into the image. The only possible solution seemed to be using the Control panel > Region and Language Settings > Administrative > Copy settings…


But that would require clicking through the GUI on every staged computer and I needed a way to automate it. I used ProcessMonitor.exe to see what is happening when I click the OK button in the dialog, but unfortunately that did not help.

I needed a different idea, so I started thinking: The logon screen is in fact LogonUI.exe that is running in the context of the System account. I searched the web and found that the settings for normal user are located in: HKEY_CURRENT_USER\Keyboard Layout\Preload. And mine looked like this:


Current user hive of the SYSTEM account is HKEY_USERS.DEFAULT and luckily Keyboard Layout\Preload key was there. I copied my settings there and restarted the station, hoping for the best.

When the station booted back to the logon screen, the correct keyboard layouts were available there, so this approach should work. Copying the Registry values from one place to another might work but I wanted something more intuitive and flexible.

The International module, introduced in Windows 8 and Windows Server 2012, provides *-WinUserLanguageList cmdlets to manage the keyboard layouts of the current user and I wanted my function to integrate with them nicely.


The Set-WinUserLanguageList prompts for confirmation and also warns you if some of the provided languages were invalid and I wanted that behavior too, so this is the function I ended up with:

function Set-WinLogonLanguageList

 	Sets the keyboards visible on the logon screen

 	This function provides automated way to copy the keyboard settings of the current user to the Windows logon screen.
  	It provides part of the functionality available in Region and Language Settings control panel.
  	Region and Language Settings > Administrative > Copy settings... ->
	Copy to New Users and Welcome Screen > Welcome screen and system accounts

	Computer restart is needed after the change.

	.PARAMETER LanguageList
	Accepts list of user language objects.

	Forces the change and computer restart without prompting for confirmation.

	Enables restarting the computer when the settings are updated.

	Get-WinUserLanguageList | Set-WinLogonKeyboardList -Force

	Sets the keyboard layouts of the current user to be available on the logon screen without asking for confirmation.

			ValueFromPipelineByPropertyName = $true


	begin {
		$list = @()

	process {
		foreach ($language in $LanguageList)
			$list += $language

	end {

		if ($Force -or $PSCmdlet.ShouldProcess(
			"Windows logon screen",
			"Set avalilable language(s) to: $($finalList.EnglishName -join ', ')"
		) {
			$path = "Microsoft.PowerShell.Core\Registry::HKEY_USERS\.Default\Keyboard Layout\preload"

			#remove the current registry settings
			$current = (Get-Item $path).Property
			Remove-ItemProperty -Path $path -Name $current -Force

			#remove languages that are not installed on the system
			if ($list | where { -not $_.Autonym } )
				Write-Warning "The list you attempted to set contained invalid langauges which were ignored"
				$finalList = $list | where Autonym
				$finalList = $list

			$languageCode = $finalList.InputMethodTips -replace  ".*:"

			for ($i = 0; $i -lt $languageCode.count; ++$i)
				New-ItemProperty -Path $path -Name ($i+1) -Value $languageCode[$i] -PropertyType String -Force | Out-Null

			if ($languageCode) {
				#restart only if changes were made
				if ($Restart -or $Force -or $PSCmdlet.ShouldProcess("Computer","Restart computer to finish the process."))
					Restart-Computer  -Force

The function requires Windows 8.1 (or Windows 8) and the elevated privileges to run successfully.

At this point one last catch reminded. During the post-deployment tasks the script is executed under the SYSTEM account. So getting the list of languages using the Get-WinUserLanguageList would only re-apply the settings that were already in place. I had to build the list myself and at first I used the following code:

$list = New-WinUserLanguageList -Language cs-CZ
Set-WinLogonLanguageList -LanguageList $list -Force

But then I realized I was making it more complicated than it had to be and used just:

Set-WinLogonLanguageList -LanguageList cs-CZ, en-US -Force

About the author: Jakub Jareš

Jakub Jareš is an IT professional with strong background in Windows desktop systems. He started with Powershell a few months ago, and couldn't let go ever since. Showing that with the right attitude, a bit of effort and lot of practice you can become advanced in Powershell in no time.

Related Posts