Roberts Blog

The House of ConfigMgr and Intune on Endpoint Management Way

Tag: PowerShell

Delivering CMTrace using Intune during AutoPilot

In this post I’m going to go through the steps needed get the CMTrace tool onto a system during an AutoPilot build, purely so we can pour over logs without the hassle of manually bringing the tool onto the system, or copying the logs onto a remote system with the tool available.

During a failed AutoPilot build, reading the IME (Intune Management Extension) log is a bit of an “art” in of itself, but viewing that log in Notepad is no fun at all; And mapping a network drive so as to copy CMTrace locally is a chore that doesn’t bear repeating often. It’s best if the tool is delivered during AutoPilot.

Whatever we do we’re going to need to lean on Intune’s Win32 app delivery support (not the Line-of-business App which requires an MSI), which affords us the ability to package up multiple files and folders then invoke something in there. In our case the executable for CMTrace and a PowerShell script.

To begin we need to download that IntuneWinAppUtil tool and point it at the folder containing the files, upload the resulting INTUNEWIN file to Intune and deploy that as required to the AutoPilot devices.

There’s two notable ways to go at delivering CMTrace with Intune, firstly just package up the CMTrace executable without a script present and let Intune run a PowerShell command to copy the executable to a destination folder, or package up the executable along with a PowerShell script which does the copying.

You can include a script if for example you wish to do more than just copy the executable to a destination folder, such as associating CMTrace as the handler for the LOG and _LO extensions as EM MVP Jörgen Nilsson does in this excellent post. Or you could put most of it on a single command, but it is worth noting that there is a character limit in Intune for command lines so don’t make them too long.

The two approaches allow for different scenarios during AutoPilot, light and easy with the admin finding the tool and launching when needed, or with no need for an admin to launch the tool before opening a LOG file (file associations set).

In this post I’m going to use the scripted route to only copy the executable to the C:\Windows directory, and leave you to wander over to Jörgen Nilsson’s post if you want to add the file handler associations stuff (just paste his script content into the script created here).

I have a folder structure to build out Intune Win32 applications while using the IntuneWinAppUtil utility. I keep this separate from my ConfigMgr source folder. It has both a folder for the source files and a folder to accommodate the resulting INTUNWIN files that are spewed out by the IntuneWinAppUtil tooling:

  • Source\Intune\<Application Folders>
  • Source\Intune\INTUNEWIN\<Application Folders>

Here goes.

  • Create a build folder for CMTrace in your Intune application source folder, call it CMTrace
  • Copy CMTrace.exe to the build folder
  • Create a new PS1 file in the build folder and call it cmtrace.ps1
  • Open the PS1, pour in the contents below, as usual check that the quotation marks are correct, save the file. Worth running the script in-place to make sure it works before proceeding.

Here’s a basic script to work from:

Copy-Item “$($PSScriptRoot)\CMTrace.exe” -Destination C:\Windows\CMTrace.exe -Force

We now have CMTrace.exe and cmtrace.ps1 in the new build folder.

You can modify this script up with as many modifications as you want, I doubt there would be many for CMTrace, but for other deployments scripting opens a door that allows us to customise delivery as we need.

The IntuneWinAppUtil packaging tool is pretty easy to use, requires three inputs to run for most scenarios of source folder, source file (the exe or the ps1) and the output folder:


Here’s the command line to package CMTrace:

IntuneWinAppUtil.exe –C “D:\Source\Intune\CMTrace” –s “D:\Source\Intune\CMTrace\cmtrace.ps1” –o “D:\Source\Intune\INTUNEWIN\CMTrace”

We’re about to run the packaging tool:

Here’s the IntuneWinAppUtil tool after packaging the source folder:

Out pops the INTUNEWIN file:

Now we need to upload this to Intune:

From the Azure Portal or DeviceManagement portal add a new App:

Select the Windows app (win32) option and then click Select

Click on Select app package file, navigate to the INTUNWIN file and select it.

Give it a friendly name and description, I use CMTrace for both. And enter Microsoft as the Publisher:

Now comes the command lines, it is highly unlikely that we’re ever going to uninstall CMTrace, and if we wanted too we just need to issue a Remove-Item command line to do so, or create another PS1 script, instead, I just used the PS1 and ignore uninstall, set Device restart behavior to No specific action:

For uninstall we could do this: PowerShell.exe –executionpolicy bypass –command Remove-Item C:\Windows\CMTrace.exe

  • Install command

powershell.exe -executionpolicy bypass -file cmtrace.ps1

  • Uninstall command

powershell.exe -executionpolicy bypass -file cmtrace.ps1


PowerShell.exe –executionpolicy bypass –command Remove-Item C:\Windows\CMTrace.exe

Choose the architecture for your device estate, most are pure 64-bit but if you have a mix select both, then the minimum Windows 10 OS which in my case is Windows 10 1607 so as not to exclude any build versions that show up:

The detection rule is file based, and just looks for C:\Windows\CMTrace.exe.

Choose to manually configure detection rules and select Add:

Choose a rule type of File, then for the path punch in C:\Windows, for File or folder enter CMTrace.exe: and choose No for Associated with a 32-bit app on 64-bit clients:

As you can see below, the detection rule is ready:

Go through the rest of the wizard and assign as required to your AutoPilot AAD group and you are done here.

Now, the CMTrace tool will show up on your AutoPilot builds on a well-known path (C:\Windows), and can be invoked from a command line during parts of the AutoPilot build (Shift F10) just by typing in CMTrace.

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.

SCCM Configuration Baseline – Detect Microsoft Compatibility Appraiser DLL Version

Update: Microsoft have revised the article, the version numbers and logic have changed significantly as MS delved into the problem and got a better handle on it.

* Table taken from updated article here

Windows 10 Build 1507, 1511, 1607 and 1703 require 1799, and 1709 can use 1704 or 1752.

It looks like the problem is both the agent and build specific, with 1709 requiring a lower version of the client, and older builds requiring a newer version. Odd.

The only thing needing change with the below mechanism, is the PowerShell script. It just needs to get the current build version and check the client version against what it should be, will return and update at some point.

One of my customers is currently waiting for the results to come back, from a deployment of a Configuration Baseline which was pushed out to detect the Microsoft Compatibility Appraiser DLL problem.

The problem itself can cause chaos on the networks, due to excessive WSUS communications, and should be read up on here.

The problem seems to be due to specific versions of the Compatibility Appraiser, which version-wise can be described as:

  • No value = No problem (not installed)
  • Less than 1704 = Problem
  • Between 1704 and 1749 = No problem
  • Between 1750 and 1751 = Problem
  • Above 1751 = No Problem

And this can be defined using 3 conditions in a PowerShell script.

If you read the detail in the above link, you’d of recognised that there isn’t a fix for this issue, just an easing off of it. The appraiser will continue it would seem, to interfere with the WUA Scan Cache, causing some of it to vanish, and thus be downloaded from WSUS again, the best we can do is bring the appraiser up to a certain version to reduce the effect, or disable the Scheduled Task that runs the appraiser.


Let’s put a PowerShell script into a Configuration Baseline and trot it out the door, to detect if there is a build up of clients that need their Appraiser upgraded.

Create a new Configuration Item, call it what you want, but I used Appraiser DLL Check, then add a new Setting and call it DLL Check:

Make sure you have Setting type set to Script, and Data type set to String

For the Discovery script click Edit Script

Make sure Script language is set to Windows PowerShell

Add in the following, making sure its formatted correctly (paste and check it is okay in notepad!)

# Get DLL Appraiser compliance status

#Get registry value

$Compliant = $true

$val = (Get-ItemProperty -path ‘HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Appraiser’).LastAttemptedRunDataVersion

# Check if within ranges

if ($val -ne $null) # Not exist is compliant (not installed)
    if ($val -lt 1704)

    # Non-compliant

        $Compliant = $false


    if ($val -gt 1749 -And $val -lt 1752)
        $Compliant = $false

# Return compliance status ($false = non-compliant)

if ($Compliant -eq $false)

This script will nothing as a statement of compliance if the LastAttemptedRunDataVersion registry value does not exist, or if it is within bounds defined above, it will return False for non-compliance if not within the bounds.

Now switch to Compliance Rules and add a new Rule, call it DLL Check or whatever.