Category Archives: OSD

Install Windows hotfixes (.MSU) during OS deployment using MDT/SCCM2012.

Recently, our local desktop support team came to me with an issue they had discovered in the image that is deployed via SCCM.  The issue was that when they attempted to “Turn Windows features on or off”, the dialog box shown was blank.  They had assumed that deploying the image via SCCM was somehow disabling this dialog box.


While troubleshooting this issue, I had discovered that Microsoft was aware of this issue and they had created KB931712 in order to fix this.  However, this did not work for me.  Another MSDN post recommended to run the System Update Readiness Tool (SURT) in order to fix any Windows Update corruption.  Again, this did not work for me either.

I started to dig deeper into this issue and found that SURT creates a log file of anything it finds.  The log file is located at C:\Windows\Logs\CBS\CheckSUR.log.  For help with reading the log file, I found this very good tutorial.

Here is the content of the log file:

Checking System Update Readiness.
Binary Version 6.1.7601.21645
Package Version 19.0
2013-12-18 15:57

Checking Windows Servicing Packages

Checking Package Manifests and Catalogs
(w) CBS Catalog Expired 0x800B0101 servicing\Packages\

Checking Package Watchlist

Checking Component Watchlist

Checking Packages

Checking Component Store

Seconds executed: 1424
 No errors detected
 CSI Catalog Expired Total count: 0
 CBS Catalog Expired Total count: 1

Even though no errors were detected, I found that update KB2722913 had an expired catalog file.  I then opened the properties to the referenced catalog file in C:\Windows\servicing\Packages and sure enough, under the “Digital Signatures” tab, the certificate that was used to sign the catalog file had expired as of 06/27/2013.  This expired certificate was preventing the Windows features from being displayed in the dialog box.


To workaround this issue, we could have just uninstalled the affected Windows update(s), but this approach does not address the root cause.  Instead, Microsoft has released KB2749655 in order to resolve this issue.  There are several ways we could use to deploy the hotfix via SCCM, for example, we could create a package with the MSU and create a program to install it using the following command:

wusa.exe Windows6.1-KB2749655-x64.msu /quiet /norestart

Similarly, you can follow this post which uses a VBScript to install multiple hotfixes to a collection.  However, I’m only interested in deploying the hotfix with an OS deployment.  In order to accomplish this we will leverage the power of an MDT/ SCCM 2012 integrated task sequence in order to apply the Windows hotfix (.msu file) to an image right after deployment.  The Powershell script and idea came from the following post at “The Knack” but I found I had to add a “Restart Computer” action to the task sequence in order to allow the hotfix to fully install.

Powershell Script (ApplyHotfixes.ps1):

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$folder = $scriptPath += "\hotfix"
$total = gci $folder *.msu | measure | Select-Object -expand Count
$i = 0
gci $folder *.msu | foreach {
        WUSA ""$_.FullName /quiet /norestart""
        while(get-process wusa -ErrorAction SilentlyContinue)
        {Write-Progress -activity "Applying Windows Hotfixes" -status "Installing $_ .. $i of $total" -percentComplete (($i / $total) * 100)}
        Write-Progress -activity "Applying Windows Hotfixes" -status "Installed $_ .. $i of $total" -percentComplete (($i / $total) * 100)
  1. Make a folder in your SCCM software repository and put the Powershell script along with a subfolder named “Hotfix”.  Inside the subfolder, place the .MSU files you would like to install.12-18-2013 10-10-39 PM
  2. Create a package out of the previously created folder and do not create a program.  Don’t forget to distribute the package to your distribution points.12-18-2013 10-14-12 PM
  3. Add a folder at the end of your OSD task sequence to group the MDT actions together.  The add the below MDT actions.12-18-2013 10-17-48 PM
  4. In the “Use Toolkit Package” action, select your MDT 2012 package.12-18-2013 10-19-07 PM
  5. In the “Gather” action, select your MDT CustomSettings.ini package.12-18-2013 10-19-21 PM
  6. In the “Run PowerShell Script” action, select the package we created with the script and if you named the script “ApplyHotfixes.ps1”, type its name in the space provided.12-18-2013 10-19-34 PM
  7. Last but not least, add a standard “Restart Computer” action to allow the MSU installation to finish.  Make sure the “Default Operating System” is selected or else it will boot back into the task sequence.12-18-2013 10-19-44 PM

This is all that is needed to get this working folks!  The powershell script will continue to recurse the directory until all .MSU files are installed and upon booting into Windows, you should be able to view the install updates under “Programs and Features” in Control Panel.

In the context of my particular issue, we were able to deploy the OS image, install KB2749655 and upon booting into Windows, the “Turn Windows features on or off” dialog box looked like this:

12-18-2013 10-32-22 PM

Support all Dell desktop and laptop drivers in your OS deployment!

Dell maintains an active online community of professionals on their TechCenter wiki.  To make SCCM driver management easier, Dell Support has released several CAB files with all supported drivers for a particular Dell model.

However, the community on the TechCenter wiki took this approach further – they released a driver pack zip file with all related drivers for a particular chassis type!  In other words, we can now choose to download one driver pack for all laptops or another driver pack for all desktops!

Head on to and scroll all the way to bottom of the page to where it reads “Combo CAB Availability” pick your device and download away!

When integrating this driver pack for Dell desktop models for example, you should use an “Any If” statement with the following WMI queries to scope out the driver pack for both Dell desktop families: Optiplex and Precision workstations.

12-9-2013 3-14-57 PM

select * from Win32_ComputerSystem where Model like 'Optiplex %'
select * from Win32_ComputerSystem where Model like 'Precision [^M]%'

Capturing task sequence log files during OSD deployment.

This idea grew out of the need to troubleshoot certain task sequence errors.  Usually when your task sequence throws an error, the code will be displayed for an X amount of time after which the machine reboots.  Retrieving the SMSTS.LOG file is somewhat cumbersome, as the exact location of the file varies depending on which phase of the OSD the machine is in:

WinPE, Before HD Format x:\windows\temp\smstslog\smsts.log
WinPE, After HD Format x:\smstslog\smsts.log
Windows, No SCCM Client Installed c:\_SMSTaskSequence\Logs\Smstslog\smsts.log
Windows x86, SCCM Client Installed c:\windows\system32\ccm\logs\Smstslog\smsts.log
Windows x64, SCCM Client Installed c:\windows\sysWOW64\ccm\logs\Smstslog\smsts.log
Task Sequence Completed x86 c:\windows\system32\ccm\logs\smsts.log
Task Sequence Completed x64 c:\windows\sysWOW64\ccm\logs\smsts.log

An easier way to gather these logs is to take advantage of a Task Sequence Variable within the OSD deployment.  Whenever the task sequence finishes either successfully or not, the TS variable “_SMSTSLastActionSucceeded” returns a true or false value.  We can then leverage this variable to create a step in the task sequence to run only if the return value is false and then further run some steps to map a network drive and copy the logs over.  I was lucky to find an old post by Steve Rachui, a Microsoft Premier Field Engineer which helped saved me time brainstorming a solution.  However, my implementation makes use of the %OSDComputerName% variable and displays a custom error message in order to prevent WinPE from rebooting after clearing the countdown.

Below are the steps I took:

  1. Created a network share and allowed “Everyone” full access permission.  You can restrict this share to a specified AD account if you wish but you will then need to specify the account in the steps below.  I named my network share “TSLogCapture”.
  2. In the root of your task sequence, create a new group named “Task Sequence” and move all the steps as a subfolder to this new group.  In the Options tab, make sure the “Continue on error” box is checked.  The idea is to have all the steps grouped and if there is an error, pass control to the next group which will copy the logs to a share.10-31-2013 3-25-10 PM
  3. Also in the root of your task sequence, create another group named “Log Capture”.  In the Options tab add a condition to run when the task sequence variable “_SMSTSLastActionSucceeded” equals “False”.11-1-2013 8-25-52 PM
  4. We will need to add the above displayed steps to the “Log Capture” folder.  To add the first step, go to Add, General, Connect to Network Folder.11-1-2013 8-31-56 PM 

    In the Properties tab, you will need to specify a Path, Drive Letter and Account to connect and map the network share.  If you restricted the network share to a specific AD account, input that account here.  Also, please note I chose the “Z:” drive letter, therefore, all my command line entries reflect this drive letter.  If you choose a different drive letter, please update any subsequent command lines with this new drive letter.11-1-2013 8-35-04 PM

  5. Now we will need to add “Run Command Line” steps to the “Log Capture” folder.  To add this step, go to Add, General, Run Command Line.  This step will remove any pre-existing folders for that machine name you are currently using from the network share.  Its purpose is to prevent duplicate log files.11-1-2013 8-43-32 PM 

    In the Properties tab, type the following:11-1-2013 8-45-53 PM

    cmd.exe /c rd /s /q z:\%OSDComputerName%
  6. Add another “Run Command Line” step.  This step will create a folder named after the computer name in the TS variable %OSDComputerName% (a friendly name of your choosing).  You can also use %_SMSTSMachineName% which will name the folder after the random “MiniNT-12345” name if the error occurs in WinPE or after the actual AD computer name if the error happens in Windows.11-1-2013 9-00-26 PM
    cmd.exe /c md z:\%OSDComputerName%
  7. Add another “Run Command Line” step.  This step will copy the log files from the path contained within the %_SMSTSLogPath% variable to machine named folder in the network share.11-1-2013 9-03-58 PM
    cmd.exe /c copy %_SMSTSLogPath%\*.* z:\%OSDComputerName%


This last step is entirely optional.  I use it to display a custom error message using VBScript in order to prevent the error countdown from starting and rebooting the machine.  To add this step, you will need to create a Package out of one file, ErrorPrompt.vbs.  To create this file, open Notepad.exe and copy/ paste the following and update the path to your network share:

WScript.Echo "There was an error in the task sequence." & VbCrLf & VbCrLf & "Please review the log files stored at:  [Your Network Share Path Here]"

Next, save the VBScript file in a folder in your SCCM package repository and create a package using the SCCM Administration Console:

11-1-2013 9-24-09 PM

11-1-2013 9-27-54 PM

11-1-2013 9-34-38 PM

Click on “Next” all the way until the package is created.  Once complete, you will need to distribute it to your distribution points or groups.

11-1-2013 9-38-28 PM

11-1-2013 9-39-38 PM

10-31-2013 4-11-36 PM

10-31-2013 4-12-13 PM

Once again, click “Next” until you finish distributing the package.  You will need to watch the “Content Status” pane in the package information section to verify that the package was distributed successfully.

10-31-2013 4-12-56 PM 10-31-2013 4-13-49 PM

Now that you have created your package and have it distributed to your distribution points.  You may proceed creating that last “Run Command Line” step in your task sequence.  In the Properties tab, insert the following command line and don’t forget to specify the package we created:

11-1-2013 9-08-06 PM

cmd.exe /c wscript.exe errorprompt.vbs

Phew!  We are finally done!  Give yourself a good pat on the back because from now on, whenever your task sequence encounters an error, you will see the following:

11-1-2013 10-01-52 PM

Handling duplicate MAC addresses in SCCM.

I had a very strange issue today as I pulled a loaner laptop to test an application I was working on – turns out the machine would not PXE boot because its MAC address was already assigned to another machine in SCCM’s database.  However, the UUID was different.  In order to determine the issue, I built out the following two queries:

Find computer by MAC address:
select distinct *  from  SMS_R_System where SMS_R_System.MACAddresses = "aa:bb:cc:11:22:33"

Find computer by UUID:
select *  from  SMS_R_System where SMS_R_System.SMBIOSGUID = "AAAAAAAA-BBBB-CCCC-1234-567890ABCDEF"

The first query returned a machine in the database with a different name than the one I was working on but had the same MAC address (actually two MACs) and with a different UUID.  The second query did not return anything when I inputted the UUID it displays when pausing at the PXE boot screen, but, after examining the contents of SMSPXE.LOG, I was able to see the last UUID that attempted to connect which was slightly different (some numbers seemed transposed) and when I used this it returned the same exact computer as in the first query (phew!).

I then started to investigate if the machine displayed in SCCM existed in active directory and sure enough, it was part of the domain.  Furthermore, I was able to ping this machine on the network!  Now I have certainly read before that it is possible to have a duplicate MAC address because of vendor error, but I didn’t think I am that unlucky.  After asking the helpdesk about the computer being returned in SCCM, it turns out the user currently assigned to it was given a loaner laptop but its hard drive was replaced by the original hard drive which has the SCCM client installed on it.  When doing inventory, it apparently picked up this new MAC address and updated its record in the database with the new value.  When the user’s original hardware came back from repair, the hard drive was swapped back to the original laptop and because the previous MAC address was already in the database, the client didn’t update and did not drop the loaner’s MAC address.

Case solved!  I removed the SCCM client from the original machine, deleted the computer in SCCM and reinstalled the client on the machine.  Upon reinstalling, it recreated the computer record in SCCM with the correct MAC address and I was finally able to reimage the loaner machine and test my application.

NOTE:  I wasn’t feeling adventurous, but in my research I came across the following Technet post.  It details a SQL query you can use to manually remove the MAC address from the database.  However, this is not supported by Microsoft and it could corrupt your database, so I left this as a last resort measure. 🙂

The task sequence failed to start with error 0x80070570.

I was testing out an OSD task sequence when I noticed I had made a mistake and I needed to restart the task sequence.  By the time I was able to force a restart, it was in the process of partitioning the hard drive.  Anyway, upon rebooting and restarting the task sequence, I was receiving error message:

“The task sequence failed to start with error 0x80070570”

This was happening right after I was picking the task sequence and assigned a computer name to a task sequence variable.  So I started doing some investigation using the F8 console window and noticed the hard drive had no partitions on it.  In order to fix this issue, I ran diskpart.exe as follows:

list disk
select disk 0
create partition primary
select partition 1
format fs=ntfs quick
assign letter=c

Then I rebooted the system with the following command “wpeutil.exe reboot”.  After the system was booted right back into WinPE, the task sequence finished without errors.

Can’t see your applications in the OSD Install Application sequence?

Today I was building out the final task sequence for the Lenovo ThinkPad X1 Carbon laptop I am configuring and while choosing the applications to install in the task sequence, I noticed all but one application was not listed in the list box to choose from.  I went to re-check the application settings and found that under the Deployment Type, in the “User Experience” tab, the “Logon Requirement” was set to “Only when a user is logged on”.  I then changed it to “Whether or not a user is logged on” and I was finally able to see the application in the task sequence.

10-17-2013 1-52-11 PM

It is also worth noting to make sure the installation behavior is set to “Install for system” and under the application’s main properties, in the “General Information” tab, you have checked the box for “Allow this application to be installed from the Install Application task sequence action without being deployed.”

Task Sequence has failed with the error code (0x80070490).

While testing out an OSD task sequence, I was receiving error message “Task Sequence: [insert task name] has failed with the error code (0x80070490).”  This particular error was hard to pinpoint a solution for because the smsts.log did not register any messages relating to this error.

However, the particular step this error was being triggered on was when attempting to apply an image.  Right off the bat I knew something was wrong as my task sequence would first partition the disk and then apply the image.  In other words, it was skipping the disk partition step.

After further inspection of the task sequence using the console, I noticed on the “Partition Disk 0” options, there was a condition specified to only run this step if the following Task Sequence Variable was met: “_SMSTSBootUEFI not equals “true”.

10-16-2013 4-57-38 PM

The particular laptop (Lenovo ThinkPad X1 Carbon) I was running this on has a UEFI BIOS enabled.  While I didn’t disable this condition because I didn’t know why it was put there in the first place, the solution was to disable UEFI and enable the “Legacy” BIOS in the laptop.  Once I rebooted and tried again, the task sequence applied without any errors.