SCCM: Missing source drivers

Scenario

I recently had a customer who was having issues importing drivers into their SCCM environment.

A user thought it would be a good idea to clean out the source directory (where you import drivers from) that contained files older than 2015. This left many drivers missing and incomplete without the ability to add to any of these drivers to new packages. When SCCM adds a new driver to a driver package it copies the source files in the driver package.

The backups didn’t go back far enough to recover the files and so when a new driver was imported it would error because it would attempt to add the source file (which no longer existed) into the new driver package.

What can we do?

So, how do we find these missing drivers? We know that the primary SCCM server’s content library contains these in the driver packages, but due to the file structure SCCM creates its hard to locate them.

In my case there were over 3200 driver sources that were missing. So, I used a mix of WMI and PowerShell to track down which driver packages already deployed had a copy of these files.

Once I found all the driver packages containing these missing drivers, I was able to copy them back to their original location.





Here is a sample of the script I used to locate them all;

# Site configuration

$SiteCode = “xxx” # Site code
$ProviderMachineName = “servername.FQDN” # SMS Provider machine name

# Customizations

$initParams = @{}

# Import the ConfigurationManager.psd1 module

if((Get-Module ConfigurationManager) -eq $null) {
   Import-Module “$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1” @initParams
}

# Connect to the site’s drive if it is not already present

if((Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue) -eq $null) {

    New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName @initParams

}

Set-Location “$($SiteCode):\” @initParams

# Reset all counters

$loopCounter = 0
$Missing = @()
$found = @()
$i = 0

<# First, I gathered a list of all drivers in the environment #>

$DriverList = Get-CMDriver | select CI_ID, LocalizedDisplayName, ContentSourcePath, DriverVersion, DriverDate, DriverProvider, DriverClass, DriverINFFile, ObjectPath

<# Then I checked to see If the file path exists #>

foreach ($Driver in $DriverList){
    $i++
   Write-Host “Checking driver: ” -NoNewline
  Write-Host $i ” /” $DriverList.Count -ForegroundColor Yellow
  $TestPath = [System.IO.Directory]::Exists($Driver.ContentSourcePath)
        if(!($TestPath)){
          $Missing += $Driver       
}
      else { $found += $Driver }
}
Write-Host “Total number of drivers investigated: ” $DriverList.count
Write-Host “Total number of drivers with missing content: ” $Missing.count  




Now that we know how many drivers are missing, we can use WMI to check where this content is on the server and which driver packs contain it.

<# Once you have variable that contains all the missing drivers, in this case ‘$missing’ you can then use WMI to check if the CID exists in any DriverPackages. #>

ForEach ($Driver in $Missing){

    # Set the current location to be the site code.

    Set-Location “$($SiteCode):\”

    # Set the variables

    $CID = $Driver.CI_ID
  $DriverName = $Driver.DriverINFfile
$ContentSourcePath = $Driver.ContentSourcePath

    # Check where the CID exists in WMI

    Write-Host “Step 1: Searching WMI for CID: $CID … “
   $FoundObj = $WMI | ? {$_.CI_ID -match $CID} | select -First 1

    # Confirm if any packages found.

    If ($FoundObj) { } Else { Write-Host “Could not find any packages for $CID ” -ForegroundColor Red }

    # Find the Package based on the name

    Write-Host “Step 2: Query SCCM for a Driver Package”
   $DriverPackageName = $FoundObj.Name
  $pkg = Get-CMDriverPackage -Name $DriverPackageName
    Write-Host “Step 3: Found driver package $DriverPackageName that containts $driverName”

    # Grab the Driver Package path

    $source = $pkg.PkgSourcePath

    # Output to console

    Write-Host “Found $DriverName in $source” -ForegroundColor Yellow
}




You can then dump all the output to a log file and create another script to copy the found files back to their original source.

Hope this script helps!