3

I'm building a code to fix keyboard layout situation on windows 10. With automated solution, I decided to use powershell. But the problem is that I'm pretty new in it and face certain problems. I managed to dig a script to change keyboard layouts, however it changes only to one language. As I try to create array with 2 languages:

$langlist=$lang_en,$lang_ru
set-winuserlanguagelist $langlist

It simply returns me next error:

Set-WinUserLanguageList : Cannot convert 'Microsoft.InternationalSettings.Commands.WinUserLanguage' to the type
'Microsoft.InternationalSettings.Commands.WinUserLanguage' required by parameter 'LanguageList'. Specified method is
not supported.
At line:1 char:25
+ set-winuserlanguagelist $langlist
+                         ~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-WinUserLanguageList], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.InternationalSettings.Commands.SetWinUserLanguageListCommand

When I tried to use next command: $test = Get-WinUserLanguageList, the command works well with set-winuserlanguagelist.

The full script:

$keys='0809:00020409', '0419:00000419'

$lang_en=new-winuserlanguagelist en-gb
$lang_en[0].inputmethodtips.clear()
$lang_en[0].inputmethodtips.add($keys[0])

$lang_ru=new-winuserlanguagelist ru
$lang_ru[0].inputmethodtips.clear()
$lang_ru[0].inputmethodtips.add($keys[1])

$langlist=$lang_en,$lang_ru

set-winuserlanguagelist $langlist
Di1997
  • 119
  • 1
  • 2
  • 13
  • Question is no longer actual. The reason behind the problem was type of the variable. I declared it wrong way. The right way was: `$langlist = New-Object "System.Collections.Generic.List[Microsoft.InternationalSettings.Commands.WinUserLanguage]"` – Di1997 Mar 04 '18 at 20:33
  • 1
    The real problem was that you created an array of _lists_ rather than an array of `[Microsoft.InternationalSettings.Commands.WinUserLanguage]` instances. The awkward design of the `New-WinUserLanguageList ` cmdlet is to blame for that, which is still worth addressing in an answer. – mklement0 Mar 04 '18 at 22:22
  • 2
    P.S.: As an aside, allow me to give you a language tip: by "actual" you probably meant "no longer relevant". ["actual" means something closer to "real"](https://www.ahdictionary.com/word/search.html?q=actual) – mklement0 Mar 04 '18 at 22:22
  • Thanks for the explanation. I understood that problem when I was trying to understand errors a little more. Creating a list of lists fixed the problem and cmdlet works as I needed. And yeah, wanted to close question, but don't know how. But at least people spent their time explaining things to me, which I really appreciate – Di1997 Mar 05 '18 at 01:23
  • Glad to hear it. In case it wasn't just a typo: it wasn't creating a list of _lists_ that fixed the problem, but a list of `WinUserLanguage` instances - which is what `New-WinUserLanguageList` _should_ allow you to do with _multiple_ languages - but currently doesn't. As for closing your question: you can _delete_ it, but - as in this case - that's not a good idea when answers have already been posted (and, as stated, your question is useful in that others may make the same mistake). – mklement0 Mar 05 '18 at 01:31

3 Answers3

2

Please check the following commented code snippets:

PS D:\PShell> ### Type mismatch

$langlist=$lang_en,$lang_ru

### Note the difference in type:

$langlist.gettype().Name                   ### Object[]

(Get-WinUserLanguageList).gettype().Name   ### List`1
Object[]
List`1
PS D:\PShell> ### Use the following:

$langlist = Get-WinUserLanguageList
$langlist.Clear()
$langlist.Add($lang_en[0])
$langlist.Add($lang_ru[0])

$langlist.gettype().Name                   ### List`1
List`1
PS D:\PShell> <### The next cmdlet should work now:

set-winuserlanguagelist $langlist

<##>
JosefZ
  • 28,460
  • 5
  • 44
  • 83
2

The problem is that you're using New-WinUserLanguageList twice, with each call returning a list, so that $langlist = $lang_en, $lang_ru mistakenly created an array of (single-item) lists rather than a single list with two items, which caused the (nonsensically-sounding) type-mismatch error you saw.

Very awkwardly, however, cmdlet New-WinUserLanguageList only allows you to specify one language, even though it returns a list type ([Collections.Generic.List[Microsoft.InternationalSettings.Commands.WinUserLanguage]]).

That is, the following should work, but doesn't:

# Try to create the list with *2* entries
$langlist = New-WinUserLanguageList en-gb, ru  # !! Doesn't work, parameter type is [string]

Instead, you have to initialize with 1 language and then add additional ones later, using the .Add() method:

# Create the list with initially just 'en-gb'...
$langlist = New-WinUserLanguageList en-gb

# ... and then add the other language, 'ru'
# Because the list is strongly typed, it is sufficient to pass the language
# identifier, which implicitly creates a new
# [Microsoft.InternationalSettings.Commands.WinUserLanguage] instance.
$langlist.Add('ru')

# Now you can modify the properties of $langlist[0] (en-gb)
# and $langlist[1] (ru)
# ...

# ... and pass the list of modified languages to Set-WinUserLanguageList:
Set-WinUserLanguageList $langlist

Alternatively, to avoid the .Add() call, you could have used:

$langlist = (New-WinUserLanguageList en-gb)[0], (New-WinUserLanguageList ru)[0]

Even though $langlist is then technically an array (a [System.Object[]] instance whose elements are of type Microsoft.InternationalSettings.Commands.WinUserLanguage), passing it to Set-WinUserLanguageList works, because it is implicitly converted to the required list type.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

The Set-WinUserLanguageList cmdlet has evolved (at lease since Win 20H1) and the syntax is now very straightforward:

Set-WinUserLanguageList -LanguageList 'fr-FR','en-US','en-GB'

If you want to add additional languages to the existing ones, you can use this code snippet:

$CurrentLanguageList = Get-WinUserLanguageList

$NewLanguageList = [System.Collections.ArrayList]::new()

foreach($Language in $CurrentLanguageList.LanguageTag){
    $NewLanguageList.Add($Language) | Out-Null
}

#Adding new languages here
$NewLanguageList.Add('de-DE') | Out-Null
$NewLanguageList.Add('ru-RU') | Out-Null

Set-WinUserLanguageList -LanguageList $NewLanguageList
Luke
  • 1,734
  • 2
  • 15
  • 18