MSEndpointMgr

Automatically retain installed Language Packs during Windows 10 Servicing

When dealing with Windows 10 upgrades on systems that have a single or multiple language packs installed, most of the time you’d want to keep the same experience in terms of language preferences that existed before the upgrade. As of writing, the Windows setup upgrade experience does not retain the existing language packs installed on the device. You could simply get around this, by simply installing the language packs again in a post-upgrade section of an upgrade tasks sequence. However, it’s my experience that many organizations either leave the language pack installation up to the user, or install them based upon some sort of condition, making the environment diverse in terms of installed language packs. Some organizations are also just installing a set of language packs on all of their machines making it easier for themselves to maintain during an upgrade of Windows 10. Although, the language packs needs to be reinstalled.

There’s also the fact that with Windows 10, there’s a scheduled task in place that removes the unused language packs after a certain time. For more information about this, read the following documentation:

https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/add-language-packs-to-windows#LPRemovalTimer

What can we do about this? What’s the easiest way forward that requires minimal work for us before any future Windows 10 servicing upgrade? By using a bit of script logic and the ConfigMgr WebService, we can quite easily detect the existing language packs, download the proper language packs for the targeted Windows 10 version and have the setup upgrade engine take care of the rest for us.

In this post we’ll go through the process of dynamically retaining the existing language packs on a device and reinstall them during Windows 10 servicing. This process involves the following:

  • Install ConfigMgr WebService
  • Create Language Pack packages
  • Implement Dynamic Language Pack detection script

When all of the pieces are in place, for future Windows 10 servicing upgrades, all you need to do is to create the language packs for each new version of Windows 10. To give you a better understanding what it is that we’re trying to accomplish here, let’s picture the following scenario:

  • You’re tasked with upgrading 100 devices running Windows 10 version 1607 to Windows 10 version 1709 using ConfigMgr
  • You have no clue what language packs are currently installed on the devices
  • You want to make sure that any potentially installed language packs are retained after the upgrade

Obviously we could attempt to detect the installed language packs, but wouldn’t it be easier if we didn’t have to? That’s the main idea with this approach, so let’s dive into the details.

NOTE – This solution does not work for scenarios where your devices may have been installed with e.g. English International, and you attempt to upgrade with an English US media.

Install ConfigMgr WebService

Installing the ConfigMgr WebService is already documented within the installation guide embedded in the download package, please see the following page on how to obtain and install it:

ConfigMgr WebService

NOTE – Make a note of the secret key shown during the installation of the web service, you’ll need to later on.

Creating Language Packs packages

With the ConfigMgr WebService installed, the next step would be to prepare ConfigMgr with the language pack packages for Windows 10 version 1709. What I tend to do, is to download the ISO containing the language packs and previously I just manually created the packages required. However, recently when starting working on the detection and download script for this post, I figured that I’d also throw in a script that could easily create the language pack packages.

Below is an example of the script being executed:

NOTE – By not specifying the LanguagePacks parameter, it will automatically create a package for all language packs available on the media.

And the result in the ConfigMgr console (script has been executed to create packages for both Windows 10 version 1703 and 1709):

If you wish to manually create these packages, it’s important that you define the Version and Language properties like shown in the picture above. It’s also required that the name of the packages contain some sort of prefix that the second script (described further down in the post) can use to filter for only these language pack packages.

Make sure that you distribute these packages to your Distribution Points. With that, language pack packages are now in place, we’re ready to continue with implementing the task sequence steps to detect and download the packages.

Implement Dynamic Language Pack detection script

The last piece of the puzzle for this solution to work, is another script called Invoke-CMDownloadLanguagePack.ps1. This script is custom built for running inside an upgrade task sequence and plays the role of detecting the currently installed language packs on the operating system before the upgrade takes place. It also detects the default system culture, for instance en-US. With this information at hand, the script can determine what language pack packages needs to be downloaded from ConfigMgr, excluding any package that match the default system culture. At this stage, this is where the ConfigMgr WebService is being utilized. This script will query the web service for a list of packages matching what’s specified in the Filter parameter.

NOTE – Invoke-CMDownloadLanguagePack.ps1 script logs to a file called LanguagePackDownload.log available in the same directory as the smsts.log file. For the actual download part, using OSDDownloadPackage.exe, that executable is logging in the smsts.log file.

Let’s take a look at how it looks like in an upgrade task sequence.

  • Download Invoke-CMDownloadLanguagePack.ps1 from the following URL:
  • Create a regular Package without a Program and point the data source to where you’ve stored the script.
  • Before the Upgrade the Operating System group, create a new group called Stage Language Packs.
  • Add a Run PowerShell Script step, call it Detect Language Packs point to the newly created package, and configure the following:
    • Script name: Invoke-CMDownloadLanguagePack.ps1
    • Parameters: -URI ‘https://server.domain.com/ConfigMgrWebService/ConfigMgr.asmx’ -SecretKey ‘YOURSECRETKEY’ -BuildNumber ‘16299’
      -OSArchitecture ‘x64’ -Filter ‘Language Pack’
    • PowerShell execution policy: Bypass
  • Add a Set Task Sequence Variable step named Set OSDSetupAdditionalUpgradeOptions right after the Run PowerShell Script step, with the following values:
    • Task Sequence Variable: OSDSetupAdditionalUpgradeOptions
    • Value: /InstallLangPacks %OSDLanguagePack01%

Detect Language Packs step

Set OSDSetupAdditionalUpgradeOptions step

Before and after an upgrade

This is an image taken from a virtual machine in my lab environment that has the Swedish language pack installed and enabled:

Below is a picture showing the Windows 10 version 1709 upgrade task sequence, running Invoke-CMDownloadLanguagePack.ps1 script:

Once the upgrade has completed, the language pack installed in the previous operating system have been reinstalled and is still active:

A trimmed down video recording of the Windows 10 version 1607 to 1709 upgrade is available as well:

And that’s it, you can now go ahead and service Windows 10 and retain those language packs on your devices.

Nickolaj Andersen

Chief Technical Architect and Enterprise Mobility MVP since 2016. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows devices and deployments including automation. Awarded as PowerShell Hero in 2015 by the community for his script and tools contributions. Creator of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService to name a few. Frequent speaker at conferences such as Microsoft Ignite, NIC Conference and IT/Dev Connections including nordic user groups.

20 comments

  • I would love to see something similar for those of us who are installing feature updates “as a patch”. From other websites, I’ve learned that if you pre-deploy a setupconfig.ini file to the proper place (see https://www.asquaredozen.com/2019/08/25/windows-10-feature-updates-using-setupconfig-ini-to-manage-feature-updates-in-the-enterprise/), the Windows 10 feature update will respect the settings in that file. Those settings include a setting called “PostOOBE” where you can specify a command to run after the upgrade but before a user logs in (must be called “setupcomplete.cmd”). That would be perfect for re-applying the language packs (or there is a setting called “installlangpacks”, but it installs every language pack that exists in a given folder). However, I don’t see a setting that can call a script before the upgrade starts to detect the language packs in the first place. Normally, simply using Dynamic Update will preserve the language packs, but that may not be an option for us since we have low bandwidth to the internet and about 50,000 workstations to upgrade.

  • Dariusz the issue you are seeing is due to Microsoft changing the paths and naming conventions of the Language Pack iso. I got around this by extracting the ISO and changing Nickolaj’s script to also rename the language pack files.

    There appears to be a problem with the task sequence as listed in the blog. The PowerShell script is setting the OSD variable OSDSetupAdditionalUpgradeOptions, so why is the “Set OSDSetupAdditionalUpgradeOptions” step needed? If I leave that step in the TS, then the TS will fail if there is only 1 language pack installed. If I remove it, the TS completes successfully with only one LP installed and multiple LP’s installed.

  • Hi Nickolaj,
    I ma trying to use your great script in order to get the language packs created but I am getting the following:
    .\New-CMLanguagePackPackage.ps1 -SiteServer “servername” -ISORootPath “E:\” -PackageSourcePath “\\servername\osd\OS_Packages\LanguagePacks” -LanguagePacks “da-DK”, “sv-SE”, “nb-NO” -LanguagePackArchitecture “x64” -PackageName “Windows 10” -WindowsVersion “1809” -WindowsBuildnumber “17763”

    WARNING: Unable to copy Language Pack file. Error message: Cannot bind argument to parameter ‘LiteralPath’ because it is null.

    Any advice please?

  • Hi and thanks a alot for this great solution. I am about to upgrade 1709 to 1809 and wonder if this is still the way to go. I cannot find any builtin solution in SCCM to support upgrading and keeping MUIs. I find it really strange that MS is ignoring this scenario.
    Regards
    Olof

  • Hi, I have an issue with this script which I’m wondering if anyone has a solution to.

    Our machines are built using en-us media and then the en-gb LP was installed manually, so i thought about using this to automate it.

    the problem is, Get-WmiObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty MUILanguages only detects en-us,

    but if i run get-winuserlangguagelist, it shows both en-us and en-gb

    any ideas?

  • […] With that taken care of lets move on to sorting the language packs. To sort this there are two things we need to sort out. First up is making sure to reinstall all language packs that are already installed. Now Nickolaj Andersen over at SCConfigMgr has an awesome post on how to do that, read that here https://msendpointmgr.com/2017/11/06/automatically-retain-installed-language-packs-during-windows-1… […]

  • Hi Nickolaj,
    Thanks for your work on this. My IPU TS to Win10 1803 x64 does fail, however, if I only have en-us and no other language packs installed (I am only doing Win10 to Win10 IPU). Have you seen that in your testing? The windows setup fails with an error of 80070003. If I have another LP installed, the process completes successfully. I am using CM 1706 and the latest 1803 ISO from VLSC.

  • Hi Nickolaj,

    I tried your solution above and currently have issue with package downloading via IIS (see error message on very bottom). Account for WebServices has been created and in SCCM have full administrator permissions. But for some reason package can´t be downloaded. Just one more info WebServices are installed on Primary server (this is also MP) and we have several secondary sites from where we are staging. Do you have some idea what could be wrong or if I need some more permissions?

    error message (please ignore fake server name):

    Unable to establish a connection to web service. Error message: Fehler beim Downloaden von ‘https://Server01.mydomain.net/ConfigMgrWebService/ConfigMgr.asmx’.

      • I hope I´ve added all parameters properly, but have this error:

        Unexpected token ‘$Web’ in expression or statement.
        + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
        + FullyQualifiedErrorId : UnexpectedToken

        Lukas

  • Nickolaj,

    Thanks for the information provided above. I’m curious though in addition to the language packs. I have found that it is also a good idea to install the features on demand for each of the language packages.

    If I copy the individual language files for each of the features on demand into the source folder for the language packs they should get copied down to the machine as part of the deployment. The question is will the get installed using the /InstallLangPacks %OSDLanguagePack01% command or will something else need to happen.

    This is the command I typical use when manually applying the language packs to an existing Windows 10 English deployment.

    $files = (gci -Path “langpacks\$winVer\$osArch” -File | Sort Name).Name
    foreach ($file in $files) {
    dism.exe /online /add-package /packagepath:langpacks\$winVer\$osArch\$file
    }

    • Hi Paul,

      I’ve not used that method before, so I don’t have a good answer for you. But I’m assuming it’s cab files that you’re talking about? If so, I’d believe they should work. But why not use the ISO from Microsoft?

      Regards,
      Nickolaj

      • Hey Nickolaj,

        We are using the ISOs from Microsoft but we basically extract the 6 files we need for the language packs and the features on demand and place them into a folder and then using a script execute them in the order they need to be installed.

        So I’m curious if I add those files to the source content created by this tool and update the content would the task sequence be able to run those additional files?

        Paul

  • Hi Nickolaj,

    i think i’ve done something wrong in the past. I created a master WIM using en-US later on i applied several Language Packs depending on the client’s location.
    Now i can’t service this machine (e.g. de-DE) with en-US media, i need to service it with de-DE Media.

    With that fact, i can’t use your solution, as i need to specify seperate Upgrade Packages per Langauge.
    Do you know what i’ve been doing wrong?

Sponsors