mirror of
https://github.com/rbalsleyMSFT/FFU.git
synced 2026-06-14 02:09:35 -06:00
Improves PE driver copy reliability and logging
Fixes buffer truncation in Get-PrivateProfileSection by dynamically growing the buffer when large INF sections are encountered. Enhances Copy-Drivers with comprehensive error handling, file existence checks, and detailed logging for each operation. Adds support for architecture-specific SourceDisksFiles sections (amd64/arm64) and provides a summary of matched, skipped, and copied files. Fixes key-value parsing to handle values containing equals signs.
This commit is contained in:
+167
-34
@@ -2759,15 +2759,41 @@ function Get-PrivateProfileSection {
|
|||||||
[Parameter()]
|
[Parameter()]
|
||||||
[string]$SectionName
|
[string]$SectionName
|
||||||
)
|
)
|
||||||
$buffer = [byte[]]::new(16384)
|
# Read the requested section from an INF/INI file
|
||||||
[void][Win32.Kernel32]::GetPrivateProfileSection($SectionName, $buffer, $buffer.Length, $FileName)
|
# Some INF sections can be large; grow the buffer to avoid truncated results
|
||||||
$keyValues = [System.Text.Encoding]::Unicode.GetString($buffer).TrimEnd("`0").Split("`0")
|
|
||||||
$hashTable = @{}
|
$hashTable = @{}
|
||||||
|
$bufferSize = 16384
|
||||||
|
$buffer = $null
|
||||||
|
$charsCopied = 0
|
||||||
|
|
||||||
|
while ($true) {
|
||||||
|
$buffer = [byte[]]::new($bufferSize)
|
||||||
|
$charsCopied = [Win32.Kernel32]::GetPrivateProfileSection($SectionName, $buffer, $buffer.Length, $FileName)
|
||||||
|
|
||||||
|
# No section found or no content
|
||||||
|
if ($charsCopied -eq 0) {
|
||||||
|
return $hashTable
|
||||||
|
}
|
||||||
|
|
||||||
|
# If the returned data is close to the buffer size, assume truncation and retry bigger
|
||||||
|
if (($charsCopied -ge ($bufferSize - 2)) -and ($bufferSize -lt 1048576)) {
|
||||||
|
$bufferSize = $bufferSize * 2
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert only the returned portion of the buffer (Unicode = 2 bytes per char)
|
||||||
|
$sectionText = [System.Text.Encoding]::Unicode.GetString($buffer, 0, ($charsCopied * 2))
|
||||||
|
$keyValues = $sectionText.TrimEnd("`0").Split("`0")
|
||||||
|
|
||||||
foreach ($keyValue in $keyValues) {
|
foreach ($keyValue in $keyValues) {
|
||||||
if (![string]::IsNullOrEmpty($keyValue)) {
|
if (![string]::IsNullOrEmpty($keyValue)) {
|
||||||
$parts = $keyValue -split "="
|
$parts = $keyValue -split "=", 2
|
||||||
$hashTable[$parts[0]] = $parts[1]
|
if ($parts.Count -eq 2) {
|
||||||
|
$hashTable[$parts[0]] = $parts[1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2792,7 +2818,32 @@ function Copy-Drivers {
|
|||||||
$filterGUIDs = @("{4D36E97D-E325-11CE-BFC1-08002BE10318}", "{4D36E97B-E325-11CE-BFC1-08002BE10318}", "{4d36e96b-e325-11ce-bfc1-08002be10318}", "{4d36e96f-e325-11ce-bfc1-08002be10318}", "{745a17a0-74d3-11d0-b6fe-00a0c90f57da}")
|
$filterGUIDs = @("{4D36E97D-E325-11CE-BFC1-08002BE10318}", "{4D36E97B-E325-11CE-BFC1-08002BE10318}", "{4d36e96b-e325-11ce-bfc1-08002be10318}", "{4d36e96f-e325-11ce-bfc1-08002be10318}", "{745a17a0-74d3-11d0-b6fe-00a0c90f57da}")
|
||||||
$exclusionList = "wdmaudio.inf|Sound|Machine Learning|Camera|Firmware"
|
$exclusionList = "wdmaudio.inf|Sound|Machine Learning|Camera|Firmware"
|
||||||
$pathLength = $Path.Length
|
$pathLength = $Path.Length
|
||||||
|
|
||||||
|
# Log start and validate paths
|
||||||
|
WriteLog "Copying PE drivers from '$Path' to '$Output' (WindowsArch: $WindowsArch)"
|
||||||
|
if (-not (Test-Path -Path $Path)) {
|
||||||
|
WriteLog "ERROR: Drivers source path not found: $Path"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
[void](New-Item -Path $Output -ItemType Directory -Force)
|
||||||
|
|
||||||
|
# Determine common arch-specific SourceDisksFiles section names
|
||||||
|
# Many INFs use 'amd64' rather than 'x64' for 64-bit paths (e.g. SourceDisksFiles.amd64)
|
||||||
|
$sourceDisksFileSections = @("SourceDisksFiles")
|
||||||
|
if ($WindowsArch -eq 'x64') {
|
||||||
|
$sourceDisksFileSections += "SourceDisksFiles.amd64"
|
||||||
|
}
|
||||||
|
elseif ($WindowsArch -eq 'arm64') {
|
||||||
|
$sourceDisksFileSections += "SourceDisksFiles.arm64"
|
||||||
|
}
|
||||||
|
|
||||||
$infFiles = Get-ChildItem -Path $Path -Recurse -Filter "*.inf"
|
$infFiles = Get-ChildItem -Path $Path -Recurse -Filter "*.inf"
|
||||||
|
WriteLog "Found $($infFiles.Count) INF files under: $Path"
|
||||||
|
|
||||||
|
$matchedInfCount = 0
|
||||||
|
$skippedInfCount = 0
|
||||||
|
$copiedFileCount = 0
|
||||||
|
$errorCount = 0
|
||||||
|
|
||||||
for ($i = 0; $i -lt $infFiles.Count; $i++) {
|
for ($i = 0; $i -lt $infFiles.Count; $i++) {
|
||||||
$infFullName = $infFiles[$i].FullName
|
$infFullName = $infFiles[$i].FullName
|
||||||
@@ -2800,45 +2851,128 @@ function Copy-Drivers {
|
|||||||
$childPath = $infPath.Substring($pathLength)
|
$childPath = $infPath.Substring($pathLength)
|
||||||
$targetPath = Join-Path -Path $Output -ChildPath $childPath
|
$targetPath = Join-Path -Path $Output -ChildPath $childPath
|
||||||
|
|
||||||
if ((Get-PrivateProfileString -FileName $infFullName -SectionName "version" -KeyName "ClassGUID") -in $filterGUIDs) {
|
# Filter to known device classes
|
||||||
#Avoid drivers that reference keywords from the exclusion list to keep the total size small
|
$classGuid = Get-PrivateProfileString -FileName $infFullName -SectionName "version" -KeyName "ClassGUID"
|
||||||
if (((Get-Content -Path $infFullName) -match $exclusionList).Length -eq 0) {
|
if ($classGuid -notin $filterGUIDs) {
|
||||||
$providerName = (Get-PrivateProfileString -FileName $infFullName -SectionName "Version" -KeyName "Provider").Trim("%")
|
$skippedInfCount++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
WriteLog "Copying PE drivers for $providerName"
|
# Avoid drivers that reference keywords from the exclusion list to keep the total size small
|
||||||
WriteLog "Driver inf is: $infFullName"
|
if (((Get-Content -Path $infFullName) -match $exclusionList).Length -ne 0) {
|
||||||
[void](New-Item -Path $targetPath -ItemType Directory -Force)
|
WriteLog "Skipping PE driver INF due to exclusion match: $infFullName"
|
||||||
Copy-Item -Path $infFullName -Destination $targetPath -Force
|
$skippedInfCount++
|
||||||
$CatalogFileName = Get-PrivateProfileString -FileName $infFullName -SectionName "version" -KeyName "Catalogfile"
|
continue
|
||||||
Copy-Item -Path "$infPath\$CatalogFileName" -Destination $targetPath -Force
|
}
|
||||||
|
|
||||||
$sourceDiskFiles = Get-PrivateProfileSection -FileName $infFullName -SectionName "SourceDisksFiles"
|
$matchedInfCount++
|
||||||
foreach ($sourceDiskFile in $sourceDiskFiles.Keys) {
|
|
||||||
if (!$sourceDiskFiles[$sourceDiskFile].Contains(",")) {
|
# Log the INF being processed
|
||||||
Copy-Item -Path "$infPath\$sourceDiskFile" -Destination $targetPath -Force
|
$providerName = (Get-PrivateProfileString -FileName $infFullName -SectionName "Version" -KeyName "Provider").Trim("%")
|
||||||
}
|
if ([string]::IsNullOrWhiteSpace($providerName)) {
|
||||||
else {
|
$providerName = "Unknown Provider"
|
||||||
$subdir = ($sourceDiskFiles[$sourceDiskFile] -split ",")[1]
|
}
|
||||||
[void](New-Item -Path "$targetPath\$subdir" -ItemType Directory -Force)
|
|
||||||
Copy-Item -Path "$infPath\$subdir\$sourceDiskFile" -Destination "$targetPath\$subdir" -Force
|
WriteLog "Processing PE driver INF: $infFullName"
|
||||||
|
WriteLog "Provider: $providerName | ClassGUID: $classGuid"
|
||||||
|
WriteLog "Target folder: $targetPath"
|
||||||
|
|
||||||
|
[void](New-Item -Path $targetPath -ItemType Directory -Force)
|
||||||
|
|
||||||
|
# Copy the INF itself
|
||||||
|
try {
|
||||||
|
Copy-Item -Path $infFullName -Destination $targetPath -Force -ErrorAction Stop
|
||||||
|
$copiedFileCount++
|
||||||
|
WriteLog "Copied: $infFullName -> $targetPath"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$errorCount++
|
||||||
|
WriteLog "ERROR: Failed to copy INF '$infFullName' to '$targetPath': $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy the catalog file (if specified)
|
||||||
|
$CatalogFileName = Get-PrivateProfileString -FileName $infFullName -SectionName "version" -KeyName "Catalogfile"
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($CatalogFileName)) {
|
||||||
|
$catalogSource = Join-Path -Path $infPath -ChildPath $CatalogFileName
|
||||||
|
if (Test-Path -Path $catalogSource) {
|
||||||
|
try {
|
||||||
|
Copy-Item -Path $catalogSource -Destination $targetPath -Force -ErrorAction Stop
|
||||||
|
$copiedFileCount++
|
||||||
|
WriteLog "Copied: $catalogSource -> $targetPath"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
$errorCount++
|
||||||
|
WriteLog "ERROR: Failed to copy catalog '$catalogSource' to '$targetPath': $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$errorCount++
|
||||||
|
WriteLog "ERROR: Catalog file not found: $catalogSource (INF: $infFullName)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WriteLog "WARNING: No CatalogFile entry found in INF: $infFullName"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy all files referenced by SourceDisksFiles sections
|
||||||
|
foreach ($sectionName in $sourceDisksFileSections) {
|
||||||
|
$sourceDiskFiles = Get-PrivateProfileSection -FileName $infFullName -SectionName $sectionName
|
||||||
|
if ($sourceDiskFiles.Count -eq 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteLog "Copying files from INF section [$sectionName] ($($sourceDiskFiles.Count) entries)"
|
||||||
|
|
||||||
|
foreach ($sourceDiskFile in $sourceDiskFiles.Keys) {
|
||||||
|
# Determine if the file lives in a subfolder relative to the INF path
|
||||||
|
$rawValue = $sourceDiskFiles[$sourceDiskFile]
|
||||||
|
$subdir = ""
|
||||||
|
|
||||||
|
if (($null -ne $rawValue) -and ($rawValue.Contains(","))) {
|
||||||
|
$splitParts = $rawValue -split ","
|
||||||
|
if ($splitParts.Count -ge 2) {
|
||||||
|
$subdir = $splitParts[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Arch specific files override the files specified in the universal section
|
if ([string]::IsNullOrWhiteSpace($subdir)) {
|
||||||
$sourceDiskFiles = Get-PrivateProfileSection -FileName $infFullName -SectionName "SourceDisksFiles.$WindowsArch"
|
$subdir = ""
|
||||||
foreach ($sourceDiskFile in $sourceDiskFiles.Keys) {
|
}
|
||||||
if (!$sourceDiskFiles[$sourceDiskFile].Contains(",")) {
|
|
||||||
Copy-Item -Path "$infPath\$sourceDiskFile" -Destination $targetPath -Force
|
# Build source and destination paths
|
||||||
|
if ([string]::IsNullOrEmpty($subdir)) {
|
||||||
|
$sourceFilePath = Join-Path -Path $infPath -ChildPath $sourceDiskFile
|
||||||
|
$destinationFolder = $targetPath
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$sourceFolder = Join-Path -Path $infPath -ChildPath $subdir
|
||||||
|
$sourceFilePath = Join-Path -Path $sourceFolder -ChildPath $sourceDiskFile
|
||||||
|
$destinationFolder = Join-Path -Path $targetPath -ChildPath $subdir
|
||||||
|
[void](New-Item -Path $destinationFolder -ItemType Directory -Force)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy with logging and error handling
|
||||||
|
if (Test-Path -Path $sourceFilePath) {
|
||||||
|
try {
|
||||||
|
Copy-Item -Path $sourceFilePath -Destination $destinationFolder -Force -ErrorAction Stop
|
||||||
|
$copiedFileCount++
|
||||||
|
WriteLog "Copied: $sourceFilePath -> $destinationFolder"
|
||||||
}
|
}
|
||||||
else {
|
catch {
|
||||||
$subdir = ($sourceDiskFiles[$sourceDiskFile] -split ",")[1]
|
$errorCount++
|
||||||
[void](New-Item -Path "$targetPath\$subdir" -ItemType Directory -Force)
|
WriteLog "ERROR: Failed to copy '$sourceFilePath' to '$destinationFolder' (INF: $infFullName): $($_.Exception.Message)"
|
||||||
Copy-Item -Path "$infPath\$subdir\$sourceDiskFile" -Destination "$targetPath\$subdir" -Force
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$errorCount++
|
||||||
|
WriteLog "ERROR: Source file not found for [$sectionName] entry '$sourceDiskFile': $sourceFilePath (INF: $infFullName)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Final summary
|
||||||
|
WriteLog "PE driver copy summary: INF total=$($infFiles.Count) matched=$matchedInfCount skipped=$skippedInfCount filesCopied=$copiedFileCount errors=$errorCount"
|
||||||
}
|
}
|
||||||
|
|
||||||
function New-PEMedia {
|
function New-PEMedia {
|
||||||
@@ -6243,7 +6377,6 @@ try {
|
|||||||
New-FFU $FFUVM.Name
|
New-FFU $FFUVM.Name
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Set-Progress -Percentage 81 -Message "Starting FFU capture from VHDX..."
|
|
||||||
#Shorten Windows SKU for use in FFU file name to remove spaces and long names
|
#Shorten Windows SKU for use in FFU file name to remove spaces and long names
|
||||||
WriteLog "Shortening Windows SKU: $WindowsSKU for FFU file name"
|
WriteLog "Shortening Windows SKU: $WindowsSKU for FFU file name"
|
||||||
$shortenedWindowsSKU = Get-ShortenedWindowsSKU -WindowsSKU $WindowsSKU
|
$shortenedWindowsSKU = Get-ShortenedWindowsSKU -WindowsSKU $WindowsSKU
|
||||||
|
|||||||
Reference in New Issue
Block a user