Last active
March 12, 2024 18:30
-
-
Save cdgco/907ac1358fa35c3dcf1d7b42f152a2f2 to your computer and use it in GitHub Desktop.
MECM Driver Injection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
This script automates the process of installing drivers specific to the computer model and the Windows version. | |
It matches the computer model to a driver folder, checks for the appropriate Windows version, and installs the drivers from the matched folder. | |
.DESCRIPTION | |
The script retrieves the computer model and a specified Windows version. It then searches a given directory for a matching model and Windows version folder. | |
If a direct match is found, it copies the drivers to the system drive under C:\Drivers and initiates the installation. | |
If no direct match is found, it looks for the closest lower version available. If still no match is found, it defaults to the base model directory. | |
The drivers are installed silently without requiring user interaction. | |
.PARAMETERS | |
- BaseDir: The base directory where driver folders are located. It's expected to contain subfolders named after computer models. | |
- ComputerModel: Automatically retrieved model of the current computer. | |
- SpecVer: The specific Windows version to match against driver folders, passed as an argument to the script. | |
- ShowDialogs: A switch parameter to enable or disable the display of popup dialogs. | |
.EXAMPLE | |
.\DriverInjection.ps1 -BaseDir "I:" -SpecVer 11 -ShowDialogs | |
This example searches the "I:\" for a folder matching the current computer's model and Windows version 11, copies the matching drivers to the system drive, and installs them. | |
.NOTES | |
- Author: Carter Roeser | |
- Last Updated: 2024-03-08 | |
- Source: https://cjroeser.com/2024/03/08/injecting-drivers-in-mecm-task-sequences/ | |
- Please ensure PowerShell Execution Policy allows script execution and that all paths and dependencies are correctly configured in your environment. | |
- Designed to be used in an MECM task sequence, where automation of driver installation is crucial. Will fail if the Task Sequence Environment COM object is not available. | |
- Make sure to adjust the script paths and environment variables according to your specific deployment environment. | |
#> | |
param( | |
[string]$BaseDir, | |
[double]$SpecVer = 11, | |
[switch]$ShowDialogs | |
) | |
Write-Host "Beginning Execution of Driver Installation Script" | |
# Retrieve the computer model and set up the task sequence environment | |
try { | |
$TSEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment | |
$TargetSystemDrive = $TSEnv.Value('OSDTargetSystemDrive') | |
$TSEnv.Value('DriversInstalled') = "False" | |
$TSProgressUI = New-Object -ComObject Microsoft.SMS.TSProgressUI | |
$ComputerModel = (Get-CimInstance -ClassName Win32_ComputerSystem).Model | |
Add-Type -AssemblyName PresentationFramework | |
} | |
catch { | |
Write-Error "Task Sequence Environment COM object not available. Ensure the script is running in an MECM task sequence." | |
exit | |
} | |
# Function: Show-PopupDialog | |
# Purpose: Displays a customizable popup dialog to the user. Used for error messages and confirmation prompts. | |
# Parameters: | |
# - message: The text message to display in the popup. | |
# - title: The title of the popup dialog window. | |
# Notes: If the ShowDialogs switch is not set, the function returns early. If the user clicks 'Cancel', the script exits. | |
function Show-PopupDialog { | |
param( | |
[string]$Message, | |
[string]$Title | |
) | |
# If ShowDialogs switch is not set, return early | |
if ($ShowDialogs -eq $false) { | |
Write-Host "Skipping popup dialog" | |
return | |
} | |
# Close the TS progress dialog if it's open | |
if ($TSProgressUI) { | |
Write-Host "Closing TS progress dialog" | |
$TSProgressUI.CloseProgressDialog() | |
} | |
Write-Host "Displaying popup dialog" | |
# Display the popup dialog and capture the user's response | |
$popup = [System.Windows.MessageBox]::Show($Message, $Title, "OKCancel", "Error") | |
Write-Host "Button clicked: $popup" | |
if ($popup -eq 2) { | |
Write-Host "User clicked 'Cancel'. Exiting script." | |
exit | |
} | |
} | |
# Function: Install-Drivers | |
# Purpose: Installs drivers from a specified directory into the system drive. | |
# Notes: Uses Add-WindowsDriver cmdlet to add drivers to the offline Windows image on the target system drive. Sets a task sequence variable upon successful completion. | |
function Install-Drivers { | |
Write-Host "Installing drivers from $TargetSystemDrive\Drivers" | |
# Attempt to install drivers using Add-WindowsDriver cmdlet | |
try { | |
Add-WindowsDriver -Path $TargetSystemDrive -Driver "$TargetSystemDrive\Drivers" -Recurse -ForceUnsigned | |
$TSEnv.Value('DriversInstalled') = "True" | |
} | |
catch { | |
Write-Error "An error occurred during driver installation: $_" | |
} | |
} | |
# Function: Copy-Drivers | |
# Purpose: Copies driver files from the source directory to the target system drive's Drivers directory. | |
# Parameters: | |
# - SourceDir: The directory containing the driver files to be copied. | |
# Notes: Creates the target directory if it does not exist and then copies all files from the source, maintaining directory structure. | |
function Copy-Drivers { | |
param([string]$SourceDir) | |
$DestDir = "$TargetSystemDrive\Drivers" | |
Write-Host "Copying drivers from $SourceDir to $DestDir" | |
try { | |
# Create the target directory if it does not exist | |
if (-not (Test-Path $DestDir)) { | |
Write-Host "Creating Directory: $DestDir" | |
New-Item -ItemType Directory -Force -Path $DestDir | Out-Null | |
} | |
# Copy all files from the source directory to the target directory | |
Get-ChildItem -Path $SourceDir -Recurse -Force | ForEach-Object { | |
# Construct the destination path by replacing the source directory with the target directory | |
$sourcePath = $_.FullName | |
$destPath = $sourcePath.Replace($SourceDir, $DestDir) | |
# Create the destination directory if the source is a directory | |
if ($_.PSIsContainer) { | |
if (-not (Test-Path $destPath)) { | |
Write-Host "Creating Directory: $destPath" | |
New-Item -ItemType Directory -Force -Path $destPath -ErrorAction SilentlyContinue | Out-Null | |
} | |
} | |
# Copy the file to the destination | |
else { | |
Write-Host "Copying driver: $sourcePath to $destPath" | |
Copy-Item -Path $sourcePath -Destination $destPath -Force -ErrorAction SilentlyContinue | Out-Null | |
} | |
} | |
} | |
catch { | |
Write-Error "An error occurred during driver copying: $_" | |
} | |
Write-Output "Drivers successfully copied from $SourceDir to $DestDir" | |
} | |
# Function: Test-DriverStoreConnection | |
# Purpose: Verifies connectivity to the specified driver store directory. | |
# Parameters: | |
# - BaseDir: The base directory of the driver store to check for connectivity. | |
# Notes: Displays a popup dialog if the connection fails, allowing the user to retry or cancel. | |
function Test-DriverStoreConnection { | |
param([string]$BaseDir) | |
$connection = $False | |
# Loop until the connection is established or the user cancels | |
while ($connection -eq $False) { | |
Write-Host "Checking driver store connection: $BaseDir" | |
# If the connection fails, display an error dialog and prompt the user to retry or cancel | |
if ((Test-Path -Path $BaseDir) -eq $False) { | |
Write-Host "Driver store connection failed. Displaying error dialog." | |
Show-PopupDialog -Title "Driver Error" -Message "Error connecting to driver store ($BaseDir)`n`nPlease check the connection and click 'OK' to try again, or click 'Cancel' to skip driver installation." | |
} | |
# If the connection is successful, set the connection flag to True | |
else { | |
Write-Host "Driver store connection successful." | |
$connection = $True | |
} | |
} | |
} | |
# Function: Test-DriverFolder | |
# Purpose: Checks for the existence of a specific driver folder within the base directory. | |
# Parameters: | |
# - BaseDir: The base directory where driver folders are located. | |
# - ComputerModel: The computer model used to construct the driver folder path. | |
# Notes: Displays a popup dialog if the folder does not exist, allowing the user to retry or cancel. | |
function Test-DriverFolder { | |
param([string]$BaseDir, [string]$ComputerModel) | |
$folder = $False | |
$modelDirPath = Join-Path -Path $BaseDir -ChildPath $ComputerModel | |
# Loop until the folder is found or the user cancels | |
while ($folder -eq $False) { | |
Write-Host "Checking for driver folder: $modelDirPath" | |
# If the folder does not exist, display an error dialog and prompt the user to retry or cancel | |
if ((Test-Path -Path $modelDirPath) -eq $False) { | |
Write-Host "Driver folder not found. Displaying error dialog." | |
Show-PopupDialog -Title "Driver Folder Not Found" -Message "Please upload drivers to:`n$modelDirPath`n`nClick 'OK' to check again or 'Cancel' to skip driver installation." | |
} | |
# If the folder exists, set the folder flag to True | |
else { | |
Write-Host "Driver folder found: $modelDirPath" | |
$folder = $True | |
} | |
} | |
} | |
# Function: Find-And-Copy-Drivers | |
# Purpose: Searches for the best match driver folder based on the computer model and Windows version, then copies and installs the drivers. | |
# Parameters: | |
# - BaseDir: The base directory where driver folders are located. | |
# - ComputerModel: The computer model for which drivers are being installed. | |
# - SpecVer: The Windows version to match against driver folders. | |
# Notes: Attempts to find an exact match first. If not found, it searches for the closest lower version available. Displays popup dialogs for user interaction during the process. | |
function Find-And-Copy-Drivers { | |
param( | |
[string]$BaseDir, | |
[string]$ComputerModel, | |
[double]$SpecVer | |
) | |
$driver = $False | |
Write-Host "Searching for drivers in $BaseDir for model $ComputerModel and Windows version $SpecVer" | |
# Check for driver store connection and folder existence | |
if ($ShowDialogs) { | |
Test-DriverStoreConnection -BaseDir $BaseDir | |
Test-DriverFolder -BaseDir $BaseDir -ComputerModel $ComputerModel | |
} | |
# Loop until the driver is found or the user cancels | |
while ($driver -eq $False) { | |
try { | |
$driverPath = Join-Path -Path $BaseDir -ChildPath "$ComputerModel\win$SpecVer" | |
$modelDir = Join-Path -Path $BaseDir -ChildPath $ComputerModel | |
$folders = Get-ChildItem -Path $modelDir -Directory -Force -ErrorAction SilentlyContinue | Where-Object { $_.Name -match '^win(\d+)' } | |
} catch { | |
Write-Error "Unable to read from driver store: $_" | |
exit | |
} | |
Write-Host "Checking for driver folder: $driverPath" | |
# If the driver folder exists, install the drivers and exit the loop | |
if (Test-Path -Path $driverPath) { | |
Write-Host "Found Exact Driver Match: $driverPath" | |
Copy-Drivers -SourceDir $driverPath | |
Install-Drivers | |
exit | |
} | |
$versions = $folders | ForEach-Object { [double]($_.Name -replace '^win', '') } | Sort-Object -Descending | |
$matchedVersion = $versions | Where-Object { $_ -le $SpecVer } | Select-Object -First 1 | |
# If a lower version match is found, copy the drivers and exit the loop | |
if ($matchedVersion) { | |
Write-Host "Found Closest Driver Match: $matchedVersion" | |
$matchedPath = Join-Path -Path $modelDir -ChildPath ("win" + $matchedVersion) | |
Copy-Drivers -SourceDir $matchedPath | |
Install-Drivers | |
exit | |
} | |
# If no match is found, use the base model folder and exit the loop | |
else { | |
Write-Host "No Driver Match Found. Using Base Model Folder." | |
if ($ShowDialogs) { | |
Show-PopupDialog -Title "Driver Folder Not Found" -Message "Please upload drivers to:`n$modelDir`n`nClick 'OK' to check again or 'Cancel' to skip driver installation." | |
} else { | |
exit | |
} | |
} | |
} | |
} | |
Find-And-Copy-Drivers -BaseDir $BaseDir -ComputerModel $ComputerModel -SpecVer $SpecVer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment