Deploy languages via Software Center with PSCMWin10Language

Adam CookEndpoint Management, MECM/MEMCM/SCCM, Powershell, Scripting18 Comments


This post complements my other post, where I walk-through the differences of LP, LIP, LXP and FoD.

Here I will show you how to use a PowerShell module I wrote, PSCMWin10Languages, to create Microsoft Endpoint Manager Configuration Manager Applications for each language you want to deploy via the Software Center.

These Applications are not for OSD. It changes the language only for the user who installs the Application via the Software Center. They will not work for OSD via task sequence.

Install the module

The module can be found on GitHub or the PowerShell Gallery. You can install it like so:

Install-Module "PSCMWin10Language" -Scope CurrentUser

Check out what functions are given to you:

Import-Module "PSCMWin10Language"
Get-Command -Module "PSCMWin10Language"

Create LP, LXP and FoD repositories

We need to form the source folders for each of our Applications (in other words, for each language we want to support). The source folders will contain the needed LP, LXP and FoD files for each language – a mix of .cab and .appx files.

Using the below functions, we can create the need folders and populate them with the files by extracting them from the ISOs downloaded from VLSC / Visual Studio subscription download portal (MSDN).

  • New-LPRepository
  • New-LXPRepository
  • New-FoDLanguageFeaturesRepository

Note: New-FoDLanguageFeaturesRepository only extracts “LanguageFeature” FoDs. If you want to include more FoDs than these, you’ll have to arrange something yourself.

If you want to support fewer than a handful of languages, then this process is typically just about OK being completed manually. However, you will have to repeat this for each new version of Windows 10 which will quickly become a drag. Especially if you want to support many more languages. This is what inspired me to write these functions.

Let’s assume I want to support languages French and German. Our end goal is to create a folder structure that looks something like this:

PS C:\> tree "\\sccm.acc.local\OSD\Source\1909-Languages" | Select-Object -Skip 2
\\SCCM.ACC.LOCAL\OSD\SOURCE\1909-LANGUAGES
+---de-de
¦   +---FoD
¦   +---LP
¦   +---LXP
+---fr-fr
    +---FoD
    +---LP
    +---LXP

Start off by going to VLSC or MSDN and downloading the following ISOs for your target Windows 10 version:

  • Language Pack
  • Features on Demand (part 1)

Once downloaded, mount them all and go back to the PowerShell prompt where we imported PSCMWin10Language, and execute the following (replace the appropriate drive letters):

New-LPRepository -Language "fr-FR", "de-DE" -SourcePath "I:\x64\langpacks" -TargetPath "\\sccm.acc.local\OSD\Source\1909-Languages"
New-LXPRepository -Language "fr-FR", "de-DE" -SourcePath "I:\LocalExperiencePack\" -TargetPath "\\sccm.acc.local\OSD\Source\1909-Languages"
New-FoDLanguageFeaturesRepository -Language "fr-FR", "de-DE" -SourcePath "J:\" -TargetPath "\\sccm.acc.local\OSD\Source\1909-Languages"

Create the Applications

With the LP, LXP and FoD repositories set up, we’re now ready to create our ConfigMgr Application(s)

New-CMLanguagePackApplication -SiteServer "cm.contoso.com" -SiteCode "P01" -SourcePath "\\sccm.acc.local\OSD\Source\1909-Languages" -Languages "fr-fr", "de-de" -WindowsVersion @{ "Version" = "1909"; "Build" = "18363" } -GlobalConditionName "Operating System build" -CreateAppIfMissing -CreateGlobalConditionIfMissing

There’s quite a few parameters used here so let me explain them:

  • Site server and site code of your hierarchy, standard stuff
  • -SourcePath of where we exported all our languages’ LP, LXP and FoDs to
  • -Languages an array of Language tags of which we want to create Applications for. The elements of this array will correlate with the folders directly beneath the given -SouthPath
  • -WindowsVersion a hashtable which denoates the version and build number of Windows 10 you’re deploying language items for. Must contain two keys: “Version” and “Build”.
  • -GlobalConditionName name of the Global Condition which queries the WMI class Win32_OperatingSystem for property Build. If a Global Condition with the given name does not exist, a terminating error is thrown. If it does exist, but it does not query the Win32_OperatingSystem class for the Build property, a terminating error is thrown.
  • Lastly, the two switches -CreateAppIfMissing and -CreateGlobalConditionIfMissing does pretty much it says on the tin; creates those items if they’re missing.

This is what the end result looks like:

There are two deployment types: one which runs as user and the other which runs as system. The system deployment type installs LP, LXP and FoD. Whereas the user deployment type registers the LXP, configures the user’s language and prompts a reboot is required by returning exit code 3010.

The user deployment type depends on the system deployment type.

Poking around, you’ll notice the requirements for all deployment types are that of what you used in the -WindowsVersion parameter.

When you’re ready to support another OS, or another language, just repeat these instructions with that context in mind and you’re good to go!

For example, I used the same process again to create deployment types on the existing Applications for Windows 10 2004:

New-LXPRepository -Language "fr-fr", "de-de" -SourcePath "I:\LocalExperiencePack\" -TargetPath "\\sccm.acc.local\OSD\Source\2004-Languages"
New-LPRepository -Language "fr-fr", "de-de" -SourcePath "I:\x64\langpacks\" -TargetPath "\\sccm.acc.local\OSD\Source\2004-Languages"
New-FoDLanguageFeaturesRepository -Language "fr-fr", "de-de" -SourcePath "I:\" -TargetPath "\\sccm.acc.local\OSD\Source\2004-Languages"
New-CMLanguagePackApplication -SiteServer "cm.contoso.com" -SiteCode "P01" -SourcePath "\\sccm.acc.local\OSD\Source\2004-Languages" -Languages "fr-fr", "de-de" -WindowsVersion @{ "Version" = "2004"; "Build" = "19041" } -GlobalConditionName "Operating System build" -CreateAppIfMissing -CreateGlobalConditionIfMissing

Support

If you have any issues with the module, please do open an issue on the PSCMWin10Language GitHub repository!

18 Comments on “Deploy languages via Software Center with PSCMWin10Language”

  1. there is a problem with passing the “20H2” version to the AppCreation cmd-let
    It doeasn’t allow that format

    Also… i noticed that u are adding new language to the UserLanguageList at the end. Why not at the begining?
    It only requires to change:

    $List = Get-WinUserLanguageList; $List.Add(‘pl-pl’); Set-WinUserLanguageList $List -Force;

    to

    $CurrentLanguageList=Get-WinUserLanguageList ; $UserLanguageList = New-WinUserLanguageList -Language ‘pl-pl’; foreach ($l in $CurrentLanguageList){ $UserLanguageList.Add($l.LanguageTag)}; Set-WinUserLanguageList -LanguageList $UserLanguageList -Force;

  2. Hi, everything appears like it worked but when I try to install it I get a “This software is not applicable to your device”.

    Any ideas?

    And you did an awesome job creating this package.

    Thanks,
    Brian

  3. They are Hyper VMs running Win 10 1909. I did run it on a test laptop too but that has 20H2.

  4. The requirements in the application rules are OS system build equals 18363 and OS equals 64 bit

  5. After clicking install in the Software Center to install the lang pack. The application install starts, errors out a minute later with a message: Status: This software is not applicable

    1. Hi Brian, have you checked the logs? AppEnforce.log AppDiscovery.log and AppIntentEval.log. Feel free to create a shareable link for me to download them.

  6. Hey Adam, just want to say thanks for all of your help…………………….email me your Venmo account if you have one……Would like to buy you a beer or case of beer…Thanks

    1. Hey Brian, no problem glad I could help! No Venmo necessary (I don’t think it’s allowed in the UK anyway), maybe at MMS or something if that’s your jam.

  7. Hi Adam,
    small addition to the .psm1 – I had to implement another detection step to get around detection on multiple OS builds to trigger at the same time:

    Detection for Build – required due to variables being the same

    New-CMDetectionClauseRegistryKeyValue -Hive ‘LocalMachine’ -KeyName ‘SOFTWARE\Microsoft\Windows NT\CurrentVersion’ -PropertyType String -ValueName ‘CurrentBuild’ -ExpressionOperator IsEquals -Value -ExpectedValue $WindowsVersion[‘Build’]
    Right now I am fighting the issue that some languages do not have the country-language inside the languagetag of the userlanguagelist – like ja-jp has only ja, ko-kr only has ko in there, same for sk-sk, zh-tw, zh-cn – so set user language does not detect install and wants to reinstall.

    Greetings
    Matthias

  8. I am trying to run the script manually before creating a deployment and getting the following error on the install.ps1:
    WARNING: Add-WindowsPackage failed. Error code = 0x800f0818
    Add-WindowsPackage : Add-WindowsPackage failed. Error code = 0x800f0818
    Did i miss something? I am running on 1909.
    Thank you

    1. Hi Mike, it would be tough to help you if you’re doing this manually… but I’ll try… running things manually leaves all sorts open for user error. I guess first question is, what version of language media are you? The correct version for 1909?

  9. Adam, thanks for trying to help. I am running on Windows 10 1909. When running through the SCCM i am getting an error in the AppEnforce.log
    Unmatched exit code (1) is considered an execution failure.
    Before the error i see this line:
    Executing Command line: “C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe” -executionpolicy bypass -noprofile -file “.\Install.ps1” with user context
    I have two programs created. User with
    Priority 1 “powershell.exe -executionpolicy bypass -noprofile -command “$ErrorActionPreference = ‘Stop’; $p = (Get-AppxPackage | Where-Object { $.Name -like ‘LanguageExperiencePackja-JP‘ }).InstallLocation; Add-AppxPackage -Register -Path $p\AppxManifest.xml -DisableDevelopmentMode; $List = Get-WinUserLanguageList; $List.Add(‘ja-JP’); Set-WinUserLanguageList $List -Force; Set-WinUILanguageOverride -Language ‘ja-JP’; exit 3010″”,
    and SYSTEM
    #2. “powershell.exe -executionpolicy bypass -noprofile -file “.\Install.ps1″”
    From the log file i see that its only running #2 which is the Install.ps1, still cant figure out why its failing?
    Will this always run User only? Do i need to run both programs?
    A bit confused which programs must be run or both?
    I am trying to install ja-jp language pack. And i have downloaded the following media:
    en_windows_10_features_on_demand_x64_dvd_6846440.iso
    mu_windows_10_language_pack_version_1903_x86_arm64_x64_dvd_c45a68ac.iso
    Path to LP:”\1909-LANGUAGES\ja-JP\ja-jp\LP\Microsoft-Windows-Client-Language-Pack_x64_ja-jp.cab”
    Path to appx: “\1909-LANGUAGES\ja-JP\ja-jp\LXP\LanguageExperiencePack.ja-JP.Neutral.appx” – “\1909-LANGUAGES\ja-JP\ja-jp\LXP\License.xml”
    and i have 5 .cab files in FoD folder
    Thank you.

    1. Hi Mike, they’re not programs, they’re deployment types. You will notice one deployment type has a dependency on the other.

      A bit confused which programs must be run or both?

      You don’t need to be concerned with which one runs, they both do – just in a particular order, but again, that’s taken care of for you. You can’t choose which deployment types run like you can with programs and packages.

      Why do you have two nested ja-jp folders?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.