cleanup injection

This commit is contained in:
Chris Titus Tech
2026-03-02 13:27:21 -06:00
parent 8db5e6b461
commit 3bc14e9b64
3 changed files with 50 additions and 124 deletions

View File

@@ -223,6 +223,8 @@ function Invoke-WinUtilISOModify {
$runspace.ApartmentState = "STA" $runspace.ApartmentState = "STA"
$runspace.ThreadOptions = "ReuseThread" $runspace.ThreadOptions = "ReuseThread"
$runspace.Open() $runspace.Open()
$injectDrivers = $sync["WPFWin11ISOInjectDrivers"].IsChecked -eq $true
$runspace.SessionStateProxy.SetVariable("sync", $sync) $runspace.SessionStateProxy.SetVariable("sync", $sync)
$runspace.SessionStateProxy.SetVariable("isoPath", $isoPath) $runspace.SessionStateProxy.SetVariable("isoPath", $isoPath)
$runspace.SessionStateProxy.SetVariable("driveLetter", $driveLetter) $runspace.SessionStateProxy.SetVariable("driveLetter", $driveLetter)
@@ -231,6 +233,7 @@ function Invoke-WinUtilISOModify {
$runspace.SessionStateProxy.SetVariable("selectedWimIndex", $selectedWimIndex) $runspace.SessionStateProxy.SetVariable("selectedWimIndex", $selectedWimIndex)
$runspace.SessionStateProxy.SetVariable("selectedEditionName", $selectedEditionName) $runspace.SessionStateProxy.SetVariable("selectedEditionName", $selectedEditionName)
$runspace.SessionStateProxy.SetVariable("autounattendContent", $autounattendContent) $runspace.SessionStateProxy.SetVariable("autounattendContent", $autounattendContent)
$runspace.SessionStateProxy.SetVariable("injectDrivers", $injectDrivers)
# Serialize functions so they are available inside the runspace # Serialize functions so they are available inside the runspace
$isoScriptFuncDef = "function Invoke-WinUtilISOScript {`n" + ` $isoScriptFuncDef = "function Invoke-WinUtilISOScript {`n" + `
@@ -324,7 +327,7 @@ function Invoke-WinUtilISOModify {
# ── Apply all WinUtil modifications via Invoke-WinUtilISOScript ── # ── Apply all WinUtil modifications via Invoke-WinUtilISOScript ──
Log "Applying WinUtil modifications to install.wim..." Log "Applying WinUtil modifications to install.wim..."
Invoke-WinUtilISOScript -ScratchDir $mountDir -ISOContentsDir $isoContents -AutoUnattendXml $autounattendContent -Log { param($m) Log $m } Invoke-WinUtilISOScript -ScratchDir $mountDir -ISOContentsDir $isoContents -AutoUnattendXml $autounattendContent -InjectCurrentSystemDrivers $injectDrivers -Log { param($m) Log $m }
# ── 4b. DISM component store cleanup ── # ── 4b. DISM component store cleanup ──
# /ResetBase removes all superseded component versions from WinSxS, # /ResetBase removes all superseded component versions from WinSxS,

View File

@@ -4,13 +4,12 @@ function Invoke-WinUtilISOScript {
Applies WinUtil modifications to a mounted Windows 11 install.wim image. Applies WinUtil modifications to a mounted Windows 11 install.wim image.
.DESCRIPTION .DESCRIPTION
Removes AppX bloatware and OneDrive, injects hardware drivers (NVMe, Precision Removes AppX bloatware and OneDrive, optionally injects all drivers exported from
Touchpad/HID, and network) exported from the running system, optionally injects the running system into install.wim and boot.wim (controlled by the
extended Storage & Network drivers from the ChrisTitusTech/storage-lan-drivers -InjectCurrentSystemDrivers switch), applies offline registry tweaks (hardware
repository (requires git, installed via winget if absent), applies offline registry bypass, privacy, OOBE, telemetry, update suppression), deletes CEIP/WU
tweaks (hardware bypass, privacy, OOBE, telemetry, update suppression), deletes scheduled-task definition files, and optionally writes autounattend.xml to the ISO
CEIP/WU scheduled-task definition files, and optionally writes autounattend.xml to root and removes the support\ folder from the ISO contents directory.
the ISO root and removes the support\ folder from the ISO contents directory.
All setup scripts embedded in the autounattend.xml <Extensions><File> nodes All setup scripts embedded in the autounattend.xml <Extensions><File> nodes
(Specialize.ps1, DefaultUser.ps1, FirstLogon.ps1, UserOnce.ps1, etc.) are written (Specialize.ps1, DefaultUser.ps1, FirstLogon.ps1, UserOnce.ps1, etc.) are written
@@ -38,6 +37,11 @@ function Invoke-WinUtilISOScript {
in dev mode it is read from tools\autounattend.xml. in dev mode it is read from tools\autounattend.xml.
If empty, the OOBE bypass file is skipped and a warning is logged. If empty, the OOBE bypass file is skipped and a warning is logged.
.PARAMETER InjectCurrentSystemDrivers
Optional. When $true, exports all drivers from the running system and injects
them into install.wim and boot.wim index 2 (Windows Setup PE).
Defaults to $false — no drivers are injected.
.PARAMETER Log .PARAMETER Log
Optional ScriptBlock used for progress/status logging. Optional ScriptBlock used for progress/status logging.
Receives a single [string] message argument. Receives a single [string] message argument.
@@ -62,6 +66,7 @@ function Invoke-WinUtilISOScript {
[Parameter(Mandatory)][string]$ScratchDir, [Parameter(Mandatory)][string]$ScratchDir,
[string]$ISOContentsDir = "", [string]$ISOContentsDir = "",
[string]$AutoUnattendXml = "", [string]$AutoUnattendXml = "",
[bool]$InjectCurrentSystemDrivers = $false,
[scriptblock]$Log = { param($m) Write-Output $m } [scriptblock]$Log = { param($m) Write-Output $m }
) )
@@ -90,32 +95,6 @@ function Invoke-WinUtilISOScript {
} }
} }
# Copies driver package folders (one per exported .inf) whose online class
# matches any of the supplied class names into a new temp staging directory.
# Returns the staging directory path — caller must delete it when done.
# Using a staging dir lets DISM inject all drivers in a single /Recurse
# call instead of one DISM process launch per .inf file.
function New-DriverStagingDir {
param ([string]$ExportRoot, [string[]]$Classes)
$stagingDir = Join-Path $env:TEMP "WinUtil_DriverStage_$(Get-Random)"
New-Item -Path $stagingDir -ItemType Directory -Force | Out-Null
Get-WindowsDriver -Online |
Where-Object { $_.ClassName -in $Classes } |
ForEach-Object { [IO.Path]::GetFileNameWithoutExtension($_.OriginalFileName) } |
Select-Object -Unique |
ForEach-Object {
Get-ChildItem -Path $ExportRoot -Filter "$_.inf" -Recurse -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty DirectoryName -Unique |
ForEach-Object {
# Each exported driver lives in its own sub-folder;
# copy that folder (with its binary files) into staging.
$dest = Join-Path $stagingDir (Split-Path $_ -Leaf)
Copy-Item -Path $_ -Destination $dest -Recurse -Force -ErrorAction SilentlyContinue
}
}
return $stagingDir
}
# Injects all drivers from $DriverDir into a DISM-mounted image in one call. # Injects all drivers from $DriverDir into a DISM-mounted image in one call.
function Add-DriversToImage { function Add-DriversToImage {
param ( param (
@@ -217,35 +196,30 @@ function Invoke-WinUtilISOScript {
} }
# ═════════════════════════════════════════════════════════════════════════ # ═════════════════════════════════════════════════════════════════════════
# 2. Inject hardware drivers (NVMe / Trackpad / Network) # 2. Inject current system drivers (optional)
# Injected into BOTH install.wim (OS) AND boot.wim index 2 (Setup). # Enabled by the "Inject current system drivers" checkbox at the
# Without storage drivers in boot.wim, Windows Setup cannot see the # Mount & Verify step. Exports ALL drivers from the running system
# target disk on systems with unsupported NVMe / SATA controllers. # and injects them into install.wim AND boot.wim index 2 so Windows
# Setup can see the target disk on systems with unsupported NVMe or
# SATA controllers.
# ═════════════════════════════════════════════════════════════════════════ # ═════════════════════════════════════════════════════════════════════════
& $Log "Exporting hardware drivers from running system (NVMe, HID/Trackpad, Network)..." if ($InjectCurrentSystemDrivers) {
& $Log "Exporting all drivers from running system..."
$driverExportRoot = Join-Path $env:TEMP "WinUtil_DriverExport_$(Get-Random)" $driverExportRoot = Join-Path $env:TEMP "WinUtil_DriverExport_$(Get-Random)"
New-Item -Path $driverExportRoot -ItemType Directory -Force | Out-Null New-Item -Path $driverExportRoot -ItemType Directory -Force | Out-Null
try { try {
Export-WindowsDriver -Online -Destination $driverExportRoot | Out-Null Export-WindowsDriver -Online -Destination $driverExportRoot | Out-Null
# Stage matching driver folders then do a single DISM /Recurse call. & $Log "Injecting current system drivers into install.wim..."
# install.wim: SCSIAdapter + HIDClass + Net Add-DriversToImage -MountPath $ScratchDir -DriverDir $driverExportRoot -Label "install" -Logger $Log
$installStage = New-DriverStagingDir -ExportRoot $driverExportRoot -Classes @('SCSIAdapter','HIDClass','Net')
& $Log "Injecting staged drivers into install.wim (single DISM call)..."
Add-DriversToImage -MountPath $ScratchDir -DriverDir $installStage -Label "install" -Logger $Log
Remove-Item -Path $installStage -Recurse -Force -ErrorAction SilentlyContinue
& $Log "install.wim driver injection complete." & $Log "install.wim driver injection complete."
# boot.wim: SCSIAdapter + Net only (HID not needed in WinPE) # Also inject into boot.wim so Windows Setup can see the target disk.
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) { if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
$bootWim = Join-Path $ISOContentsDir "sources\boot.wim" $bootWim = Join-Path $ISOContentsDir "sources\boot.wim"
if (Test-Path $bootWim) { if (Test-Path $bootWim) {
$bootStage = New-DriverStagingDir -ExportRoot $driverExportRoot -Classes @('SCSIAdapter','Net') & $Log "Injecting current system drivers into boot.wim..."
& $Log "Injecting staged drivers into boot.wim (single DISM call)..." Invoke-BootWimInject -BootWimPath $bootWim -DriverDir $driverExportRoot -Logger $Log
Invoke-BootWimInject -BootWimPath $bootWim -DriverDir $bootStage -Logger $Log
Remove-Item -Path $bootStage -Recurse -Force -ErrorAction SilentlyContinue
} else { } else {
& $Log "Warning: boot.wim not found — skipping boot.wim driver injection." & $Log "Warning: boot.wim not found — skipping boot.wim driver injection."
} }
@@ -255,66 +229,8 @@ function Invoke-WinUtilISOScript {
} finally { } finally {
Remove-Item -Path $driverExportRoot -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path $driverExportRoot -Recurse -Force -ErrorAction SilentlyContinue
} }
# ── 2c. Optional: extended Storage & Network drivers from community repo ──
$extDriverChoice = [System.Windows.MessageBox]::Show(
"Would you like to add extended Storage and Network drivers?`n`n" +
"This installs EVERY Storage and Networking device driver " +
"in EXISTANCE into the image. (~1000 drivers)`n`n" +
"No Wireless drivers only Ethernet, use for stubborn systems " +
"with unsupported NVMe or Ethernet controllers.",
"Extended Drivers", "YesNo", "Question")
if ($extDriverChoice -eq 'Yes') {
& $Log "Extended driver injection requested."
# Ensure git is available
$gitCmd = Get-Command git -ErrorAction SilentlyContinue
if (-not $gitCmd) {
& $Log "Git not found — installing via winget..."
winget install --id Git.Git -e --source winget `
--accept-package-agreements --accept-source-agreements | Out-Null
# Refresh PATH so git is visible in this session
$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' +
[System.Environment]::GetEnvironmentVariable('PATH', 'User')
$gitCmd = Get-Command git -ErrorAction SilentlyContinue
}
if (-not $gitCmd) {
& $Log "Warning: git could not be found after install attempt — skipping extended drivers."
} else { } else {
$extRepoDir = Join-Path $env:TEMP "WinUtil_ExtDrivers_$(Get-Random)" & $Log "Driver injection skipped."
try {
& $Log "Cloning storage-lan-drivers repository..."
& git clone --depth 1 `
"https://github.com/ChrisTitusTech/storage-lan-drivers" `
$extRepoDir 2>&1 | ForEach-Object { & $Log " git: $_" }
if (Test-Path $extRepoDir) {
& $Log "Injecting extended drivers into install.wim (this may take several minutes)..."
Add-DriversToImage -MountPath $ScratchDir -DriverDir $extRepoDir -Label "install" -Logger $Log
& $Log "Extended driver injection into install.wim complete."
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
$bootWimExt = Join-Path $ISOContentsDir "sources\boot.wim"
if (Test-Path $bootWimExt) {
& $Log "Injecting extended drivers into boot.wim..."
Invoke-BootWimInject -BootWimPath $bootWimExt -DriverDir $extRepoDir -Logger $Log
} else {
& $Log "Warning: boot.wim not found — skipping extended driver injection into boot.wim."
}
}
} else {
& $Log "Warning: repository clone directory not found — skipping extended drivers."
}
} catch {
& $Log "Error during extended driver injection: $_"
} finally {
Remove-Item -Path $extRepoDir -Recurse -Force -ErrorAction SilentlyContinue
}
}
} else {
& $Log "Extended driver injection skipped."
} }
# ═════════════════════════════════════════════════════════════════════════ # ═════════════════════════════════════════════════════════════════════════

View File

@@ -1494,6 +1494,13 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
Width="Auto" Padding="12,0" Width="Auto" Padding="12,0"
Height="{DynamicResource ButtonHeight}"/> Height="{DynamicResource ButtonHeight}"/>
<CheckBox Name="WPFWin11ISOInjectDrivers"
Content="Inject current system drivers"
FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}"
IsChecked="False"
Margin="0,8,0,0"
ToolTip="Exports all drivers from this machine and injects them into install.wim and boot.wim. Recommended for systems with unsupported NVMe or network controllers."/>
</StackPanel> </StackPanel>
<!-- Verification results panel --> <!-- Verification results panel -->