System Center Configuration Manager OSD for Distributed Environments

My company is highly distributed. We have around 150 Config Manager boundaries assigned to 100+ different Distribution Points with network bandwidth ranging from 3Mb up to 1Gb. Yes, 3Mb, we’ve got some slower sites out there in the globe! Being the Primary OSD guy at my company, this creates a challenge. Let’s say I create a new OS Image the week of patch Tuesday, we test and target all distribution points that Friday. Considering that we have Patch content being distributed, plus now these large WIM files (not to mention anything else that may be distributing, site data, client data, etc…) most-often, we see the following patch Tuesday before we can add the new WIM into our task sequence. We have a CAS and elect to make all our changes then and there for the globe to use; this helps us achieve a consistent deployment process regardless of the geographical location of the site.

Obviously, our problem here is we may see 4-6 weeks before distributing new OS Image files; Considering we support a Windows 7 32/64-bit, Windows 8.1 32/64-bit, and now Windows 10 64-bit, this is a lot of data to push out! The slower cadence of our OS Images the more updates that need to run during the “Install Software Updates” steps. So, whats the solution? I can beg and beg until I retire to get our bandwidth updated but this can be VERY costly depending on the exact location around the world. We could only update our images quarterly, semi-annually, or annually? All this does is allow the updates to stack up during “Install Software Updates” which can cause issues, extend run-time, and in some case create a mess.

But…what if I had a way to make changes to our OSD process (New Image, New Driver Package, etc…) and (dynamically) as this content becomes available that content is used? I call this a “Dynamic Task Sequence” or DTS.

Theory of Operation


The Dynamic Task Sequence (DTS) System implements an additional layer on top of the traditional Operating System Deployment (OSD) Task Sequence. This added layer—Referred to as a Task Sequence Scenario—contains two OSD Task Sequences.

For each OSD Task Sequence Scenario there would be two Task Sequence: one with the latest and greatest updates/changes/modifications (hereby referred to as the “Fast”) and one referencing content that is known to be globally distributed (hereby referred to as the “Slow”). Rather than selecting a Task Sequence to run, a task sequence scenario would be selected (e.g.: Windows 32-bit, Windows 64-bit). This to be done during the Wizard or “Pre-Start” Command.

Upon selecting a scenario, the Fast task sequence would be evaluated to see if the references are available within the client’s ConfigMgr boundary (See my post on Content Location Requests). If all content is available to the client, the Fast Task Sequence would then be run. If any of the referenced content fails to validate, the Slow Task Sequence is run.

This allows updating the Fast task sequence as soon as changes are tested and validated to work. The beauty of this system, is that as content is distributed and arrives to ConfigMgr servers, locations will begin to use the Fast Task Sequence automatically.

Once Fast content is globally distributed, the Slow Task Sequence is updated with that content. The Fast Task Sequence is not used to “test” or “pilot” changes, but to make the latest changes available as soon as possible!

This allows locations to take advantage of changes as soon as the content reaches a client’s local servers rather than waiting for content to be distributed globally.

DTS versus Normal OSD

Normal Task Sequence OSD

In a normal Scenario, we would have one Task Sequence per Build (Example: 32-bit Windows 10 & 64-bit Windows 10). The task sequence consists of all the SCCM Packages that are referenced by the Task Sequence (Applications, Boot Media, OS Image, etc.…). In order for us to update a referenced Package in this Task Sequence, we would need that new package to be distributed to all servers. With highly distributed environments, this causes extended delays when we need to make changes to an OSD Task Sequence.

DTS Task Sequence OSD

Under the DTS system we add the scenario layer. A Scenario is a collection of Two Task Sequences. Rather than selecting a Task Sequence to run, you select the scenario. Similar to traditional OSD, the availability of each Task Sequence reference is performed; however, with DTS, we evaluate the Fast Task Sequence first. If criteria is met, that task sequence is used; if evaluation of the fast task sequence fails, we default to the “Slow”.

Under DTS we do not add a package to the Slow Task Sequence unless it is 100% distributed. This allows us to modify the Fast Task Sequence even before the content is distributed. Since the “Fast” task sequence is evaluated at run-time, as content becomes available to a location, those clients will begin running the “fast” task sequence automatically.

Effects of Missing Content

With Traditional OSD, if I update my Task Sequence with a package that is not completely distributed, those “pending” locations will be unable to run this Task Sequence.

With DTS, I update my Fast Task Sequence before content is completely distributed. At run-time (in WinPE), we validate the reference packages. If we have a failed content location request, we simply default to the “Slow”. No need to evaluate the Slow build as this will be done once we select a Task Sequence. In Theory, this prevents any sort of failed Task Sequence due to missing content (as long as we’re updating our Slow Task Sequence honestly 😉 ).

Maintenance Requirements

Now, this isn’t perfect! There are some additional maintenance items that we’ll need to perform.

  • Double Task Sequences
    • Since selection is based on Scenario, two task sequences will be required per “Scenario”
    • Changes now need to be made twice; once to the fast, then again to the slow when distribution is complete.
  • Additional SQL to Map Scenarios (if using SQL for this)
    • A basic SQL table is required to map a scenario to the respective fast and slow task sequences.
    • Typically, this will only need to be created once, unless a Scenario is added/removed, or a modified Task Sequence Package ID or Task Sequence Advertisement ID.
  • Additional Reporting
    • In order to maintain the “Slow” task sequence, we’ll need a report to give the distribution status of the “Fast” content. Once we see “Fast” content fully distributed, we can safely add this to the “Slow” Task Sequence.

Technical Breakdown


  • SCCM 2012 (or newer) Infrastructure
  • Scenario Mapping (Server running MS SQL [Recommended])
    • New Database or new Table in an existing Database; NOT YOUR SCCM DATABASE!
    • This will be used to handle mapping information from a Scenario to the Fast/Slow Task Sequences
    • Hosted SQL Server MUST have a linked server connection to the SCCM Server
    • This does not have to be on the SCCM Server itself.
  • Boundaries by AD Site (IP/Subnet could be used–I have not tested though)
  • Bootable Media with a Prestart Command

SCCM Infrastructure

For this to work, a SCCM infrastructure running version 2012 RTM or higher is required (Although you should be on the latest service pack of 2012/R2 if not the latest product!)

SCCM’s default configuration will work for this theory. The only specific requirement is that boundaries are defined by AD Site for Content Validation to work properly. You CAN manipulate a content location request using an IP address; but I have not tested this as we use AD Site configurations.

Each Scenario will require 2 Task Sequences: “Fast” and “Slow”

Scenario Mapping

With each “Scenario” you’ll have 2 Task Sequences: “Fast” and “Slow”. You’ll need something to tie a Scenario to each task sequence and each task sequences package ID and Advertisement ID. We chose to use SQL since this is where all our wizard content comes from. If you’re using MDT, you can use that same database (just add a new table). Alternatively, this information can be placed into a XML file and packaged with your pre-start command files. The only down-side to this is that anytime you have an update, you need new boot media (We try to limit our Boot Media Image updates only to hardware [driver] additions).

IMPORTANT: If you elect NOT to use SQL for storing your Scenarios and Scenario Details, you still need some method to query your ConfigMgr Database for Task Sequence References!

We’ll want to create a few tables, views, and stored procedures to make these actions easier for our OSD Wizard. I’ll have 2 tables: One showing the Scenario and Scenario ID (SQL id column), and another table referencing the Scenario table and then containing all the necessary information for our Task Sequence. Having these split up allows us to call unique Scenarios for our wizard. All the rest of the information is addressed and handled in the background hidden from the user.

SQL Table: TaskSequenceScenarios


This table will hold each Scenario. It contains an Identity column and a name column.


id groupName
0 Windows 7 (32-bit)
1 Windows 7 (64-bit)
2 Windows 10 64-bit


SQL Table: TaskSequenceScenarioDetail

This table will store the Task Sequences associated with a Scenario. It has an identity column, a column that links back to the id column of TaskSequenceScenarios, a Task Sequence Package ID, Task Sequence Advertisement ID, Description, Notation of Fast or Slow, Active, Date Added, and Date Removed.


id groupId taskSequencePkgId advertisementId description isFast active dateAdded dateRemoved
1  0  ABC00100  ABC20100  Windows 7 32-bit Fast TS  1  1  2016-03-16 06:54:34.160  NULL
2  0  ABC00101  ABC20101  Windows 7 32-bit Slow TS  0  1  2016-03-16 06:54:34.160  NULL
3  1  ABC00102  ABC20102  Windows 7 64-bit Fast TS  1  1  2016-03-16 06:54:34.160  NULL
4  1  ABC00103  ABC20103  Windows 7 64-bit Slow TS  0  1  2016-03-16 06:54:34.160  NULL
5  2  ABC00104  ABC20104  Windows 10 64-bit Fast TS  1  1  2016-03-16 06:54:34.160  NULL
6  2  ABC00105  ABC20105  Windows 10 64-bit Slow TS  0  1  2016-03-16 06:54:34.160  NULL


SQL Stored Procedure: SP_GetScenarioDetailsByGroup

You’ll want a stored procedure to ask the database for the details of a scenario. This Stored Procedure will obtain the Task Sequences (and their relevant OSD details) assigned to a Scenario. Ideally, your wizard would obtain the Scenario and ID from the TaskSequenceScenarios Table, list the “Name” to select, then use the corresponding ID against this procedure to get the necessary details.

	active = 1 and groupId = @TaskSequenceGroupId

SQL Stored Procedure: sp_GetTaskSequencePackageReferences

This is where the linked server back to your ConfigMgr server is required. This procedure takes the Task Sequence Package ID stored in your TaskSequenceScenarioDetails table and returns all of the referenced packages. We’ll need to get the PackageId and SourceVersion to do a proper content location request (See my post on Content Location Requests).

	(Select distinct ReferencePackageID
		from [ConfigManagerServer].[ConfigMgrDatabase].dbo.v_tasksequencereferencesInfo
		where PackageID = @TaskSequencePackageID
	inner join [ConfigManagerServer].[ConfigMgrDatabase].dbo.v_package P on TSPKG.ReferencePackageID = P.PackageID
order by P.PackageID


I’m going to assume that you’ll update your wizard/pre-start on your own to select the Task Sequence Scenarios for selection. Remember, if showing a selectable Scenario for a build, you’ll want to display the groupName column and preserve the id as the id will be needed to get the details.

At a high level summary, we’ll use our stored procedure (SP_GetScenarioDetailsByGroup) using the id from TaskSequenceScenarios. This will return (most importantly) our Task Sequence Package ID and Advertisement ID.

From here we’ll start with our “Fast” Task Sequence. We’ll need to perform a Content Location Request on each package (If you missed the first few links: See by blog post Configuration Manager: Content Location Requests).

You’ll need to point the Content Location Request to a management point server. You can simply use a hard-coded MP but that’s not very dynamic. You’ll be better off using the Task Sequence Variable “SMSTSLocationMPs” (this is a string of multiple MP’s separated by ‘*’). If you’re using Dynamic boot media, this may contain several servers, so how can you tell which is the correct one? We can do a simple http request to any of those MP’s with our ip address and subnet address to get the appropriate MP for where we’re at:

The function below will do just that! It will return a hashtable of SiteCode, and ManagementPoint from the http command used. If you want, this http command can be used inside any browser if you want to verify.

function Get-SMSMpInformationOSD()
        [string] $ClientIpAddress,
        [string] $ClientSubnetAddress
    $TsEnv = New-Object -Comobject Microsoft.SMS.TSEnvironment
    $ManagementPoints = $TsEnv.Value("SMSTSLocationMPs").Split('*')
    [xml]$locationResponse = $null

    foreach ($mp in $ManagementPoints)
        if (-not (Test-Connection -ComputerName $($mp.TrimStart('http://').TrimStart('https://')) -Count 1 -ErrorAction SilentlyContinue))
        { continue }
        $serverResponse = Invoke-WebRequest -Uri "$mp/sms_mp/.sms_aut?MPLocation&ir=$($ClientIpAddress)&ip=$($ClientSubnetAddress)" -UseBasicParsing
        [xml]$locationResponse = $serverResponse.Content

    if ($locationResponse -eq $null)
        throw "Unable to contact any ($($ManagementPoints.Count)) Management Point Server(s)"

    return @{"SiteCode"=$($locationResponse.MPLocation.Location[0].SiteCode);
            "ManagementPoint"=$($locationResponse.MPLocation.Location[0].MP) }


If you need some assistance getting the Subnet Address, head over to TechNet and pick this one up.

Now that we have our local Management Point and it’s site code, we can begin to do the Content Location Request (You guessed it: See by blog post Configuration Manager: Content Location Requests). Analyze the xml returned and if the request shows at least 1 “Local” location, we can continue. As soon as a content location request fails, you can break out of the loop.

Whether or not the Fast or Slow has all of the references we need a way to set what Task Sequence will be run. If we don’t, we could have a list of Task Sequence to select, and may not know which one to run (And if we have multiple scenarios, each with 2 task sequences, this may be a long list!). The answer comes from the “advertisementId” column in the TaskSeqeunceScenarioDetails SQL Table. Set the Task Sequence Variable “SMSTSPreferredAdvertID” with the Advertisement ID from your SQL Table. If the task sequence finds that advertisement targeted, no more “Select a Task Sequence”; instead you just have a message saying “‘x’ Task Sequence is about to be run”.

Simple right? It’s a bit to grasp and certainly isn’t something that Microsoft will support. If you’re interested in implementing this, as with anything else, test it in a lab over and over. Just when you think it’s working, test it again!



Windows 10 Upgrade: Using USMT Hardlink

For those of us who have 32-bit Versions of Windows (whatever) floating around, you may have noticed that a lot of Hardware OEM’s are no longer providing 32-bit drivers for Windows 10. This creates an issue if/when you want to get those devices up to Windows 10. The In-Place Upgrade options built into the Windows 10 setup is amazing! However, it does not support 32-bit to 64-bit upgrade. Your best bet to getting this upgraded is to use whats called a USMT Hardlink and upgrade the OS.

What is USMT Hardlink?

USMT (User State Migration Tool) is a nice utility from Microsoft that is used to migrate a user profile from one operating system to the next. A USMT Hardlink deployment refers to a Windows OS Deployment (to the same hardware) where we’ll create a local offline copy of the user profile, apply the new OS (without cleaning the disk) and then injecting the user profile back to that machine. In the situation of say Windows XP to Windows 7, USMT Hardlink was our only option (As there was no In-Place Upgrade). The same goes for a 32-bit verions of Windows-whatever (7,8,8.1) to Windows 10 64-bit.

One thing to mention: Microsoft requires that for Windows 10 deployments, you have the appropriate Service Pack Installed. Now it is possible to do this without the Service Pack using a few small steps. I’ll include those steps with the process, look for “Without Service Pack“. If you do not have the Service Pack installed, you will need a system that has the Windows 10 ADK installed. We’ll need to pull some files and make some packages using that media.

Create the Task Sequence

  1. Once created, we’ll be deleting the whole thing, I’m running through this with you in case you need a Boot Image, MDT Package, USMT Package, or custom package created as this wizard will help you create those. If you already have these packages, feel free to create a custom Task Sequence and skip ahead.
  2. Make sure you have MDT 2013 installed with the ConfigMgr Integration setup, as well as the Windows ADK!
    Open the SCCM Console, Navigate to the Software Library Node, Expand Operating Systems.
  3. Right click “Task Sequence” and select “Create MDT Task Sequence”
  4. Select “Client Replace Task Sequence” and click Next.
  5. Name your task sequence appropriately, “Windows 10 64-bit (Hardlink)” works for me!
  6. Boot Image: Specify an existing or create a new.

    1. Without Service Pack: You’ll need a WinPE Image from the Windows 10 ADK which cannot be done 100% without the Service Pack. Specify whatever boot image you have for now. We’ll fix this later!
  7. MDT Package: Specify an existing package or create a new.
  8. USMT Package: Specify an existing package or create a new one.
    Without Service Pack: On the machine with the Windows 10 ADK Installed, copy the following folder to the network and use this source to create your USMT Package: “C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\User State Migration Tool
  9. Settings Package: Specify and existing or create a new. I use the vanilla Custom Settings Package for this; I’ll assume you are too.
  10. Review the Summary, and complete the wizard.


Boot Image:

If you’re running 2012 R2 SP1 (or 2012 SP2), then you should have the Windows 10 ADK installed on your server so new Boot Media should be a breeze. If, however, you do NOT have the Service Pack installed, a Win10 WinPE Boot media image CAN be imported and used, you just can’t modify it:

Boot Media with SCCM Service Pack:


Boot Media without SCCM Service Pack. Notice we’re missing some key tabs:


The solution here, is to create the Boot Media, then import the customized WIM file. Rather than provide instructions, I’ll direct you over to the best of the best: Johan Arwidmark. Follow his tutorial to create your custom WinPE.wim, then import directly into SCCM.

MDT Package:

Right now there isn’t a MDT version released with Windows 10 Support, However, I’ve been successful using the Toolkit Package from MDT 2013 as well as the Preview MDT that has been released.

USMT Package:

For your USMT Package, you’ll need to use what comes with the Windows 10 ADK. Install the Windows 10 ADK on any system then copy the following folder to the network and use this as the package source to create your USMT Package: “C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\User State Migration Tool“. Your package source must match the folders structure! You package source will have 3 folders: amd64, arm64, x86. If you have custom xml files to use with USMT, place them in the appropriate folder for the architecture of the OS.

Operating System Image

If you don’t already have SCCM 2012 R2 SP1 (2012 SP2) to create a proper Build and Capture, you can simply import the install.wim into SCCM under “Operating System Images”. Point directly to the install.wim inside the sources folder.

Reference the Boot Media

If a boot media is not referenced, a Restart Computer step cannot select the assigned Boot Media. It’s good to have this setup ahead of time, so all steps can be properly configured.

  1. Right-Click your Task Sequence and select Properties.
  2. Verify “Use a boot image” is checked.
  3. Click Browse and select the Windows 10 WinPE Image you have.
    1. If you want, you can add options to set only on specific Operating Systems. This will help prevent the wrong Client Operating System from running the deployment.
  4. Click OK.

Customize the Task Sequence

  1. Edit the Task Sequence.
  2. Now, If you ran through the wizard creating the Task Sequence, Remove all steps! Yes, All of them!
  3. Create a Folder called “Initialization”
    1. Within this group we’ll create 3 built in steps
      1. MDT> Use Toolkit Package
        1. Specify the packages you created for the Toolkit Package
      2. MDT> Gather
        1. Specify the packages your Custom Settings Package for Gather if you desire. I use “Gather only local data…”.
      3. General> Check Readiness
        1. Set “Ensure minimum memory (MB)” 2048 (you may adjust higher if you see fit)
        2. “Ensure minimum processor speed (MHz)” I left at the default (800)
        3. Verify “Ensure minimum free disk space (MB)” is at least 6000 (6GB).
        4. Verify “Ensure current OS to be refreshed is” is set to “Client”.
  4. Below those steps, add a folder called “Capture User State and Settings”. Within here we’ll have 6 steps in this order:
    1. General> Run Command Line
      1. Name: Capture Groups
      2. Command line: cscript.exe “%deployroot%\Scripts\ZTIGroups.wsf” /capture
    2. Settings> Capture Network Settings
      1. Check both options “Migrate domain…” and “Migrate network…”
    3. Settings> Capture Windows Settings
      1. Check all options “Migrate computer name”, “Migrate Registered user and organization names” and “Migrate time zone”
    4. General> Set Task Sequence Variable
      1. Name: “Set User State Store Path”
      2. Task Sequence Variable: OSDStateStorePath
      3. Value: %SystemDrive%\UserState
    5. General> Set Task Sequence Variable
      1. Name: Set USMT Additional Capture Options
      2. Task Sequence Variable: OSDMigrateAdditionalCaptureOptions
      3. The Value can be any mix of USMT capture arguments. Please note with the Windows 10 USMT Package, you do not need to specify the /hardlink parameter. I use the following:
        1. Value: /uel:90 /ui:DOMAIN\*
        2. This migrates all domain profiles that have been used in the last 90 days.
        3. Make sure to replace “DOMAIN” with your domain!
    6. User State> Capture User State
      1. Specify your Windows 10 USMT Package
      2. If you have custom capture files, be sure to specify those using the “Customize how user profiles are captured”
      3. In my example, I left “Enable verbose logging” and “Skip…EFS” unchecked
      4. Select “Copy by using file system access”
        1. “Continue if some files cannot be captures” is Checked
        2. “Capture locally by using links instead of by copying files” is Checked
  5. Create a new group called “Install Operating System”. We’ll have 8 steps in this order:
    1. General> Restart Computer
      1. Name: “Restart in Windows PE”
      2. Select “The boot image assigned to this task sequence”
      3. User notification is recommended in this case, so feel free to specify a friendly message for the user.
    2. MDT> Use Toolkit Package:
      1. Specify your MDT Package
    3. MDT> Gather
      1. Specify your Custom Settings package if you desire. I use “Gather only local data…”.
    4. Images> Apply Operating System
      1. Specify your Windows 10 Image
      2. If you have an answer file, specify that. I don’t use one here.
      3. Verify the Destination is set to “Next available formatted partition”
    5. Settings> Apply Windows Settings
      1. Specify your org information, local admin, and time zone settings as a good fallback if the captured settings cannot be used.
    6. Settings> Apply Network Settings
      1. If you’ll be upgrading a domain computer, make sure to specify the Domain and Account. Since we’ll be using the captured settings, we don’t need to specify a Domain OU.
    7. MDT> Gather
      1. Specify your Custom Settings package if you desire. I use “Gather only local data…”.
    8. General> Run Command Line
      1. Name: Configure
      2. Command line: cscript.exe “%deployroot%\Scripts\ZTIConfigure.wsf”
  6. Create a folder called “Apply Drivers”
    1. You can either use the Auto Apply or specify a Driver package. If you’re using driver packages make sure to filter any hardware specific information on each step.
  7. Create a folder called “Setup Operating System”. We’ll have 4 steps in this order:
    1. Images> Setup Windows and Configuration Manager.
      1. Specify your Package for the Configuration Manager Client
      2. Without Service Pack: add the following in the “Installation Properties”: /skipprereq:windowsupdateagent30-x64.exe
    2. General> Restart Computer
      1. “The currently installed default operating system”
      2. At this point its not necessary to provide notification.
    3. MDT> Use Toolkit Package
      1. Specify your MDT Package
    4. MDT> Gather
      1. Specify your Custom Settings package if you desire. I use “Gather only local data…”.
  8. Create a folder called “Software Installation”
    1. Here is where you’d put a list of software to install within your image. For us, this is where we place our standard Corporate Applications.
  9. Create a folder called “Install Software Updates”
    1. Typically we’ll have 3 repeated steps of “Install Software Updates”. If you are only deploying the OS, one should be enough, however, if you’re deploying software like “Office”, it may be wise to have 2 or 3 just to make sure all gets applied. At this time I only have one cycle:
      1. General> Install Software Updates
        1. All Software Updates
      2. General> Restart Computer
        1. “The Current Default Operating System”
        2. Notification is not necessary.
  10. Create a folder called “Restore User Files and Settings”. We’ll have the following 5 steps:
    1. MDT> User Toolkit Package
      1. Specify your MDT Package
    2. General> Run Command Line
      1. Name: Restore Groups
      2. Command line: cscript.exe “%deployroot%\Scripts\ZTIGroups.wsf” /restore
    3. General> Set Task Sequence Variable
      1. Name: Set USMT Additional Restore Options
      2. Task Sequence Variable: OSDMigrateAdditionalRestoreOptions
      3. Value: /uel:90 /ui:DOMAIN\*
    4. User State> Restore User Files and Settings
      1. Specify your USMT Package
      2. If you used custom xml files to capture user profiles, you’ll need to specify them again here for the restore.
      3. If you desire to restore local profiles, check the box
      4. Check “Continue if some files cannot be restored”.
    5. General> Restart Computer
      1. “The currently installed default operating system”
  11. And that’s it!


  1. Distribute your package references:
    1. Right Click the Task Sequence and select “Distribute Content”.
    2. Run through the wizard selecting any Distribution Points or Distribution Point Groups.
  2. If you don’t already, make sure you have a Collection setup to deploy to!
  3. Right Click the Task Sequence and select “Deploy”,
    1. Select your Collection and complete the Wizard.
  4. Update Machine Policy on the client.
  5. Watch Software Center
  6. Click Install and wait.
  7. Once all is done, We’re at Windows 10 64-bit!


Inject Drivers to Windows 10 Install Media

So Windows 10 is here with its second build (9860) in its “Technical Preview”. Since I am an OSD guy, I like to make sure when a system is built all the drivers are there (even for my test machines and ad-hoc builds to “see if it works”). Usually this just entails adding some drivers and–for the most part–plug and play is nice enough to install everything for me. If you’re without MDT and/or SCCM or just like to have a USB installer ready for anything, you don’t have the luxury of a driver package and just want all the drivers to automatically be there when Windows installs.

This process is very common and really, this applies to Windows Vista (and up) but as I went to inject drivers to Windows 10 media from my Windows 8.1 machine I met an old-friend-of-an-error and figured this was worth sharing.

Get the Drivers

First thing’s first. Get the Drivers! For Windows 10, Microsoft has done a great job of letting Windows 7/8.1 drivers install (or attempt to) and maintain a large percentage of support. So, download all the drivers and put them into one directory. Make sure that any downloaded installers are extracted first to where you can see the inf, cat, and sys files. I know Dell and HP both have self extracting executable for most drivers they offer out.

If you’re like me, you’ll have a huge hierarchy of Manufacturer> Model showcasing all the different models that you want to test on and support.



Create Your Media

Connect a USB Drive (USB 3.0 is better :)). We’ll need to format the disk…This will remove all of the files so make sure to backup anything.

  1. Open an Administrative Command Prompt
  2. DiskPart <enter>
  3. List Disk <enter>
  4. Locate which disk is the usb drive. Easiest way is to tell by size.
  5. select disk # <enter>  (# is the disk number from previous step)
  6. clean <enter>
  7. create partition primary <enter>
  8. select partition 1 <enter>
  9. format fs=fat32 quick <enter>
  10. active <enter>
  11. assign <enter>
  12. exit <enter>

Now you have a clean and fresh USB drive to use.

Extract the Install Files

With Windows 8+ you can just right-click and select “Mount” on the iso. Copy all of the files to the USB drive.

With Windows 7, you’ll need a program like 7-zip. Open the ISO, and extract all files to the USB drive.

Mount the WIM

There are two WIM’s in your Windows Installer that we’re concerned about: <InstallRoot>\sources\boot.wim and <InstallRoot>\sources\install.wim.

  • The Boot.wim is what gets loaded when you boot to your install media. This is a WinPE image used to apply an OS–MDT/SCCM people will be very familiar with the boot media concept.
  • The install.wim file is the actual sysprepped OS Installation that will get applied to your hard drive. If you mounted this, it will look just like your C drive: Program Files, Windows, Users, etc…

So really we now dive to 2 scenarios:

  1. When you boot to your media, your hard drive (or other device) is not recognized.
  2. When Windows is installed, drivers are missing

Scenario 1 relates to your boot media, scenario 2 relates to the install.wim. A rule of thumb is that your boot.wim only needs essential drivers; eg: storage and network. In this scenario, we’re only concerned about storage, since we’re using USB as our source media. Really though, both processes are the same.

  1. Open an Administrative Command prompt.
  2. Create a directory to mount the WIM file (mkdir c:\mount)
  3. Mount the wim:
dism /mount-wim /wimfile:%PathToWimFile% /Index:1 /mountdir:%ImageMountDir%

Add in the Drivers:

To add the drivers we’ll need to point the command to the folder of drivers we created above.

REMEMBER: only add storage and network to boot.wim. Anything more is just silly.

If you have you install.wim mounted you can point to the top folder that contains all the drivers for your model. Example: c:\drivers\hp\EliteBook800SeriesG1

Add the drivers:

dism /image:%ImageMountDirFromAbove% /add-driver /driver:%PathToDriversFolder% /recurse /forceunsigned

The recurse option will check all sub folders. the forceunsigned will allow unsigned drivers to be added.

On Windows 8.1 while mounting my Windows 10 install.wim i was greeted with an error:

Deployment Image Servicing and Management tool
Version: 6.3.9600.17031
Error: 50

To service this Windows image requires the latest version of the DISM. See to find the latest version of DISM, and to learn how to install the latest version of DISM from the ADK on your computer.

The DISM log file can be found at C:\Windows\Logs\DISM\dism.log

We could look at the dism log if we wanted but to me this error is rather self-explanatory. Essentially this is saying that the OS i have mounted is newer than the dism tool i’m using. Dism version: 6.3.9600.17031…Windows 8.1 OS Version is 6.3.9600 (see what they did there?). Think of it this way: Each version supports the corresponding Windows release plus older (Backwards compatible). It cannot work with a newer version since older version doesn’t know what newer version is.

The fix for this is to use the DISM command included in the Windows setup disk. Rerun the dism command above but this time, we’ll need to use the full path to the Windows 10 media:

%PathToWindowsInstallMedia%\Sources\dism.exe  /image:%ImageMountDirFromAbove% /add-driver /driver:%PathToDriversFolder% /recurse /forceunsigned

And voila…now we have drivers added.

Save the Changes

Last thing is to commit the changes we made:

%PathToWindowsInstallMedia%\Sources\dism.exe  /unmount-wim /mountdir:%ImageMountedDir% /commit

Again, this process will really apply to any version of Windows where you’d like to inject drivers within your media!



TPM Not Found After OSD

Today I experienced something frustrating. After applying OSD on some new hardware I attempted to enable BitLocker (TPM+PIN Configuration). To my surprise I received an error that a valid TPM could not be found. Here is my experience and methodology for troubleshooting a missing TPM.

(1) Check WMI
Using Powershell:

Get-WmiObject Win32_TPM -Namespace root/cimv2/security/MicrosoftTPM | Select IsActivated_InitialValue, IsEnabled_InitialValue, IsOwned_InitialValue | Format-List

Usually you’d see something like this:

IsActivated_InitialValue : True
IsEnabled_InitialValue   : True
IsOwned_InitialValue     : True

(2) Check TPM MMC Console
If and when WMI is blank I move on to the TPM MMC console snap-in (tpm.msc).

(3) Check BIOS
At this point I’ve determined the TPM isn’t visible to the Operating System; It happens! On most BIOS you’ll have settings whether or not the Operating System can see and/or manage the TPM Device. Boot into the BIOS, look for a security section and check the TPM Status. In my instance this looked good! TPM was listed as Enabled and Activated. I rebooted back to the OS, repeated steps 1 and 2…both still with the same result.

(4) Vendor Software
When it comes to using vendor-provided installers/software/executables to install drivers, I typically have one rule: I DON’T! In my experience (Dell, Lenovo, HP, Samsung, MS Surface) Plug-n-Play will identify and capture 99% of the hardware without the necessity to install the vendor’s software. In this instance this was an Infineon TPM device so I grabbed the driver CD, extracted and ran. Unless absolutely necessary, I’ll usually use the software to install only the driver where possible. A lot of driver installations will also provide an application that tromps over the built in Windows functions with their own; Bloatware, Crapware…call it what you want, I find it extremely unnecessary. The most infuriating being the old “HP Wireless Assistant” which was a clunky “remix” of Windows’ normal Wireless Connection Menu and tray icon–I found this to be slow, clunky, and down right unnecessary!

Back to the TPM…I launched the “Infineon TPM Professional Package”. I select custom install hoping to see “Driver”. Instead I see a bunch of extra stuff I don’t need and when I went to tell the installer to “not install” a component, I saw this wasn’t an option…It would appear that in order to get an Infineon TPM device seen to the OS, I have to use their crappy application to “manage and control” it. Not gonna happen!

As I contemplated what to do next I eventually did what I probably should have done at step (1)…

Check Device Manager
Usually, device manger would show a TPM device under the “security” category as seen:




Unfortunately, not found! I then started digging in Device Manager and eventually stumbled across “Infineon Trusted Platform Module” under “System Devices”. That explains why the TPM MMC couldn’t find it!


Right-Click -> Uninstall (making sure to check “Delete the driver software for this device”.


Richt-Click –> “Scan for Hardware Changes”

Just like magic, the TPM was detected and placed in the “Security Devices” category. TPM.msc detected it. BitLocker was enabled and there was much rejoicing. I then removed the “tpm driver” from the Driver Package, updated distribution points and all was well!


My hope is that this will save some of you from additional headaches if this comes up in your OSD world.