Hello,
I just wanted to share how I’ve been handling driver installation to have 1 image work for over 20 different models. I’ve done this for both Windows 7 and Windows 10 with (mostly) great results.
I’d argue that the most important step is to make sure your image contains all of the NIC drivers for all the models that you need to support. Drivers are going to be hosted on a network share. No NIC drivers means no Internet.
Go ahead and download all of the NIC drivers for all of your models or find driver packs online. Once downloaded extract the files to a common folder. In the root of the folder create a PowerShell script with the following line. Run the script. (You may need to adjust your Execution Policy to run scripts. Google it.)
Get-ChildItem -Path $PSScriptRoot -Recurse | Where-Object -Property Extension -EQ ".inf" | ForEach { PnPUtil.exe -a $PSItem.FullName }
This will do a recursive search for all files that have the .inf extension and use pnputil to add them to Windows driver store. During sysprep Windows will detect your hardware and pull the correct driver from the driver store.
Besides the NIC drivers, there are only 3 files that I add to the image. My unattend.xml, SetupComplete.cmd, and SetupComplete.ps1. The rest are pulled from a network share.
I assume you already have a working answer file, I’m not going to go into that or how to use sysprep.
SetupComplete.cmd - Located in C:\Windows\Setup\Scripts\ - You’ll need to create the Scripts folder.
@ECHO OFF
ECHO Initializing Driver Installation Script
START /wait PowerShell.exe -Command "& '%~dpn0.ps1'"
ECHO Removing configuration files.
CD %dp0
DEL SetupComplete.ps1
CD %windir%\System32\Sysprep
DEL unattend.xml
This will launch a PowerShell script with the same name as the SetupComplete.cmd file, stored in the same location. SetupComplete.ps1.
After SetupComplete.ps1 is finished running it will get deleted. The unattend.xml file also gets deleted.
SetupComplete.ps1 - Located in C:\Windows\Setup\Scripts\
# Credentials used to access network drive.
$Username = "Domain\Username"
$Password = "Password" | ConvertTo-SecureString -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Username, $Password
$RootPath = "$env:HOMEDRIVE\Drivers\"
# Function to determine if 10.10.0.1 is reachable, used to verify
# that NIC drivers are working. Waits up to 30 seconds.
Function Wait-ForConnection {
$wait = $true
$count = 30
Write-Host "Establishing network connection." -NoNewline
while($wait) {
$connection = Test-Connection 10.10.0.1 -ErrorAction SilentlyContinue
if ($connection) {
Write-Host
Write-Host "Connection established!" -ForegroundColor Green
$wait = $false
} else {
Write-Host " ." -NoNewline
$count = ($count -1)
Start-Sleep -Seconds 1
}
if ($count -le 0) {
$wait = $false
Write-Host "Unable to establish a network connection." -ForegroundColor Red
}
}
}
Wait-ForConnection
Write-Host
Write-Host "Mounting network drive."
New-PSDrive -Name "Deploy" -PSProvider FileSystem -Root \\ShareName\Windows10 -Credential $Credential | Out-Null
$Deploy = Test-Path -Path Deploy:\ -ErrorAction SilentlyContinue
if ($Deploy) {
Write-Host "Successfully mounted network drive." -ForegroundColor Green
Write-Host
if (!(Test-Path -Path $RootPath)) {
New-Item -Path $RootPath -ItemType Directory | Out-Null
}
$Controller = "Deploy:\Controller.ps1"
Copy-Item -Path $Controller -Destination "$env:HOMEDRIVE\Drivers\Controller.ps1" -Force
$Controller = "$env:HOMEDRIVE\Drivers\Controller.ps1"
Write-Host "Running script " -NoNewline
Write-Host "Controller.ps1 " -NoNewline -ForegroundColor Yellow
Invoke-Expression -Command $Controller
# Do other stuff, etc...
Write-Host
Write-Host "Unmounting network drive."
Remove-PSDrive -Name "Deploy"
} else {
Write-Host "Failed to mount network drive." -ForegroundColor Red
}
Start-Sleep -Seconds 5
Restart-Computer
First off, this will check to see if you can reach 10.10.0.1 (Change this to something relevant to you).
If you can reach it then your NIC is probably working.
Second, it will mount a network drive using supplied credentials. The account only needs Read access to the share and it’s contents.
Third, it will copy another PowerShell script that I’ve titled Controller from the network share to a local directory. It’ll then run that script.
Last, after Controller.ps1 has finished doing it’s thing we unmount the network drive and restart the computer.
Controller.ps1 - Stored in the root of the network share you mounted in the last step.
Note: This is a shortened version. I removed somethings for the purpose of this guide.
$Model = (Get-WmiObject -Class Win32_ComputerSystem).Model
Write-Host "Model identified as: " -NoNewline -ForegroundColor DarkYellow
Write-Host $Model -ForegroundColor Yellow
Write-Host
$file = ""
switch ($Model) {
"OptiPlex 7040" { $file = "dell7040.ps1"; break; }
"Precision 3510" { $file = "dell3510.ps1"; break; }
"Precision T1700" { $file = "dell1700.ps1"; break; }
"Precision Tower 7810" { $file = "dell7810.ps1"; break; }
"HP Compaq Pro 6300 SFF" { $file = "hp6300.ps1"; break; }
"VirtualBox" { $file = "virtualbox.ps1"; break; }
default {
# There were multiple numbers for these models.
If ($model -like '*6710b*') { $file = "hp6710.ps1"; }
ElseIf ($model -like '*6730b*') { $file = "hp6730.ps1"; }
}
}
$filePath = $RootPath + "Model.ps1"
Copy-Item -Path "Deploy:\ModelScripts\$file" -Destination $filePath -Force
Invoke-Expression -Command $filePath
if ((Get-WmiObject -Class Win32_ComputerSystem).Manufacturer -match "Dell") {
# May do some Dell BIOS settings here.
}
Write-Host
Write-Host "Downloading FOG Client from FOGServer." -ForegroundColor Yellow
$url = "http://<FOGSERVER>/fog/client/download.php?newclient"
$outfile = "$RootPath + FOGService.msi"
(New-Object System.Net.WebClient).DownloadFile($url, $outfile)
Write-Host "Installing FOG Client." -ForegroundColor Cyan
$ArgumentList = "/i $outfile /quiet USETRAY=""0"" WEBADDRESS=""<FOGSERVER>"" WEBROOT=""/fog"" /norestart"
Start-Process -FilePath MSIEXEC.exe -ArgumentList $ArgumentList -Wait
Write-Host "Creating a scheduled task to start the FOGClient after reboot."
$TaskPath = "$env:windir\Setup\StartFOG.ps1 "
Copy-Item -Path "Deploy:\StartFOG.ps1" -Destination $TaskPath
$Action = New-ScheduledTaskAction -Execute PowerShell.exe -Argument "-Command ""& $TaskPath """
$Trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -Action $Action -Trigger $Trigger -TaskName "StartFOG" -User "NT AUTHORITY\SYSTEM" -RunLevel Highest -Force
Write-Host "Deleting downloaded driver files."
Remove-Item -Path $RootPath -Recurse -Force
Here we use a quick WMI query to get the model number of the PC and use a switch to pick the model specific driver installation script. You’ll want to run the query on each machine beforehand to find out exactly how it’s stored.
The beauty of this is that it’s flexible. You can easily add support for new models as long as the NIC drivers are on the image.
hp6300.ps1 - Located in Deploy:\ModelScripts\ - You’ll make similiar script for each model. This is a very simple one.
Write-Host "$Model Driver Installation" -ForegroundColor DarkGreen
$chipset = $RootPath + "chipset.exe"
$audio = $RootPath + "0008-64bit_Win7_Win8_Win81_Win10_R281\Setup.exe"
Write-Host "Downloading Intel Chipset Drivers."
Copy-Item -Path "Deploy:\Drivers\chipset\Intel\SetupChipset.exe" -Destination $chipset -Force
Write-Host "Downloading Realtek HD Audio Drivers."
Copy-Item -Path "Deploy:\Drivers\audio\Realtek\0008-64bit_Win7_Win8_Win81_Win10_R281\" -Destination $RootPath -Recurse -Force
Write-Host
Write-Host "Installing Intel Chipset Support Drivers."
Start-Process -FilePath $chipset -ArgumentList "/s /norestart" -Wait
Write-Host "Installing Realtek HD Audio Driver."
Start-Process -FilePath $audio -ArgumentList "/s" -Wait
Start-Sleep 5
Doesn’t really get much simplier than this one. Most drivers Windows 10 already picked up. The process is basically the same for every driver, as long as they are properly signed.
This should be enough information to get you started, if you want to do it this way. I like doing it this way because it gives me a high level of control over everything. I can specify exactly what version gets installed onto each model. You could even query the serial number of the PC and install device specify software, if you really wanted to get down to that level of detail (FOG snapins would obviously be easier though)