1

At my work we have 150+ workstations using Windows 7.
The default keyboard on the computers is set to German.
Soon there will be a new character - scanned on these workstations that the German keyboard reads as ß
So I am looking for the easiest way to set every keyboard to English as default.

The users on the workstations are very limited in access. All we can use is a tool with admin access to make changes. The tool runs as the admin account and we can access almost anything we want from it.

What I tried so far:

  1. A command line + xml script here on superuser.
    The problem with it is that it will change the default keyboard of the admin account, because the tool runs as the admin account. I also tried to run it as the local user but because of the restrictions it won't run.

  2. The other option I found is to modify the registry in
    HKEY_USERS\.DEFAULT\Keyboard Layout\Preload and set 1 to 00000409
    The problem with this is that I can not run a reg file as the current user because of the restrictions, and as the admin user it will apply this to the admin account. I can not identify the other users because they appear as example S-1-5-21-2013013795-1015563843-1545874412-206927 this code changes on different workstations. I can not use load hive, because it says that it is currently in use.

Is there another way I could try or a workaround for one of the solutions above to make it work?
It would also be a good solution to apply these to every users somehow.

EDIT:

I don't know if this helps but there is one thing that is common in HKEY_USERS: the accounts name we need to change always ends in [...]-1003 or [...]-1004

2 Answers 2

1

There are 2 options here: 1. to use psgetsid.exe to identify the correspondence of the username and user's SID that you see in HKEY_USERS and then use it in the batch script. In the same batch you can use psexec.exe to execute the required registry change on the remote computers. You can pass a text file with a list of the computers t these programs.

Usage: psgetsid [\\computer[,computer2[,...] | @file] [-u Username [-p Password]]] [account | SID]
     -u         Specifies optional user name for login to
                remote computer.
     -p         Specifies optional password for user name. If you omit this
                you will be prompted to enter a hidden password.
     account    PsGetSid will report the SID for the specified user account
                rather than the computer.
     SID        PsGetSid will report the account for the specified SID.
     computer   Direct PsGetSid to perform the command on the remote
                computer or computers specified. If you omit the computer
                name PsGetSid runs the command on the local system,
                and if you specify a wildcard (\\*), PsGetSid runs the
                command on all computers in the current domain.
     @file      PsGetSid will execute the command on each of the computers listed in the file.

2. The second option is to execute this Powershell script on the remote computers:

New-PSDrive HKU Registry HKEY_USERS
$allusers = Get-ChildItem -Path hku:\ | select -ExpandProperty name
foreach($i in $allusers)
{
    if (($i -like '*S-1-5-21*') -and ($i -notlike '*_Classes*')) {
        "Users found:"
        $i
        Set-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::$i\Keyboard Layout\Preload" -Name 1 -Value 409
        Set-ItemProperty -Path "Microsoft.PowerShell.Core\Registry::$i\Keyboard Layout\Preload" -Name 2 -Value 407
    }
}

It will scan through all available SIDs in the HKEY_USERS and apply the setting to each of them if they meet the filter.

P.S. All AD users SIDs start with S-1-5-21, that's why I used it in the filter. I also ignored all hives with _Classes in the end.

6
  • Tried the second one, it worked only after starting the script manually from powershell.exe and running Set-ExecutionPolicy RemoteSigned first. Is there a faster way to make it work?
    – Divin3
    Dec 15, 2015 at 12:11
  • @Divin3 Of course, you need to configure your powershell policy first in Windows always to run ps scripts whether they are signed or not for the solution above. I thought it is done on your computer already :)
    – Hardoman
    Dec 15, 2015 at 12:15
  • @Divin3 NOTE: To change the execution policy for the default (LocalMachine) scope, start Windows PowerShell with the "Run as administrator" option. You need to do it only once.
    – Hardoman
    Dec 15, 2015 at 12:22
  • So I need to start powershell.exe and enable powershell more than 150 times, than run the script? This would be painful.
    – Divin3
    Dec 15, 2015 at 12:25
  • @Divin3 No, If you run Set-ExecutionPolicy as administrator, the policy will be set for all users on one PC. But of course, you'll need to do it on every PC at least once. You can do it using psexec.exe using a list with PC names as I command.
    – Hardoman
    Dec 15, 2015 at 12:34
0

There are many options available:

  • You can start powershell.exe with the option -executionpolicy bypass. This way you won't have to set the execution policy on each machine. E.G.: powershell.exe -executionpolicy bypass
  • You can use PowerShell remoting to connect to every workstation and run the script remotely. No need for psexec. Off course you need to have PowerShell remoting enabled on all clients.
  • You can use remote registry to connect to the registry on all computers and change the settings directly. This is by far the best option. I've written a PowerShell function that you can use:
function Set-DefaultKeyboard
{
    [CmdletBinding()]
    Param
    (
        # Name of the computer
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [Alias('Name')]
        [string[]]
        $ComputerName,

        [Parameter(Mandatory=$true,
                   Position=1)]
        [string[]]
        $LayoutCode
    )

    Process
    {
        foreach ($Computer in $ComputerName) {

            Write-Verbose "Testing connection to '$Computer'..."
            IF (Test-Connection $Computer -Quiet -Count 1) {

                Write-Verbose 'Computer appears to be online.'
                $State = 'Online'

                #Connect remote registry
                try {
                    Write-Verbose 'Connecting with Remote Registry...'
                    $oReg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $Computer)
                }
                catch {
                    [pscustomobject]@{
                        ComputerName = $Computer
                        Result = 'Failed to connect.'
                    }
                    continue
                }
                Write-Verbose 'Connection established.'
                $AllUsers = $oReg.GetSubKeyNames() | ?{$_ -like '*S-1-5-21*' -and $_ -notlike '*_Classes*'}
                foreach ($User in $AllUsers)
                {
                    try
                    {
                        $KeyBoards = $oReg.OpenSubKey("$User\Keyboard Layout\Preload",$true)
                        $i = 1
                        foreach ($Code in $LayoutCode)
                        {
                            $FullCode = $Code.PadLeft(8,'0')
                            $KeyBoards.SetValue($i,$FullCode,[Microsoft.Win32.RegistryValueKind]::String)
                            $i++
                        }
                        [pscustomobject]@{
                            ComputerName = $Computer
                            Result = 'OK'
                        }
                    }
                    catch
                    {
                        [pscustomobject]@{
                            ComputerName = $Computer
                            Result = 'Failed to set values.'
                        }
                    }
                }
            }
            else
            {
                [pscustomobject]@{
                    ComputerName = $Computer
                    Result = 'Computer is offline'
                }
                continue
            }
        }
    }
}

You can use the function like this:

\> Set-DefaultKeyboard -ComputerName PC1,PC2,PC3 -LayoutCode 409

\> Get-ADComputer -Filter * | Set-DefaultKeyboard -LayoutCode 409,407

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .