Dell Driver Pack Download and Update CM Package

<Copy from last Post> This Script connects to your ConfigMgr then compares the list of BIOS Driver Cabs to what Dell has available. Note, there are some other great tools like the Driver Automation Tool, but those didn’t fit my needs and I wanted to fully automate this with scheduled tasks.  We also had issues using the tool in our network due to our proxy servers, so I wrote my own.

This tool will download the Cabs, Expand them, and Update the Package Info (Does NOT create the CM Packages)

Build your list of Dell Models, Let it know the Package Number, then the script will do the rest.  I also have this script send me an email, you’ll need to update it to fit your needs.

Your List of Dell Models & the associated Package ID:

</Copy from last Post>
You should read this first (last Post):

What it looks like in the Console after you’ve run script.. (ignore the BIOS references)

image-5.png (1024×382)

Folder Structure it Creates:

The .CAB file will be located in the Driver Cab Folder


It then Extracts the Cab into a folder called “Windows10-VERSION”


The CMPackage Source is set to the x64 folder as shown above.


It also sets all of this wonderful information:

Email Alert:


Script Code:

Downloads Driver Packs for Specific Models.
    Param (
		    $RunMethod = "Download"


#Settings for Google - Rest of Info @ Bottom
$SMTPServer = ""
$SMTPPort = "587"
$Username = ""
$Password = "yourgmailpassword"

$LogFile = "$PSScriptRoot\DellDriverPackDownload.log"
$SiteCode = "ps2"
$EmailArray = @()
$scriptName = $MyInvocation.MyCommand.Name
$CabPath = "$PSScriptRoot\"
$FileServerName = "SRC"

#region: CMTraceLog Function formats logging in CMTrace style
        function CMTraceLog {
    Param (
		    $Component = "Dell Driver Cab Downloader",
    Type: 1 = Normal, 2 = Warning (yellow), 3 = Error (red)
	    $Time = Get-Date -Format "HH:mm:ss.ffffff"
	    $Date = Get-Date -Format "MM-dd-yyyy"
	    if ($ErrorMessage -ne $null) {$Type = 3}
	    if ($Component -eq $null) {$Component = " "}
	    if ($Type -eq $null) {$Type = 1}
	    $LogMessage = "<![LOG[$Message $ErrorMessage" + "]LOG]!><time=`"$Time`" date=`"$Date`" component=`"$Component`" context=`"`" type=`"$Type`" thread=`"`" file=`"`">"
	    $LogMessage | Out-File -Append -Encoding UTF8 -FilePath $LogFile

function Get-FolderSize {
Param (
$Units = "MB"
  if ( (Test-Path $Path) -and (Get-Item $Path).PSIsContainer ) {
    $Measure = Get-ChildItem $Path -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum
    $Sum = $Measure.Sum / "1$Units"
      "Path" = $Path
      "Size($Units)" = $Sum

$DellModelTable = @(

        @{ Model = "Latitude 5290"; PackageID = "PS200042"}
        @{ Model = "Latitude 5490"; PackageID = "PS200043"}
        @{ Model = "Latitude 5580"; PackageID = "PS200044"}
        @{ Model = "Latitude 5590"; PackageID = "PS200045"}
        @{ Model = "Latitude 7275"; PackageID = "PS200046"}
        @{ Model = "Latitude 7280"; PackageID = "PS200047"}
        @{ Model = "Latitude 7480"; PackageID = "PS200048"}
        @{ Model = "Latitude E5570"; PackageID = "PS200049"}
        @{ Model = "Latitude E7250"; PackageID = "PS20004A"}
        @{ Model = "Latitude E7270"; PackageID = "PS20004B"}
        @{ Model = "Latitude E7450"; PackageID = "PS20004C"}
        @{ Model = "Latitude E7470"; PackageID = "PS20004D"}
        @{ Model = "OptiPlex 3040"; PackageID = "PS20004E"}
        @{ Model = "Optiplex 5050"; PackageID = "PS20004F"}
        @{ Model = "OptiPlex 5060"; PackageID = "PS200050"}
        @{ Model = "Optiplex 7040"; PackageID = "PS200051"}
        @{ Model = "Optiplex 7050"; PackageID = "PS200052"}
        @{ Model = "Venue 11 Pro 7140"; PackageID = "PS200053"}

cd c:
# Format Cab DL Path
$scriptName = $MyInvocation.MyCommand.Name
$CabPath = "$PSScriptRoot\"
if  (Test-Path 'C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin'){Import-Module 'C:\Program Files (x86)\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1'}

write-host "Current Running Mode = $RunMethod" -ForegroundColor Yellow
CMTraceLog -Message "Starting Script: $scriptName" -Type 1 -LogFile $LogFile
Write-Output "Starting Script: $scriptName"

#Check if Running with Access to Source Server (File Server)
try {Test-Connection -ComputerName $FileServerName -Quiet -Count 1 
    $DownloadPackRoot = "\\$FileServerName\src$\OSD\Drivers\Dell"
    $DownloadToServer = $true
    Write-Output "Connected to Server $FileServerName"
    Write-Output "Not Connected to File Server, Exiting"
    $DownloadToServer = $false

#If you use a Proxy... configure this secion... if not... make sure you don't have something with
if ((Test-NetConnection -Port 8080).NameResolutionSucceeded -eq $true) 
    $UseProxy = $true
    CMTraceLog -Message "Found Proxy Server, using for Downloads" -Type 1 -LogFile $LogFile
    Write-Output "Found Proxy Server, using for Downloads"
    $ProxyServer = ""
    $BitsProxyList = @(",,")
    CMTraceLog -Message "No Proxy Server Found, continuing without" -Type 1 -LogFile $LogFile
    Write-Output "No Proxy Server Found, continuing without"

# Download Dell Cab File (Invoke-WebRequest works with our without Proxy info if you use -Proxy, so no need to change command if you use Proxy.. unlike Bits Transfer)

Write-Output "Starting Download of Dell Catalog"
CMTraceLog -Message "Starting Download of Dell Catalog" -Type 1 -LogFile $LogFile
Invoke-WebRequest -Uri "" -OutFile $CabPath -UseBasicParsing -Verbose -Proxy $ProxyServer
While(!(Test-Path $CabPath) -and $n -lt '3'){
    Invoke-WebRequest -Uri "" -OutFile $CabPath -UseBasicParsing -Verbose -Proxy $ProxyServer

# Extract XML from Cab File
Write-Output "Starting Expand of Dell Catalog"
CMTraceLog -Message "Starting Expand of Dell Catalog" -Type 1 -LogFile $LogFile
If(Test-Path "$PSScriptRoot\DriverPackCatalog.xml"){Remove-Item -Path "$PSScriptRoot\DriverPackCatalog.xml" -Force -Verbose}
Start-Sleep -Seconds 1
expand $CabPath "$PSScriptRoot\DriverPackCatalog.xml"
Write-Output "Successfully Extracted DriverPackCatalog.xml to $PSScriptRoot"
Start-Sleep -Seconds 1 #Wait for extract to finish
[xml]$XML = Get-Content "$PSScriptRoot\DriverPackCatalog.xml" -Verbose

    # Create Array of Downloads
    $Downloads = $Xml.DriverPackManifest.DriverPackage
    ForEach ($DellModel in $DellModelTable)
        {Write-Host "---Starting to Process Model: $($DellModel.Model)---" -ForegroundColor Cyan
         CMTraceLog -Message  "---Starting to Process Model: $($DellModel.Model)---" -Type 2 -LogFile $LogFile
        #Create Download Link For Model
        #This is where you might need to change some filters to fit your need, like I needed to exclude (-notmatch) 2 in 1 devices.
        $Target = $Downloads | Where-Object -FilterScript {$PSitem.SupportedSystems.Brand.Model.Name -match $($DellModel.Model) -and $PSItem.SupportedOperatingSystems.OperatingSystem.osCode -match "Windows10"}
        $Target = $Target | Where-Object -FilterScript {$PSItem.path -notmatch "2-IN-1"}
        $Target = $Target | Where-Object -FilterScript {$PSItem.path -notmatch "AIO"}
        $Target = $Target | Where-Object -FilterScript {$PSItem.path -notmatch "9020M"}
        $CMPackageVersionLabel = "$($Target.vendorVersion), $($Target.dellVersion)"
        $TargetLink = "$($Target.path)"
        $TargetFileName = ($'#cdata-section').Trim()
        $TargetPath = "$DownloadPackRoot\$($DellModel.Model)\Driver Cab"
        $TargetFilePathName = "$TargetPath\$TargetFileName"
        $DellModelNumber = $DellModel.Model.Split( )[1]
        $ReleaseDate = Get-Date $Target.dateTime -Format 'yyyy-MM-dd'

        if (-NOT(Test-Path $TargetPath))
            CMTraceLog -Message  "Creating Directory $TargetPath" -Type 1 -LogFile $LogFile
            Write-Host "Creating Directory $TargetPath"
            New-Item -Path $TargetPath -ItemType Directory
        #Get Current Driver CMPackage Version from CM
        Set-Location -Path "$($SiteCode):"
        $PackageInfo = Get-CMPackage -Id $DellModel.PackageID -Fast
        Set-Location -Path "C:"

        #Do the Download
        if ($PackageInfo.Version -eq $Target.dellVersion)
            Write-host "CM Package $($PackageInfo.Name) already Current" -ForegroundColor Green
            $EmailArray += "<font color='green'> CM Package <b> $($PackageInfo.Name)</b> already Current with version <b>$($PackageInfo.Version) </b></font> <br>"
            CMTraceLog -Message "CM Package $($PackageInfo.Name) already Current" -Type 1 -LogFile $LogFile
            Write-host "Updated Driver Pack for $($DellModel.Model) available: $TargetFileName" -ForegroundColor Yellow
            $EmailArray += "<font color=#8B0000>Updated Driver Pack for <b>$($DellModel.Model)</b> available: <b>$TargetFileName</b></font> <br>"
            CMTraceLog -Message  "Updated Driver Pack for $($DellModel.Model) available: $TargetFileName" -Type 1 -LogFile $LogFile
            Write-host "Need to Update CM Package $($PackageInfo.Name) from $($PackageInfo.Version) to $($Target.dellVersion)" -ForegroundColor Yellow
            $EmailArray += "<font color=#8B0000>Need to Update CM Package <b>$($PackageInfo.Name)</b> from <b>$($PackageInfo.Version)</b> to <b>$($Target.dellVersion)</b></font> <br>"
            CMTraceLog -Message "Need to Update CM Package $($PackageInfo.Name) from $($PackageInfo.Version) to $($Target.dellVersion)" -Type 1 -LogFile $LogFile
        if ($RunMethod -eq "Download")
            $OldDownload = Get-childitem -Path "$DownloadPackRoot\$($DellModel.Model)\Driver Cab\*.cab" | Select-Object -ExpandProperty Name
            if ($OldDownload -eq $null) 
                Write-host "There currently no source files for Model: $($DellModel.Model)" -ForegroundColor Yellow
                CMTraceLog -Message  "There currently no source files for Model: $($DellModel.Model)" -Type 1 -LogFile $LogFile
                Write-host "Current Downloaded Pack for $($DellModel.Model) is $OldDownload" -ForegroundColor Yellow
                CMTraceLog -Message  "Current Downloaded Pack for $($DellModel.Model) is $OldDownload" -Type 1 -LogFile $LogFile
            CMTraceLog -Message  "Starting Download of $($DellModel.Model) Driver Cab: $TargetFileName" -Type 1 -LogFile $LogFile
            Write-Output "Starting Download of $($DellModel.Model) Driver Cab: $TargetFileName" 
            #BITS Download of Driver Pack with Retry built in (Do loop)
            $BitStartTime = Get-Date
            Import-Module BitsTransfer
            $DownloadAttempts = 0
            if ($UseProxy -eq $true) {Start-BitsTransfer -Source $TargetLink -Destination $TargetFilePathName -ProxyUsage Override -ProxyList $BitsProxyList -DisplayName "$TargetFileName" -Asynchronous}
            else {Start-BitsTransfer -Source $TargetLink -Destination $TargetFilePathName -DisplayName "$TargetFileName" -Asynchronous}
                Get-BitsTransfer -Name "$TargetFileName" | Resume-BitsTransfer
                ((test-path "$TargetFilePathName") -ne $true)

            #Invoke-WebRequest -Uri $TargetLink -OutFile $TargetFilePathName -UseBasicParsing -Verbose -Proxy $ProxyServer -ErrorAction Stop
            $DownloadTime = $((Get-Date).Subtract($BitStartTime).Seconds)
            CMTraceLog -Message  "Download Complete: $TargetFilePathName" -Type 1 -LogFile $LogFile
            Write-Output "Download Complete: $TargetFilePathName"
            CMTraceLog -Message  "Took $DownloadTime Seconds to Download $TargetFileName with $DownloadAttempts Attempt(s)" -Type 1 -LogFile $LogFile
            Write-Output "Took $DownloadTime Seconds to Download $TargetFileName with $DownloadAttempts Attempt(s)"
            $EmailArray += "<font color=#8B0000>Took $DownloadTime Seconds to Download $TargetFileName with $DownloadAttempts Attempt(s)</font> <br>"
            if (test-path $TargetFilePathName)
                cd c:
                $ExpandFolder = "$DownloadPackRoot\$($DellModel.Model)\Windows10-$($Target.dellVersion)"
                $PackageSourceFolder = "$($ExpandFolder)\$($DellModelNumber)\win10\x64"
                CMTraceLog -Message  "Create Source Folder: $ExpandFolder" -Type 1 -LogFile $LogFile
                New-Item -Path $ExpandFolder -ItemType Directory -Force
                CMTraceLog -Message  "Starting Expand Process for $($DellModel.Model)" -Type 1 -LogFile $LogFile
                Write-Output "Starting Expand Process for $($DellModel.Model) file $TargetFileName"
                $Expand = expand $TargetFilePathName -F:* $ExpandFolder
                $FolderSize = (Get-FolderSize $ExpandFolder)
                $FolderSize = [math]::Round($FolderSize.'Size(MB)') 
                CMTraceLog -Message  "Finished Expand Process for $ExpandFolder, size: $($FolderSize)MB" -Type 1 -LogFile $LogFile
                Write-Output "Finished Expand Process for $ExpandFolder, size: $FolderSize"
                $EmailArray += "<font color=#8B0000>Finished Expand Process for $($TargetFileName), size: $($FolderSize)MB</font> <br>"

                #Update Package to Point to new Source & Trigger Distribution
                if ($DownloadToServer -eq $true)
                    Set-Location -Path "$($SiteCode):"
                    Set-CMPackage -Id $DellModel.PackageID -path $PackageSourceFolder
                    Set-CMPackage -Id $DellModel.PackageID -Version $Target.dellVersion
                    #Set-CMPackage -Id $DellModel.PackageID -DriverPkgVersion $Target.dellVersion
                    #Set-CMPackage -Id $DellModel.PackageID -DriverModel $DellModel.Model
                    #Set-CMPackage -Id $DellModel.PackageID -DriverManufacturer "Dell"
                    Set-CMPackage -Id $DellModel.PackageID -Description "Version $($Target.dellVersion) Released $($ReleaseDate).  Cab Location = $TargetFilePathName" 
                    Set-CMPackage -Id $DellModel.PackageID -Language $Target.releaseID
                    $PackageInfo = Get-CMPackage -Id $DellModel.PackageID -Fast
                    $EmailArray += "<font color=#8B0000>Updated Package $($PackageInfo.Name), ID $($DellModel.PackageID) Information: </font><br>"
                    $EmailArray += "<font color=#8B0000>&emsp;Version to $($Target.dellVersion) </font><br>"
                    $EmailArray += "<font color=#8B0000>&emsp;Language to: $($Target.releaseID)</font><br>"
                    $EmailArray += "<font color=#8B0000>&emsp;Desciption to: Version $($Target.dellVersion) Released $TargetDate.  Cab Location = $($TargetFilePathName)</font><br>"
                    Update-CMDistributionPoint -PackageId $DellModel.PackageID
                    Set-Location -Path "C:"
                    CMTraceLog -Message "Updated Package $($PackageInfo.Name), ID $($DellModel.PackageID) to $($PackageInfo.Version) which was released $ReleaseDate"  -Type 1 -LogFile $LogFile


#Settings for Email
#Customize this Part for your Subject & Body.  Keep it short if you plan to use SMS texts.
$to = ""
$subject = "Dell Driver Pack Updates"
$body = "$EmailArray" 
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.body = $body
$message.IsBodyHTML = $true
$message.from = $username
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
write-host "Mail Sent"
CMTraceLog -Message "Finished Script: $scriptName" -Type 1 -LogFile $LogFile
Write-Output "Finished Script: $scriptName"


I was asked if this could be done with traditional Driver Packages... yes, yes you can...

It's not quite the same, the commands would be different.. Instead of making Legacy Packages to hold the Extracted Content, you'd create Driver Packages, then run the PowerShell commands to Import the extracted drivers into the Driver Pack. You'd need to do something like
$CMDriverPack = Get-CMDriverPackage -id "PS20009B"
Import-CMDriver -UncFileLocation "\\src\src$\OSD\Drivers\Dell\Latitude 5290\Windows10-A07\5290\win10\x64" -ImportFolder -DriverPackage $CMDriverPack
You could then get fancy and apply the Version to the CMDriverPack
Set-CMDriverPackage -inputobject $CMDriverPack -version $DellVersion

Doing just one driver pack took a very long time to do in my lab. (which is actually pretty slow, so hopefully it won't take as long for you) but still



Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.