How To: Inject Drivers from USB During a ConfigMgr Operating System Task Sequence

ConfigMgr OSD does a great job of injecting drivers ‘on the fly’ into your OS Deployment process. For example, you can create task sequence steps with conditional statements to apply drivers for a specific model. That’s great for your standard build, but how do you handle those one-offs, those non-standard builds? Here’s a process that you can you for those non-standard builds, or for that hardware that you’re testing, but haven’t quite committed to being a standard yet.  All we need is a vbScript, raw drivers, and an additional step in your task sequence (haven’t tested with MDT, but should work there as well). The following process ONLY works on Windows 7 and Windows Server 2008 R2. If there is enough demand, I’ll create a similar script for previous Operating System versions.

Step 1 – Create a USB folder with raw drivers for the desired hardware.

  • Create a folder in the root of a USB drive named “ExportedDrivers”
  • Copy desired drivers to this folder. You can create subfolders to help with organization if you’d like. Please note that *everything* in the ExportedDrivers AND ALL SUBFOLDERS will be processed, so try to keep the folder structure organized, and to ONLY include the desired raw drivers.
  • Your folder should look similar to this:
  • We have a few extra folders here to keep things organized, but you can just put them in the root of “ExportedDrivers” if desired.

Step 2 – Create a package with ImportCustomDrivers.vbs

  • Create a new Package (or just add this file to an existing package)
  • Download ImportCustomDrivers.txt, and rename to ImportCustomDrivers.vbs.
  • Send to DPs.

Step 3 – Add new step to OSD Task Sequence

  • This step should run in WinPE, just before all other “Apply Driver Package”or “Auto Apply Drivers” step.
  • Your Task Sequence step would look similar to this:
  • Depending on your environment, you may want to enable the ‘continue on error’ checkbox on the Options tab. If the script attempts to import a driver that does not apply to the current operating system, it will return a failure exit code.
  • If you have ADDITIONAL “Apply Driver Package”, or “Auto Apply Drivers”steps, and you want to skip these steps if we import drivers from the USB, enter a conditional where Task sequence variable “OSDCustomDriversApplied” not equals “True” (this variable is set in the .vbs when it runs).

Now that you have your task sequence configured, insert the USB drive into the test system and launch a test build. At the “Add Custom Drivers…” step. you will see a command prompt that shows the status of the drivers that are being injected.

  • In WinPE, two log files will be created in X:\Windows\Temp\SMSTSLog:
    • OSD_CustomDrivers.log – this is the log for the vbscript
    • DISMCustomImport.log – this is the out file from the DISM command to import everything under USBDRIVE:\ExportedDrivers\
  • The log files will also be copied to the ConfigMgr log file directory to allow for post-image troubleshooting.

Again, this process is meant for those one-off scenarios. If you plan to fully support a platform, be sure to handle driver installation using ConfigMgr driver management.

Greg

ramseyg@hotmail.com

Source Code:


'Use this script to import custom drivers for Server 2008 R2, Win7, and newer - full blog post on http://gregramsey.wordpress.com/
'Created by: Greg Ramsey

Log "ImportCustomDrivers - Start"
strComputer = "."
strDriverFolder = "ExportedDrivers"
intReturnCode = 0
intFinalReturnCode = 0
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set oShell = WScript.CreateObject("WScript.Shell")
Set colDisks = objWMIService.ExecQuery("Select * from Win32_LogicalDisk")

'enum each drive letter, and see if strDriverFolder exists in the root.
For Each objDisk In colDisks
'Check each drive letter to see if there is a
If objFSO.FolderExists(objDisk.DeviceID & "\" & strDriverFolder) Then
'this will only run in a TS environment, so fail if we can't connect to sms.tsenvironment
Log vbTab & "Connecting to SMS.TSEnvironment"
Set oTSEnv = CreateObject("Microsoft.SMS.TSEnvironment")
If err.number <> 0 Then
Log vbTAB & "Unable to connect to Microsoft.SMS.TSEnvironment"
Log "ImportCustomDrivers - End"
WScript.quit(err.number)
Else
'prepare the command line, and launch the DISM command
Log vbTAB & objDisk.DeviceID & "\" & strDriverFolder & " Exists, Importing drivers.."
strCommand = CStr("Dism /image:" & oTSEnv("OSDTARGETSYSTEMDRIVE") & "\ /logpath:%windir%\temp\smstslog\DismCustomImport.log /Add-Driver /driver:" & objDisk.DeviceID & "\" & strDriverFolder & " /recurse")
Log vbTAB & "Preparing to run the following command: " & strCommand
intReturnCode = oShell.Run(strCommand, 1, True)
Log vbTAB & "Return Code = " & intReturnCode
Log vbTAB & "Setting TS Variable OSDCustomDriversApplied = True"
oTSEnv("OSDCustomDriversApplied") = "True"
End If
Else
'no custom drivers exist
End If
'slightly cheesy - if more than one drive have the special folder, the DISM command will run more than once
' so we're using this to capture if ANY of the exit code are <> 0, so we can capture that if there are any failures
' you'll have to review the %windir%\temp\smstslog\DISMCustomImport.log for details
If intReturnCode <> 0 Then intFinalReturnCode = intReturnCode
Next
Log "Final Return code = " & intFinalReturnCode
Log "ImportCustomDrivers - End"
WScript.Quit(intFinalReturnCode)

'a simple logging subroutine
Sub Log(message)
WScript.Echo message
Const ForAppending = 8
Set WshShell = CreateObject("WScript.Shell")
strSystemRoot = WshShell.ExpandEnvironmentStrings("%SystemRoot%")
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not objFSO.FolderExists(strSystemRoot & "\Temp\SMSTSLog\") Then
objFSO.CreateFolder(strSystemRoot & "\Temp\SMSTSLog\")
End If
'Create Output Log
stroutputlog = strSystemRoot & "\temp\SMSTSLog\OSD_CustomDrivers.log"
Set objTextFile = objFSO.OpenTextFile(strOutputLog, ForAppending, True)
On Error Resume Next
txtstatus.value = Trim(Replace((message & " " & Now()), vbTab, ""))
On Error Goto 0
message = Now() & " " & message
'
' Log the given message
'
objTextFile.writeline(message)
objTextFile.Close

End Sub

System Center Universe content available for download

Head on over (and subscribe) to the CTSMUG blog to download content from System Center Universe.

 

Dell Systems and Advanced Format Hard Drives

If you’re new to OSD, make sure you understand Advance Format Drives. Chances are, you already have them in your environment. If you have new systems (or old systems with new hard disks) where users are reporting degradation of performance, or issues with Windows Update in the event log, you could be a victim. If you are responsible for Operating System Deployment, I highly recommend the following resources:

Deploying Dell Systems with Advanced Format Hard Drives from DellTechCenter

If there’s one thing I suggest you do, it’s this: Start your change control process to perform the following tasks asap:

  1. Update the WAIK to 3.1 and then update your OSD boot disk, or  apply KB 982018 to your WinPE boot disk.
  2. Deploy KB 982018 to all Win7, Server 2008 R2 systems (or upgrade them to Sp1)
  3. Update Intel Mass Storage Drivers in your OSD Process, if necessary

The easiest way to avoid any advanced format drive headaches is to get your build process updated asap.  

Greg

The Wally Files are Live over on CTSMUG Blog

Head on over to the CTSMUG blog to download the media recording’s from Wally’s presentations at our User Group meetings on January 18th and 20th.

Greg

Interesting issue with thumbs.db

I’m surprised I just ran into this today – seems easy enough to run into a long time ago.  I was working in ConfigMgr 2012 Beta 2, and was receiving failures when sending content to a distribution point. Looking at distmgr.log, I saw the following errors:

CreateFileW failed for \\servername\sharename\thumbs.db

Failed to add the file. Please check if this file exists. Error 0×80070020

 

Thumbs.db is a hidden file that contains a thumbnail cache for the current directory. I tried to delete the file, and received an error that the file was in use by Windows Explorer. I decided to test this same process in ConfigMgr 2007, and encountered the same issue (which is why I’m surprised I haven’t experienced this issue before). Finally, I terminated and restarted my Windows Explorer process (explorer.exe), and then could successfully delete the evil thumbs.db, and could then update my distribution points successfully.

To prevent this in the future, you need to disable the creation of the thumbnail cache. You can read more for how to disable this using either folder options or group policy. Both links refer to Windows 7, but the same applies to Server 2008R2. You would need to disable this feature on any system you use to browse to the package source. This issue obviously doesn’t occur all the time, but is something to be aware of moving forward.

*Note: this can also affect you if a user who has admin rights browses to a ConfigMgr DP share and thumbs.db is created. Now the hash of this folder if different than ConfigMgr expects, causing a hash mismatch error when running the program.

 

Greg

How To: Enable the “Suppress Program Notifications” Checkbox for all Programs in a Package

In a previous post, I wrote how to enable the “Suppress Program Notifications” Checkbox for Program Properties for all programs in your environment. By request, in this post we’re going to modify the script slightly to modify all programs for one package, given the PackageID.

#Select all programs for one package
#(Update MySiteServer and LAB with your ConfigMgr Server name and Site code, and PackageID with a valid packageID)
$prgs = get-wmiobject sms_program -computername MySiteServer -namespace root\sms\site_LAB -filter "PackageID='LAB0023C'"
$prgs | foreach {
#ProgramFlags are a lazy property, so make explicit call.
$prg = [wmi] $_.__Path
if ($prg.ProgramFlags -band ([math]::pow(2,10)))
{
# Suppress already enabled
}
else
{
# Not suppressed - display programname and packageID
$prg.Programname + "`t" + $prg.PackageiD
# flip the programflags bit to enable suppression
$prg.ProgramFlags = $prg.ProgramFlags -bor ([math]::pow(2,10))
# use Put to save changes
$prg.put()
}
#rinse and repeat
}

The only change we had to make was to add the filter command to the get-wmiobject cmdlet. -filter “PackageID=’LAB0023C’”

 Read more about SMS_Program and ProgramFlags.

Greg

Follow

Get every new post delivered to your Inbox.

Join 1,246 other followers