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:


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 ‘http://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

Principal Consultant 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. Currently working for TrueSec as a Principal Consultant. 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 and user groups.

  • ben
    Posted at 16:41 November 6, 2017

    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?

  • Paul Andrews
    Posted at 23:24 February 22, 2018
    Paul Andrews


    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

    • Nickolaj Andersen
      Posted at 23:29 May 18, 2018
      Nickolaj Andersen

      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?


  • Leave a Reply