Automate Driver Installation

The drivers can be installed in different ways, but when installed, they are loaded into the folder named: ‘DriverStore’, which is located under %SYSTEMDRIVE%\Windows\System32\DriverStore. You can use different command line tools to populate this driver store as follows:
1. PnPutil is a command-line tool that is included in every version of Windows, and the following example show how it can be used with PowerShell script to add and install driver.

$driversCollection = (Get-ChildItem -Path C:\MyDriversFolder -Filter "*.inf" `
-Recurse -ErrorAction SilentlyContinue | 
Select-Object -ExpandProperty Fullname)
foreach($driver In $driversCollection){
# Add and install driver package
pnputil.exe -i -a $driver
} 

2. DISM is a command-line tool that can be used to service a Windows image and therefore to add driver packages with the following servicing options available for an offline image.
DISM.exe /image: [/Get-Drivers | /Get-DriverInfo | /Add-Driver | /Remove-Driver | /Export-Driver]
An example:

$MountPath = “C:\Images\Win7OffLine”
$WimFile = “C:\Images\Win7.wim"
$driverFolder = "C\Drivers\HP EliteBook 850\HP_ZEP_G1_W7_X64_A1.106\x64_win7"
# ---------------------------------------------------------------------------
# MOUNT
If(!(Test-Path $MountPath)){New-Item -Path $MountPath -ItemType directory}
    	dism.exe /Mount-Wim /WimFile:$WimFile /index:1 /Mountdir:$MountPath
#INJECT DRIVERS
# --------------------------------------------------------------------------
If(Test-Path -Path $driverFolder){
    	dism.exe /Image:$MountPath /Add-Driver /Driver:$driverFolder /Recurse
}
# UNMOUNT
# --------------------------------------------------------------------------
dism.exe /Unmount-Wim /Mountdir:$MountPath /commit
 

I have used both PnPutil and DISM to install drivers in different scenarios, but always wanted a command-line app that will overcome limitations of the aforementioned tools. Firstly, if you have an unsigned driver, pnputil.exe will be prompted with the message “Windows can’t verify the publisher of this driver software”, and you will need to click Install to allow installation to proceed, and secondly, DISM.exe commands and options depend on whether the image is currently online (running an operating system) or the system is offline; unfortunately you cannot use DISM.exe when the system is online for the purpose of loading/removing drivers.
Starting with Windows 7, the Windows Driver Kit (WDK) includes version 2.1 of DPInst.exe command line tool that will silently install signed and unsigned drivers on a Windows running operating system. Being part of the Windows Driver Kit (WDK), you have to download kits and tools for Windows in order to obtain DPInst.exe. To download WDK, please use this link: http://www.microsoft.com/whdc/devtools/WDK/default.mspx

DPInst Example:
Please note that there are separate x64 and x86 dpinst.exe executable. Always use the latest version for your scripts. In this example, I will present a PowerShell script that I use with SetupComplete.cmd file to finalize installation of drivers after Windows Setup completes.
I place all my drivers inside C:\Driver folder as shown in the pictures below:

DriverdFolderPicture 1: Driver folder with all the drivers sorted by Manufacturer and hardware Model

DriverdFolder02Picture 2: displaying drivers available for hardware Model – “HP EliteBook 8540p”

As you can see, I prefer to create a folder for each Manufacturer and a subfolder for each hardware Model. Having this well organized Driver folder structure helps me to be very granular of what drivers are available during installation. To find out computers’ Manufacturer and Model, I usually use WMI Win32_ComputerSystem class, but you can run the MSInfo32 command and from its output write down the values for System Manufacturer and System Model items.
Here is the PowerShell script:

# Filename:	InstallDriver.ps1
# Date:		Oct 2015
# Author:	Alex Dujakovic
# Description:  PS script to inject/install drivers  
# ===================================================================

$driverFolder = "C:\Driver"
$installDriverLog = "C:\Windows\Temp\DriverLog.log"

$m = (Get-WmiObject -Class Win32_ComputerSystem -Property * |
Select-Object -Property Manufacturer, Model)
Write-Host "Manufacturer is: $($m.Manufacturer)" -ForegroundColor Green
Write-Host "Model is: $($m.Model)" -ForegroundColor Green


Function InstallDriver($path){
$x = (Get-ChildItem -Path $path -Recurse -Filter "*.inf" | select -Property Directory)
    foreach ($i In $x){
        try{
            $errorActionPreference = "Stop" 
            # Installing driver
            Write-Host "Installing driver: $($i.Directory.FullName)" -ForegroundColor Yellow
	        C:\Driver\dpinst.exe /path "$($i.Directory.FullName)" /lm /s /sa | Out-Null
            "Installing driver: $($i.Directory.FullName)" | 
            Out-File $installDriverLog -Encoding ascii -Append
        }
        catch{
            Write-Host "Error installing driver: $($i.Directory.FullName)" -ForegroundColor Red
            "Error installing driver: $($_.Exception.GetType().FullName)" | 
            Out-File $installDriverLog -Encoding ascii -Append
            "Exception Message: $($_.Exception.Message)" | 
            Out-File $installDriverLog -Encoding ascii -Append
        }
     }
}

$p = (Get-ChildItem -Path "$($driverFolder)" -Recurse -Directory -Filter "$($m.Model)" | 
Where-Object -FilterScript {$_.Name -match "$($m.Model)"} |
Select-Object -Property FullName)

If (!($p.FullName -eq $null) -and (Test-Path "$($p.FullName)")) {
    InstallDriver -path "$($p.FullName)" | Out-Null
    Write-Host "Finish driver installation" -ForegroundColor Green
}
Else{
    Write-Host "Folder with drivers for Manufacturer: '$($m.Manufacturer)' `
    - Model: '$($m.Model)' not found" -ForegroundColor Red
    "Folder with drivers for Manufacturer: '$($m.Manufacturer)' - Model: '$($m.Model)' not found" | 
    Out-File $installDriverLog -Encoding ascii -Append
}

And here is the SetupComplete.cmd file example:

start “Driver Installation” /wait C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -WindowStyle Normal -ExecutionPolicy ByPass -File “C:\Driver\InstallDriver.ps1”

Note that commands in the Setupcomplete.cmd file are executed with local system privilege. After Windows is installed, but before the logon screen appears, Windows Setup searches for the SetupComplete.cmd file in the %WINDIR%\Setup\Scripts\ directory. If a SetupComplete.cmd file is found, the file is executed. Windows Setup logs the action in the Setupact.log file. You cannot reboot the system and resume running SetupComplete.cmd. The functionality of Setupcomplete.cmd differs from the RunSynchronous and RunAsynchronous commands in that Setupcomplete.cmd runs after Windows Setup completes while the RunSynchronous and RunAsynchronous commands run during Windows Setup.


4 thoughts on “Automate Driver Installation

  1. Olv'

    This ps script was exactly what I was looking for my multiple systems imaging, it works like a charm after the sysprep process. So, THANKS for sharing the script.
    It only requires at least the version 3 of Powershell installed.

    Reply
  2. Nicu Berger

    Thank you so much for the pnputil.exe idea. I made a ps1 with your script and then i’ve made a script that copies that ps1 and a bunch of drivers dependig on the HW model and starts the copied ps1 via invoke-command. Now i’ve got a simple way for automated driver deployment.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *