4

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…

image001

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:

image002

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.

image003

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
{
	[CmdletBinding(ConfirmImpact='High',SupportsShouldProcess=$true)]

	<#
  .SYNOPSIS
 	Sets the keyboards visible on the logon screen

  .DESCRIPTION
 	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.

	.PARAMETER Force
	Forces the change and computer restart without prompting for confirmation.

	.PARAMETER Restart
	Enables restarting the computer when the settings are updated.

	.EXAMPLE
	Get-WinUserLanguageList | Set-WinLogonKeyboardList -Force

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

	param(
		[Parameter(
			Mandatory=$true,
			ValueFromPipeline=$true,
			ValueFromPipelineByPropertyName = $true
		)]
		[Microsoft.InternationalSettings.Commands.WinUserLanguage[]]
		$LanguageList,

		[Switch]$Force,
		[Switch]$Restart
	)

	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
			}
			else
			{
				$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
$list.Add("en-US")
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
Filed in: Articles, Community, Online Only Tags: , ,

4 Responses to "Set keyboard layouts available on logon screen in Windows 8.1"

  1. Andy says:

    Unfortunately, the entries under HKEY_CURRENT_USER\Keyboard Layout\ Preload are deleted after login.
    After a SignOut only two languages ​​are available again.

    regards
    Andy

Leave a Reply

Submit Comment

© 2016 PowerShell Magazine. All rights reserved. XHTML / CSS Valid.
Proudly designed by Theme Junkie.
%d bloggers like this: