Finding and Removing Unused ConfigMgr Drivers

This is this the third and final part of my series on driver management in ConfigMgr.  Part 1 can be found here. Part 2 can be found here.

The script can be found here.

Driver Cleanup

Have you ever tried to clean up old or unused drivers in ConfigMgr and quickly became overwhelmed?  It can become pretty hard to determine what drivers are truly not in use since if you attempt to import drivers that already exist, which is pretty common, you can quickly run into drivers that are in several driver packages and driver categories which can make for a challenging puzzle to unravel.  Or at least it can be pretty time consuming.  Unfortunately it is not as easy as simply deleting driver packages for unused hardware models.

“In Use” Drivers

So, how do we determine what drivers are actually no in use?  Let me first define what “in use” means as far as drivers in ConfigMgr are concerned.  If any of these conditions are true a driver is consider “in use”:

  1. The driver is in a Driver Package that is referenced by a Apply Drivers step of a task sequence.
  2. The driver is in a Driver Category that is referenced by an Auto Apply Drivers step of the task sequence.
  3. The driver is imported into existing boot media.

There is a caveat if you are using an auto apply drivers step utilizing all available drivers as your primary method of deploying drivers during OSD this script probably isn’t of too much use to you and will generate a warning during execution that can be ignored if so desired.  There is really no way to logically determine which drivers are not in use if they are applied in this manner since you are technically using them all.  The script will still run and report back unused drivers, it just can’t be trusted.  If you are using an auto apply drivers step but scoping it to particular categories, this script will work just fine.

Sometimes it is just tempting to delete the driver source files and neglect the driver content ConfigMgr.  This could be done to free up space on a site server for example.  This is bad idea.  Don’t do this.  You have to delete the drivers from the console first before deleting the source.  Trust me.

The Script

Requirements –

  • Windows Management Framework (PowerShell) 5.0 – I use custom classes, because they are awesome.
  • The ConfigurationManager PowerShell module. This is available anywhere the ConfigMgr console is installed.

Before using this script it is highly recommended to clean and/or delete any legacy task sequences.  At the very least remove any apply drivers steps from existing task sequences you know are not being used.


  • This script can take a while to run depending on your environment.  (45+ minutes)
  • This heavily utilizes PowerShell verbose output and creates a very detailed transcript file.
  • An HTML report will be created when the HtmlReport parameter is provided. It defaults to UnusedDrivers.html.
  • This script makes use of the “WhatIf” functionality of PowerShell. Use this if you want to report on missing drivers without deleting them.

Usage –

Discover what drivers are not in use but do not delete them. (WhatIf)

Delete unused drivers ignore warnings for auto apply all drivers steps.


Delete unused drivers with warnings when auto apply all drivers steps are found.


ConfigMgr Client Push Installation Failing

Retrieved package version ’23’. But it is smaller than the expected version ’24’. Content is not ready yet.
GetDPLocations failed with error 0x87d00215
Failed to get DP locations as the expected version from MP ‘server.domain.local’. Error 0x87d00215

You can find this in the ccmsetup.log on a client device.


This happened to me after a 2012 r2 to Current Branch upgrade. (SQL, OS, everything)  At some point the client package got out of whack apparently.  To resolve refresh the content of the Configuration Manager Client  Package and this error goes away. Viola!

Removing ConfigMgr Drivers with missing source files

You can find the drivers with missing source files removal script here.  This is the second article in a series a driver articles. You can find part 1 here.

Driver management with ConfigMgr can be a bear at times.  Without some attention to detail towards organizing your driver source locations it is not uncommon for driver source files to be deleted before the driver is removed from ConfigMgr, by accident or otherwise.  This can end up being a real pain in the long run.  If source files are missing you can have problems with distributing, deploying drivers as well as maintaining boot images.


  • An HTML report will be created when the HtmlReport parameter is provided. It defaults to UnusedDrivers.html.
  • This script makes use of the “WhatIf” functionality of PowerShell. Use this if you want to report on missing drivers without deleting them.
  • This heavily utilizes PowerShell verbose output and creates a very detailed transcript file.
  • This requires PowerShell 5.0 or higher.


Discover what drivers are missing source files but do not delete them. (WhatIf)


Delete drivers with missing source files.



Delete drivers with missing source files and create a html report named “MyUnusedDrivers.html”.


Keep your driver repository clean!

Import boot image drivers from existing boot image

With the new “Current Branch” model of ConfigMgr and Windows 10 we can expect a faster release cycle of the ADK, which means new boot images pretty regularly!   Creating new boot media is really simple.  However, reimporting all of your required drivers into that boot image can be a real chore.  Here is a script that that identifies the drivers in a source boot image and imports them into a destination image.  This should reduce time to create usable boot media significantly.  Give it a spin and give me some feedback.

The script can be found here .

Usage –


“Mfc120u.dll is missing from your computer” when viewing Status Message Queries in ConfigMgr Console

When trying to view status message queries from the ConfigMgr console –


The program can’t start because mfg120u.dll is missing from your computer.  Try reinstalling the program to fix this problem.

You are missing the VCRuntime 2013 x86.  The installer can be normally be found at \\primarysiteserver\sms_xxx\client\i386\vcredist_x86.exe or from Microsoft


Maintaining Your Office 2016 Installation Source

Deploying an updated Office installation has always been an annoyance of mine.  It is ideal to be able to deploy a fully updated Office installation so you don’t have to run a software update scan and then wait for all the office patches to download and install.  Having to install less software updates can reduce your deployment or build and capture times significantly.

Side Note –  To avoid all of this legacy overhead, use Office 365 Click to Run edition.   It is easier to deploy and manage the click to run editions of Office because there is built in functionality to keep your installation source up to date without having to identify, download and test each individual update.

Fred has joined Now Micro and is passionate about PowerShell and how it can make life so much easier.  The solution laid out below can reduce your deployment time and complexity around deploying and managing Office.

The Updates Folder

To install Microsoft Office software updates as part of the Office suite deployment you can download the applicable updates and place them in the updates folder of the Office source installation.  These are in the form of MSP files.  This is a well-documented process that hasn’t changed for a while.


The biggest challenge with this has always been locating all the available updates for your particular Office installation.  Sifting through the windows update catalog is a real chore and I am lazy, so I looked to enlist the help of ConfigMgr and PowerShell.

In the site settings for your software update point be sure that you have selected the Office 2016 product.  Do this and then synchronize your software updates point if you haven’t already.


Download all Office 2016 Software Updates, that are not expired, not superseded and for the appropriate architecture (32 or 64 bit) to a new Software Updates Deployment Package. Filter your search results to just include the architecture you are looking for.  (64-bit or 32-bit)


Select all updates (ctrl-a), right click and select Download.


Create a new Deployment Package when prompted. Take note of the Package Source folder. It will be referenced later.


This will download all the source files to wherever you specified when you created the Software Updates Deployment Package.  A unique directory (sometimes more than one) is created for each software update in the Deployment Package.


Remove the problematic updates –

Remove the following updates from your Deployment Package before proceeding.  These updates for reasons unknown will fail to install during the deployment and will cause the installation to return a failure error code.  These can be removed directly from the Deployment Package using the ConfigMgr console. (Right click each update and select delete)
















Each folder created during the software update download will have a .cab file that contains the Office update MSP you are interested in.  If you start extracting these archives you will quickly notice that all the software updates for Excel are named the same. This behavior is the same for all products in the suite.  (Word, OneNote, etc.).  PowerShell to the rescue!

This script will extract the MSP files from each cab archive, save them with a unique name, copy them to the updates folder of the Office installation and then clean up .  To use this script modify the parameters of the Get-Office2016MSPsFromCab function to match your environment or specify them explicitly when running the function.


The script in its entirety can be found here.

I hope you find this useful!   Contact me at @FredBainbridge with specific questions.

Enable Isolated User Mode in Windows 10

You need to enable Isolated User Mode in Windows 10 if you want to, among other things, utilize the virtual TPM chip in generation 2 virtual machines.  If you try to start a gen 2 virtual machine with the TPM chip enabled but without Isolated User Mode enabled you get this error message –

First, own and activate your TPM chip and then run the following PowerShell commands –

Did you reboot after doing this and expect it to work but it didn’t?  Check out the event log and then activate your TPM chip!


Git and the PowerShell prompt

There is lots of information out there on using Posh-Git.  This is nothing new, its just a little helper for me since I have been recently been shuffling through workstations at an alarming rate.  If it is useful for you as well, stellar!

  1. Install GIT

  1. From an elevated powershell prompt –


  1. Modify your profile for PowerShell and PowerShell_ISE

Reference for PowerShell profiles

Posh-Git will install in C:\Program Files\WindowsPowerShell\Modules\posh-git\\.  This will obviously change as newer versions are released.  Verify the path with this command –

In this directory you will find profile.example.ps1

 Comment out line 4 and uncomment line 8.  (Unless this doesn’t work for you, then make the modifications that would work for you)


  1. Make any additional modification you want to make to your profile and then copy the contents of profile.example.ps1 to:

C:\Users\[username]\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 and



  1. Start a new PowerShell instance and then create a new GIT repository.  Check out your awesome prompt.


Nested PowerShell Modules

If you are curious about how to import a PowerShell module that has dependencies on other modules this can be done with the module manifest file (PSD1). You can do some pretty wild stuff with a PowerShell Module Manifest file. For starters here is a great outline how that file works with some decent examples.
Here is an example of how to have nested PowerShell modules. The nested module in this case being a C# compiled .dll. It is nothing fancy, just a custom class definition. More on PowerShell classes here.

First you use the NestedModules element of the psd1 file to reference the path of the nested module to be loaded. This requires a path relative to a location in the $env:PSModulePath. Aka, where you would normally look for modules. In this case the module would be expected to be found at [PSModulePath]\TCMABL\. This can be a comma separated list if you have multiple nested modules.

Then use the ModuleList element to list all modules packaged with this module. Note – your nested modules do not have to be packaged with your module. But if you want to ensure it is present it may be a good idea to package them together.

That is it. Now the nested module will be available as long your original module is loaded. But the nested module itself won’t be listed as loaded if you do a Get-Module. But rest assured, it’s there and ready for use.

For fun, let’s prove it –

First, clear all loaded modules –

Import just the nested module. (I am not using relative paths in this example, but you can)


Now I can instantiate my custom class if I so desire.
Side note – This class was used for some sabremetric baseball stats for an amateur baseball league I play in.  I’m so replacement level.

In order for the object type to no longer be available you have to restart the PowerShell instance. Close and open the ISE or whatever you are using for you PowerShell development. If you try to instantiate the custom object now, it won’t work unless you have the module package present in your $env:PSModulePath.

Now load your PowerShell module that has this .dll listed as a nested module and do a Get-Module. Notice only the PowerShell module I imported is now available.


Notice you don’t see the NestedModule listed but you can still instantiate the custom object!

Cool stuff.