mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 10:19:36 -06:00
0b0046986e
Adds a new `Test-ExistingDriver` function to the common driver module to centralize the logic for checking if drivers have already been downloaded, either as a folder or a WIM file. This change removes duplicated code from the Dell, HP, Lenovo, and Microsoft driver download tasks, simplifying maintenance and ensuring consistent behavior across all manufacturers.
253 lines
11 KiB
PowerShell
253 lines
11 KiB
PowerShell
# FFU Common Drivers Module
|
|
# Contains shared functions related to driver handling.
|
|
|
|
# --------------------------------------------------------------------------
|
|
# SECTION: Driver Compression Function
|
|
# --------------------------------------------------------------------------
|
|
|
|
function Compress-DriverFolderToWim {
|
|
[CmdletBinding(SupportsShouldProcess)]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateScript({ Test-Path -Path $_ -PathType Container })]
|
|
[string]$SourceFolderPath,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$DestinationWimPath,
|
|
|
|
[Parameter()]
|
|
[string]$WimName, # Optional, defaults to folder name
|
|
|
|
[Parameter()]
|
|
[string]$WimDescription # Optional, defaults to folder name
|
|
)
|
|
|
|
WriteLog "Starting compression of folder '$SourceFolderPath' to '$DestinationWimPath'."
|
|
|
|
# Default WIM Name and Description to the source folder name if not provided
|
|
$sourceFolderName = Split-Path -Path $SourceFolderPath -Leaf
|
|
if ([string]::IsNullOrWhiteSpace($WimName)) {
|
|
$WimName = $sourceFolderName
|
|
WriteLog "WIM Name not provided, defaulting to source folder name: '$WimName'."
|
|
}
|
|
if ([string]::IsNullOrWhiteSpace($WimDescription)) {
|
|
$WimDescription = $sourceFolderName
|
|
WriteLog "WIM Description not provided, defaulting to source folder name: '$WimDescription'."
|
|
}
|
|
|
|
# Ensure destination directory exists
|
|
$destinationDir = Split-Path -Path $DestinationWimPath -Parent
|
|
if (-not (Test-Path -Path $destinationDir -PathType Container)) {
|
|
WriteLog "Creating destination directory: $destinationDir"
|
|
try {
|
|
New-Item -Path $destinationDir -ItemType Directory -Force -ErrorAction Stop | Out-Null
|
|
}
|
|
catch {
|
|
WriteLog "Failed to create destination directory '$destinationDir': $($_.Exception.Message)"
|
|
return $false # Indicate failure
|
|
}
|
|
}
|
|
|
|
if ($PSCmdlet.ShouldProcess("Folder '$SourceFolderPath'", "Compress to WIM '$DestinationWimPath'")) {
|
|
try {
|
|
# Construct arguments for dism.exe
|
|
$dismArgs = "/Capture-Image /ImageFile:`"$DestinationWimPath`" /CaptureDir:`"$SourceFolderPath`" /Name:`"$WimName`" /Description:`"$WimDescription`" /Compress:Max /CheckIntegrity /Quiet"
|
|
|
|
WriteLog "Executing dism.exe via Invoke-Process with arguments:"
|
|
WriteLog "dism.exe $dismArgs"
|
|
|
|
# Call Invoke-Process (assumed to be available from FFUUI.Core.psm1 or another imported module)
|
|
# Invoke-Process is expected to throw an exception for non-zero exit codes.
|
|
Invoke-Process -FilePath "dism.exe" -ArgumentList $dismArgs -Wait $true
|
|
|
|
WriteLog "Successfully compressed '$SourceFolderPath' to '$DestinationWimPath' using dism.exe."
|
|
|
|
# Remove the source folder after successful compression
|
|
WriteLog "Removing source driver folder: $SourceFolderPath"
|
|
try {
|
|
Remove-Item -Path $SourceFolderPath -Recurse -Force -ErrorAction Stop
|
|
WriteLog "Successfully removed source folder '$SourceFolderPath'."
|
|
}
|
|
catch {
|
|
WriteLog "Warning: Failed to remove source folder '$SourceFolderPath'. Error: $($_.Exception.Message)"
|
|
# Do not fail the whole operation, just log a warning.
|
|
}
|
|
|
|
return $true # Indicate success
|
|
}
|
|
catch {
|
|
WriteLog "Failed to compress folder '$SourceFolderPath' to WIM '$DestinationWimPath' using dism.exe."
|
|
WriteLog "Error details: $($_.Exception.Message)"
|
|
# Check if the error message contains details about the DISM log (dism.exe output might be in the exception)
|
|
if ($_.Exception.Message -match 'DISM log file can be found at (.*)') {
|
|
$dismLogPath = $matches[1].Trim()
|
|
WriteLog "Check the DISM log for more details: $dismLogPath"
|
|
}
|
|
return $false # Indicate failure
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "Compression operation skipped due to -WhatIf."
|
|
return $false # Indicate skipped operation
|
|
}
|
|
}
|
|
|
|
# --------------------------------------------------------------------------
|
|
# SECTION: Driver Mapping Function
|
|
# --------------------------------------------------------------------------
|
|
|
|
function Update-DriverMappingJson {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[array]$DownloadedDrivers, # Array of PSCustomObjects with Make, Model, DriverPath
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$DriversFolder # Base drivers folder (e.g., C:\FFUDevelopment\Drivers)
|
|
)
|
|
|
|
$mappingFilePath = Join-Path -Path $DriversFolder -ChildPath "DriverMapping.json"
|
|
WriteLog "Updating driver mapping file at: $mappingFilePath"
|
|
|
|
# Load existing mapping file or create a new list
|
|
$mappingList = [System.Collections.Generic.List[PSCustomObject]]::new()
|
|
if (Test-Path -Path $mappingFilePath -PathType Leaf) {
|
|
try {
|
|
$existingJson = Get-Content -Path $mappingFilePath -Raw | ConvertFrom-Json
|
|
# Ensure it's a collection before adding to the list
|
|
if ($existingJson -is [array]) {
|
|
# Iterate through the array to avoid type conversion issues with AddRange
|
|
foreach ($item in $existingJson) {
|
|
$mappingList.Add($item)
|
|
}
|
|
}
|
|
else {
|
|
$mappingList.Add($existingJson)
|
|
}
|
|
WriteLog "Loaded $($mappingList.Count) existing entries from $mappingFilePath"
|
|
}
|
|
catch {
|
|
WriteLog "Warning: Could not read or parse existing DriverMapping.json. A new file will be created. Error: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
$updatedCount = 0
|
|
$addedCount = 0
|
|
|
|
foreach ($driver in $DownloadedDrivers) {
|
|
# Skip if any required property is missing or null
|
|
if (-not $driver.PSObject.Properties['Make'] -or -not $driver.PSObject.Properties['Model'] -or -not $driver.PSObject.Properties['DriverPath'] -or [string]::IsNullOrWhiteSpace($driver.DriverPath)) {
|
|
WriteLog "Skipping driver entry due to missing or empty Make, Model, or DriverPath. Details: $(($driver | ConvertTo-Json -Compress -Depth 3))"
|
|
continue
|
|
}
|
|
|
|
# Find existing entry
|
|
$existingEntry = $mappingList | Where-Object { $_.Manufacturer -eq $driver.Make -and $_.Model -eq $driver.Model } | Select-Object -First 1
|
|
|
|
if ($null -ne $existingEntry) {
|
|
# Update existing entry if the path is different
|
|
if ($existingEntry.DriverPath -ne $driver.DriverPath) {
|
|
WriteLog "Updating driver path for '$($driver.Make) - $($driver.Model)' from '$($existingEntry.DriverPath)' to '$($driver.DriverPath)'."
|
|
$existingEntry.DriverPath = $driver.DriverPath
|
|
$updatedCount++
|
|
}
|
|
}
|
|
else {
|
|
# Add new entry
|
|
$newEntry = [PSCustomObject]@{
|
|
Manufacturer = $driver.Make
|
|
Model = $driver.Model
|
|
DriverPath = $driver.DriverPath
|
|
}
|
|
$mappingList.Add($newEntry)
|
|
WriteLog "Adding new mapping for '$($driver.Make) - $($driver.Model)' with path '$($driver.DriverPath)'."
|
|
$addedCount++
|
|
}
|
|
}
|
|
|
|
if ($updatedCount -gt 0 -or $addedCount -gt 0) {
|
|
try {
|
|
# Sort the list for consistency before saving
|
|
$sortedList = $mappingList | Sort-Object -Property Manufacturer, Model
|
|
$sortedList | ConvertTo-Json -Depth 5 | Set-Content -Path $mappingFilePath -Encoding UTF8
|
|
WriteLog "Successfully saved DriverMapping.json with $addedCount new entries and $updatedCount updated entries."
|
|
}
|
|
catch {
|
|
WriteLog "Error saving updated DriverMapping.json: $($_.Exception.Message)"
|
|
throw "Failed to save driver mapping file."
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "No changes needed for DriverMapping.json."
|
|
}
|
|
}
|
|
|
|
# --------------------------------------------------------------------------
|
|
# SECTION: Driver Existence Check Function
|
|
# --------------------------------------------------------------------------
|
|
function Test-ExistingDriver {
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Make,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Model,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$DriversFolder,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Identifier,
|
|
|
|
[Parameter()]
|
|
[System.Collections.Concurrent.ConcurrentQueue[hashtable]]$ProgressQueue = $null
|
|
)
|
|
|
|
$makeDriversPath = Join-Path -Path $DriversFolder -ChildPath $Make
|
|
$modelPath = Join-Path -Path $makeDriversPath -ChildPath $Model
|
|
$driverRelativePath = Join-Path -Path $Make -ChildPath $Model
|
|
|
|
# Check for WIM file first
|
|
$wimFilePath = Join-Path -Path $makeDriversPath -ChildPath "$($Model).wim"
|
|
if (Test-Path -Path $wimFilePath -PathType Leaf) {
|
|
$status = "Already downloaded (WIM)"
|
|
WriteLog "Driver WIM for '$Identifier' already exists at '$wimFilePath'."
|
|
if ($null -ne $ProgressQueue) { Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $Identifier -Status $status }
|
|
$wimRelativePath = Join-Path -Path $Make -ChildPath "$($Model).wim"
|
|
return [PSCustomObject]@{
|
|
Model = $Identifier # Return original identifier
|
|
Status = $status
|
|
Success = $true
|
|
DriverPath = $wimRelativePath
|
|
}
|
|
}
|
|
|
|
# Check for existing driver folder
|
|
if (Test-Path -Path $modelPath -PathType Container) {
|
|
$folderSize = (Get-ChildItem -Path $modelPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
|
|
if ($folderSize -gt 1MB) {
|
|
$status = "Already downloaded"
|
|
WriteLog "Drivers for '$Identifier' already exist in '$modelPath'."
|
|
if ($null -ne $ProgressQueue) { Invoke-ProgressUpdate -ProgressQueue $ProgressQueue -Identifier $Identifier -Status $status }
|
|
return [PSCustomObject]@{
|
|
Model = $Identifier # Return original identifier
|
|
Status = $status
|
|
Success = $true
|
|
DriverPath = $driverRelativePath
|
|
}
|
|
}
|
|
else {
|
|
WriteLog "Driver folder '$modelPath' for '$Identifier' exists but is empty or very small. Re-downloading."
|
|
}
|
|
}
|
|
|
|
# If neither WIM nor a valid folder exists, return null
|
|
return $null
|
|
}
|
|
|
|
# --------------------------------------------------------------------------
|
|
# SECTION: Module Export
|
|
# --------------------------------------------------------------------------
|
|
|
|
Export-ModuleMember -Function Compress-DriverFolderToWim, Update-DriverMappingJson, Test-ExistingDriver |