Roberts Blog

The House of SCCM and Intune on System Center Street

Tag: Windows 10

Windows 10 Automation–Changing Language–B1903

A customer of mine is in the process of bringing the image factory back in-house, leveraging their ConfigMgr installation, hosted in Azure, to deliver Windows 10 task sequences (build and upgrade) to intranet and eventually via their CMG, internet based devices.

The quality bar is relatively basic from the MSP that is responsible for purchasing, preparing and shipping their devices to their end-users, so it hasn’t taken long to spin up OSD in ConfigMgr, and match the build results, producing a better tooled, more customised build that meets their needs and goes several steps further, while they handle purchasing via the MSP and do the delivery themselves.

Managing the Windows 10 image factory using ConfigMgr is an interim measure for this specific customer, at some point they will swing towards using AutoPilot as part of their modernisation and cost reduction plan that we’ve come up with, which includes the ultimate objective that a company can have nowadays, or an IT pro can have on their radar, the biggy, winding up Active Directory.

Part of this customers image factory requirements is that the build starts out life in English (en-GB), so that their build engineers can customise the OS further with a bunch of tasks that haven’t been brought into the task sequence at this point, due to time restraints or Windows 10 B1903 related bugs (VPN settings annoyances when setup in SYSTEM context, SCCM delivered Wifi profile password woe’s …). Finally the customer wants to be able to switch the builds language to that required for the target user, just before they close the lid and begin shipping.

In this post I’m going to show how I handled the customers language requirements in Windows 10 using SCCM OSD, leaving some footprints on ground already well-trodden by notable others.

Straight out of the gate I was experiencing issues setting the language reliably in Build 1903.

I tried to approach using the unattended setup file, that ‘trusty’ old horse, and when that wouldn’t play ball, I turned to using brutality with DISM and PowerShell applets at the tail end of the task sequence, in an attempt to coerce the operating system into doing my bidding. Failure is a spur towards success for the less weak-of-heart, is what I say when things just don’t work. Surely there has to be a way.

I cruised the net. Saw much chatter about language issues in various Windows 10 builds, most of it seemingly unrelated noise, I noticed a post by Dan Padgett where he uses a different method, RUNDLL32 and an XML file (or two), passed it by, I recall at the time thinking that it most likely was for an older version of Windows 10 and looked pig ugly Smile

At my whit’s end, I reached out to Paul Winstanley, who promptly pointed me back at Dan’s post as the only reliable way he could get it all to work at present.

Dan’s post is actually quite comprehensive and is in part a derivative of some of the ground work carried out by Nicolas Lacours [Link here], there isn’t much more for me to add if anything, a Stirling job indeed, instead I’ll show how I leveraged the proposed method to switch languages during and after OSD.

So yeah, I implemented Dan’s write-up on using the RUNDLL32 method, and viola, after a bit of tinkering to match up with the task sequence variables in use, and after ironing out SillinessFromMe™, I was able to produce a build in any of the list of languages the customer needed.

Now that language in the newly built OS was controllable (thanks Dan and Nicolas, and Paul for circling me back there!) the next step was to force it to build with en-GB, while storing away in the registry what was chosen as the destination language when UI++ launches, so that it can be read in and processed another time to do the final language switch.

At this point the build engineer has an en-GB build to log into, and do whatever they want in readiness for the user.

The next piece was the final language switch, I used another task sequence, with all the language steps from the main task sequence copied across and some additional bits added, and then deployed as Available to the OSD build collection.

This then showed up in Software Center, and could be run as the final task before the device is powered off and shipped.

I’ll now go over the OSD build parts where it differs from Dan’s, and has notes worth pointing out, as I said there wasn’t much need for any change from what he has already etched out.

At the front-end of the task sequence, UI++ runs and interviews the build engineer:

  1. Launch UI++, buzz the engineer for build details and store selections in task sequence variables
  2. Stored the resulting OSDUILanguage value in a new task sequence variable called StoredOSDUILanguage, which is then used at the tail-end of the task sequence as part of the branding\tattooing (not MDT tattoo) of the device
  3. OSDUILanguage is forced to become en-GB to model the experience needed, this is the override that will force all builds to be en-GB initially

After the Setup Windows and ConfigMgr step, we break into the steps to handle the language.

Pretty much how Dan does it. I think the only difference is that I put the Language pack logic on the steps, and added the UK keyboard instead of US.

The final part of the solution in my task sequence runs just before the task sequence finishes up, and is used to poke the value stored away in the task sequence variable StoredOSDUILanguage, into the registry for later use alongside a few other settings.

Aside from my modifications, if you follow Dan’s guide, and you’ll get perfect a result every time. Very nice.

The task sequence to do the final language switch is part-clone of the OSD build task sequence steps, along with some customisations.

As you can see the structure of the change language task sequence is a copy\pasta of the OSD build task sequence with some added bits:

What’s happening:

  1. OSDUILanguage, the task sequence variable doing all the language donkey work, is set to en-GB as a default in case anything goes awry
  2. The registry key OSDUILanguage is retrieved from the registry and poked into OSDUILanguage, I do this using a PowerShell script stored in the same package hosting the language injection script from Dan
  3. A task sequence variable that I use to confirm if the language can be changed, BeginProcessing, is initialised as False
  4. OSDUILanguage is used to drive the dynamic variable step, each rule sets the BeginProcessing variable to True

5. The Begin group has logic on it that will skip the group if BeginProcessing isn’t true, which essentially ends the task sequences execution.

The rest is identical to the OSD build task sequence, the language is laid down, three reboots occur, and bosh the language has changed for new users (who have not already logged in). I will no doubt finesse this out a bit more to do error handling and an existential check on the registry key to trigger an abort if missing.

The PoSh to retrieve the registry key, which most likely can be done better, is here:

$tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
$regValue = Get-ItemProperty -Path ‘HKLM:\Software\<COMPANY NAME HERE>\Branding’ -Name OSDUILanguage | Select OSDUILanguage
$tsenv.Value(“OSDUILanguage”) = $regValue.OSDUILanguage
Write-host (“Found language ” + $regValue.OSDUILanguage)

We can probably collapse that into a single line executed using a Run Command Line step and do away with the script. Be ideal if ConfigMgr let us read directly from a ‘repository’ such as the registry as a task sequence step, and poke the value into a task sequence variable.

With this mechanism in place, simply changing the registry key from say fr-FR to de-DE and running the task sequence from Software Center will swap languages for new users only.

I couldn’t get it to switch the language for any profiles that were already created on the device.

The build engineers profile remains en-GB, however the destination user once they log in for the first time will have the correct language set.

Now the customer has a handle on their Windows 10 builds, and language is slotted into place to fit their needs, initially configured as en-GB, then configured with one of several other languages supported by the company in readiness for delivery.

All in all a job well done I thought.

I might take a look into changing the language for all users not just new users, and whittle up a post on it at some point if its doable without the user having to be logged in.

ConfigMgr and MSIX authoring

Technical Preview 1810.2 introduced the first cut for converting MSI’s to the new application installation technology MSIX, direct from the ConfigMgr console, and in this post I’m going to kick the features tyre’s and try to get an end to end test out of the way.

Head over to the TP documentation here.

We have some funky technologies to install:

  • MSIX Packaging Tool from the Microsoft Store
  • Latest Windows Insider version of Windows 10

I’m using the following build version:

  • The Windows SDK, which you will need later on as it contains the tooling needed to sign the MSIX so that it be can deployed
  • The ConfigMgr Console.

I opted to install the SDK and Console inside the Windows 10 Insider Preview VM, and run things from there.

I’d recommend with TP1810.2 to edit a ConfigMgr Console XML file to remove an XML attribute, this tripped me up further into the process:

It is called out in the documentation, follow it there. Will be fixed in next TP’s.

I downloaded the Windows SDK ISO and installed everything, initially I tried to install just Windows SDK Signing Tools for Desktop Apps but it left me short of some of the signing tooling such as MakeCert, Pvk2Pfx.

To actually author an MSIX, ConfigMgr is going to drive the MSIX Packaging Tool, giving it the MSI and waiting for the tool to spit out the MSIX.

So let’s get the MSIX packaging tool and install it.

You can open the Microsoft Store from within the Windows 10 Insider Preview build, or open a browser in there and use that to navigate into the store:

Below we’re ready to get the MSIX Packaging Tool from within the Microsoft Store.

With that in place we’re now ready to convert an MSI.

I’m using my LogLauncher MSI, which is not trusted and thus is marked as Unknown Publisher. Most MSI’s direct from vendors will have the publisher listed, I’m cheap, and didn’t want to pay lots of money for a signing license, so all my community-tooling is as Unknown Publisher. When it comes time to make a signing certificate to sign this MSI we’ll return to this point.

Note that the reference MSI must not be installed before you proceed.

Opening the Console installed into the Windows 10 build, I visit Applications and right clicked off of LogLauncher, as you see below, the option to Convert to .MSIX is listed, select it:

Read and make sure you’re sorted:

Also make sure the Applications content source is accessible, it will be referenced. We’re not it seems, taking the content from the Content Library but the content source.

Provide an output location for the MSIX Packaging Tool to spew out an MSIX:

Notice the Publisher is noted as CN=Unknown Publisher:

Let it proceed.

You can monitor the CBS and DISM logs, which spew out lots of information as the process proceeds down the rail towards an MSIX.

I noted that logs and other files are deposited inside:


If it fails, refer to the log file in DiagOutputDir, no issues then you’ll be met with success:

Here’s my new MSIX for the LogLauncher MSI:

I renamed it to LogLauncherV3.6.msix.

MSIX is a container, and if you rename the extension to zip you’ll be able to navigate around, even extract the contents.

Note that the MSI will now be installed on the reference system, uninstall it. Remember also that to repeat the conversion process you will need to uninstall the MSI, also note I had issues repeating the conversion and put it down to file lock sensitivity on logs and possibly the log folder.

Here’s a reference to the MSI being installed:

If you try to install the MSIX, no dice, since it is not signed:

So now we come to signing the MSIX.

This isn’t done in-console today, we jump out and I signed using the CA PKI and the SIGNTOOL unsuccessfully, then with some assistance from the PG reverted to self-signed certificates which was successful.

I won’t cover the CA PKI work as it resulted in failure, I’m not 100% sure if this is expected but for the purposes of turning the handle on the feature, self-signed certificates carried the day, and I’ll document those steps so you can proceed as I did.

You’ve got the SDK installed, so open a CMD prompt and navigate into the Windows SDK folder, C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64 for a default installation.

1. MakeCert

We create our self-signed CER certificate file and private key file.

MakeCert /n “CN=Unknown Publisher” /r /h 0 /eku “,” /e “01/01/2040” /sv c:\temp\UnknownPublisherKey.pvk c:\temp\UnknownPublisherKey.cer

If you get a pop-up interactive dialog select None to proceed. I didn’t get this the second time around, and I don’t have Conan around today to offer his wisdom as to why, he’s off rescuing ladies, stealing jewels or overthrowing a bad guy I guess.

2. Pvk2Pfx

We then bundle the CER and PVK together into a PFX.

Pvk2Pfx -pvk c:\temp\UnknownPublisherKey.pvk –pi password -spc c:\temp\UnknownPublisherKey.cer -pfx c:\temp\UnknownPublisherKey.pfx -po password

3. SignTool

Now we sign the MSIX with the PFX certificate.

SignTool sign /fd SHA256 /a /f c:\temp\UnknownPublisherKey.pfx /p password c:\temp\LogLauncherV3.6.msix

Once we’re signed okay, we need to store the CER file into the Windows 10 Insider Preview computers Trusted Root Certification Authorities so that our certificate is trusted.

The next hurdle is to enable sideloading in Windows 10:

To install this app, turn on sideloading mode in Settings > Update & security > For developers. If you can’t turn it on, ask your system administrator to unlock the machine for sideloading (0x80073CFF)

If you have this managed in Group Policy great, otherwise head to GPEDIT.MSC on the Windows 10 Insider Preview build, and navigate down to Computer Configuration\Administrative Templates\Windows Components\App Package Deployment\All all trusted apps to install and enable it:

Helpful information on how to do this here:

We can now enable the Sideload apps option: