So as we make the move to Modern Management, one of the reoccurring questions I keep hearing is how to automate the deployment of updated drivers to Intune enrolled devices?
This is of course a new situation we find ourselves having to deal with. The traditional model of course is to package driver updates through ConfigMgr and update them on machines using DISM or depend on vendor supplied utilities. So when Microsoft added the ability to run PowerShell scripts through Intune, this got me thinking that I could re-architect parts of our Driver Automation Tool / Modern Driver Management solutions to run locally.
Introducing The Script
Here it is, version 1.0 of the Invoke-MSIntuneDriverUpdate.ps1 which automates the following processes for Dell, HP and Lenovo devices;
- Determine the make/model and system sku or baseboard product values
- Download or read in an appropriate manufacturer source file and match a driver download
- Download and extract the drivers
- Install the drivers
- Provide full logging for each step of the process
The script in total is 741 lines and just over 30Kb, which is about 1/20th the size of the GUI Driver Automation Tool, so this script is indeed “tiny“.
Prerequisites
The script is for use with Windows 10 only.
Lets Step Through The Process
The first thing to do of course is download the script from the MS Technet Site – https://gallery.technet.microsoft.com/scriptcenter/Driver-Automation-Script-a933dd50.
Note: I have also included a copy of the script on our GitHub site in case you wish to expand/branch the script as per your own requirements – https://github.com/MSEndpointMgr/Intune/blob/master/Driver%20Automation/Invoke-MSIntuneDriverUpdate.ps1
Now you have the script, lets proceed with rolling it out via Intune:
- Log onto your Azure / Intune Portal
- Click on Intune on the blades section
- Click on Device Configuration
- Click on PowerShell Scripts
- Click on +Add
- Browse and select the Invoke-MSIntuneDriverUpdate.ps1
- Click Create
- Click on Assignments and assign the script to a group
- Monitor the deployment
What To Expect – During Run time
When the script initialises you should see the creation of a Temp folder on the C:\ followed by a series of sub folders. If you are using Dell or HP client devices, the first thing you should see is files starting to appear in the SCConfigMgr\Temp folder. Here you find the downloaded CAB files and extracted XML files used for matching models during the WMI query process in the script. The Lenovo process runs online as the XML is hosted, rather than being contained within a downloadable cabinet file:
You should also see two sub folders, the first of which is the Driver Cab folder and this is used for downloading the compressed driver package files. In the below example you will see drivers from all three vendors:
Dell, HP and Lenovo Driver Files
In the below screenshot you will see the contents of the other sub folder, that being the Driver Files folder. This is where the driver files are extracted to and installed from later in the script:
Example: HP ProOne 600 G2 21.5-inch Non-Touch All-in-One PC – Extracted folder structure
Model Matching
The matching process in the script uses either the SystemSKU or BaseBoard Product values depending on the make of hardware used. For simplicity I have labelled the variable as SystemSKU for all makes, below is an example of the methods used;
# Determine manufacturer name and hardware information switch -Wildcard ($ComputerManufacturer) { "*HP*" { $ComputerManufacturer = "Hewlett-Packard" $ComputerModel = Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model $SystemSKU = (Get-CIMInstance -ClassName MS_SystemInformation -NameSpace root\WMI).BaseBoardProduct } "*Hewlett-Packard*" { $ComputerManufacturer = "Hewlett-Packard" $ComputerModel = Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model $SystemSKU = (Get-CIMInstance -ClassName MS_SystemInformation -NameSpace root\WMI).BaseBoardProduct } "*Dell*" { $ComputerManufacturer = "Dell" $ComputerModel = Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model $SystemSKU = (Get-CIMInstance -ClassName MS_SystemInformation -NameSpace root\WMI).SystemSku } "*Lenovo*" { $ComputerManufacturer = "Lenovo" $ComputerModel = Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object -ExpandProperty Version $SystemSKU = ((Get-CIMInstance -ClassName MS_SystemInformation -NameSpace root\WMI | Select-Object -ExpandProperty BIOSVersion).SubString(0, 4)).Trim() } }
These values are used as a primary match as they provide a unique identifier for the machine, I have found that the model name doesn’t always provide this exact match. There have been instances however where the SystemSKU value on some Dell machines has not been inserted, so if this occurs the script will fall back to attempting a match based on the model name;
if ($SystemSKU -ne $null) { global:Write-CMLogEntry -Value "Info: SystemSKU value is present, attempting match based on SKU - $SystemSKU)" -Severity 1 $ComputerModelURL = $DellDownloadBase + "/" + ($DellModelCabFiles | Where-Object { ((($_.SupportedOperatingSystems).OperatingSystem).osCode -like "*$WindowsVersion*") -and ($_.SupportedSystems.Brand.Model.SystemID -eq $SystemSKU) }).delta $ComputerModelURL = $ComputerModelURL.Replace("\", "/") $DriverDownload = $DellDownloadBase + "/" + ($DellModelCabFiles | Where-Object { ((($_.SupportedOperatingSystems).OperatingSystem).osCode -like "*$WindowsVersion*") -and ($_.SupportedSystems.Brand.Model.SystemID -eq $SystemSKU) }).path $DriverCab = (($DellModelCabFiles | Where-Object { ((($_.SupportedOperatingSystems).OperatingSystem).osCode -like "*$WindowsVersion*") -and ($_.SupportedSystems.Brand.Model.SystemID -eq $SystemSKU) }).path).Split("/") | select -Last 1 } elseif ($SystemSKU -eq $null -or $DriverCab -eq $null) { global:Write-CMLogEntry -Value "Info: Falling back to matching based on model name" -Severity 1 $ComputerModelURL = $DellDownloadBase + "/" + ($DellModelCabFiles | Where-Object { ((($_.SupportedOperatingSystems).OperatingSystem).osCode -like "*$WindowsVersion*") -and ($_.SupportedSystems.Brand.Model.Name -like "*$ComputerModel*") }).delta $ComputerModelURL = $ComputerModelURL.Replace("\", "/") $DriverDownload = $DellDownloadBase + "/" + ($DellModelCabFiles | Where-Object { ((($_.SupportedOperatingSystems).OperatingSystem).osCode -like "*$WindowsVersion*") -and ($_.SupportedSystems.Brand.Model.Name -like "*$ComputerModel") }).path $DriverCab = (($DellModelCabFiles | Where-Object { ((($_.SupportedOperatingSystems).OperatingSystem).osCode -like "*$WindowsVersion*") -and ($_.SupportedSystems.Brand.Model.Name -like "*$ComputerModel") }).path).Split("/") | select -Last 1 }
Driver Update Example
Here you will see an example of a driver updated during the process.
In this example we are looking at the touchpad driver for a Dell Latitude E5470, using the latest SCCM driver package (as of 3/12/2017 – https://en.community.dell.com/techcenter/enterprise-client/w/wiki/11789.latitude-e5470-windows-10-driver-pack):
Dell Driver Pack Note:
Device Manager Post Update:
My demo laptop in this instance was enrolled in Intune and immediately installed the drivers as per the script running, below is an extract from the log:
Review The Logs
Obviously you can monitor the status of the deployed script through the portal, however the script itself also has extensive logging for troubleshooting purposes.
The primary log is the Invoke-MSIntuneDriverUpdate.log located in the C:\Temp\SCConfigMgr\Logs directory (note you can also change the location of the base temp directory in the script). This log will show you all of the key steps undertaken during each step of the script:
The next script is the Install-Drivers.log file, this is generated only once the drivers are available to install using the PNPUtil utility:
What Isn’t Covered
At this point BIOS updates and proxies are not catered for. I can add in the BIOS update feature if its something of interest, as for proxy servers I urge you to play around with the script and find out settings that suit your environment.
Other Things To Note
Driver packages are subject to the vendor providing enterprise ready bundled driver packages for use with SCCM. It is these packages which are extracted in the script. If your model is not listed then please refer to the vendor SCCM pages to cross reference against supported models and OS versions.
Dell – https://en.community.dell.com/techcenter/enterprise-client/w/wiki/2065.dell-command-deploy-driver-packs-for-enterprise-client-os-deployment
HP – https://ftp.hp.com/pub/caps-softpaq/cmit/HP_Driverpack_Matrix_x86.html / https://ftp.hp.com/pub/caps-softpaq/cmit/HP_Driverpack_Matrix_x64.html
Lenovo – https://support.lenovo.com/ie/en/solutions/ht074984
Feedback
If you have any feedback, please drop me an email ([email protected]).
I would love to use this script for handling BIOS updates as well, that would be really neat!
Really nice work, if you could get BIOS update in there as well that would be a dealbreaker!
We already install both drivers and BIOS upgrades in our current image installation through tasksequence from SCCM so this was a Little issue from on us when going over to modern deployment and autopilot.
Is there any chance you could add the Bios updates into the script as well please?
Thank you very much
I had a T440 that found 2 driver packages, 1 from 2016 and 1 from 2018.
I had to make some changes to have the script select the latest, at around line 341.
Simply amazing! Thanks again!
Nice work 🙂