iso save success

This commit is contained in:
Chris Titus Tech
2026-02-23 10:51:59 -06:00
parent 751b7ef79c
commit df75cd8c6f
4 changed files with 321 additions and 110 deletions

View File

@@ -98,10 +98,10 @@ function Invoke-WinUtilISOMountAndVerify {
# ── Read edition / architecture info ── # ── Read edition / architecture info ──
Set-WinUtilProgressBar -Label "Reading image metadata..." -Percent 55 Set-WinUtilProgressBar -Label "Reading image metadata..." -Percent 55
$editions = Get-WindowsImage -ImagePath $activeWim | Select-Object -ExpandProperty ImageName $imageInfo = Get-WindowsImage -ImagePath $activeWim | Select-Object ImageIndex, ImageName
# ── Verify at least one Win11 edition is present ── # ── Verify at least one Win11 edition is present ──
$isWin11 = $editions | Where-Object { $_ -match "Windows 11" } $isWin11 = $imageInfo | Where-Object { $_.ImageName -match "Windows 11" }
if (-not $isWin11) { if (-not $isWin11) {
Dismount-DiskImage -ImagePath $isoPath | Out-Null Dismount-DiskImage -ImagePath $isoPath | Out-Null
Write-Win11ISOLog "ERROR: No 'Windows 11' edition found in the image." Write-Win11ISOLog "ERROR: No 'Windows 11' edition found in the image."
@@ -112,9 +112,20 @@ function Invoke-WinUtilISOMountAndVerify {
return return
} }
# Store edition info for later index lookup
$sync["Win11ISOImageInfo"] = $imageInfo
# ── Populate UI ── # ── Populate UI ──
$sync["WPFWin11ISOMountDriveLetter"].Text = "Mounted at: $driveLetter | Image file: $(Split-Path $activeWim -Leaf)" $sync["WPFWin11ISOMountDriveLetter"].Text = "Mounted at: $driveLetter | Image file: $(Split-Path $activeWim -Leaf)"
$sync["WPFWin11ISOEditionList"].Text = ($editions -join "`n") $sync["WPFWin11ISOEditionComboBox"].Dispatcher.Invoke([action]{
$sync["WPFWin11ISOEditionComboBox"].Items.Clear()
foreach ($img in $imageInfo) {
[void]$sync["WPFWin11ISOEditionComboBox"].Items.Add("$($img.ImageIndex): $($img.ImageName)")
}
if ($sync["WPFWin11ISOEditionComboBox"].Items.Count -gt 0) {
$sync["WPFWin11ISOEditionComboBox"].SelectedIndex = 0
}
})
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Visible" $sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Visible"
# Store for later steps # Store for later steps
@@ -126,7 +137,7 @@ function Invoke-WinUtilISOMountAndVerify {
$sync["WPFWin11ISOModifySection"].Visibility = "Visible" $sync["WPFWin11ISOModifySection"].Visibility = "Visible"
Set-WinUtilProgressBar -Label "ISO verified ✔" -Percent 100 Set-WinUtilProgressBar -Label "ISO verified ✔" -Percent 100
Write-Win11ISOLog "ISO verified OK. Editions found: $($editions.Count)" Write-Win11ISOLog "ISO verified OK. Editions found: $($imageInfo.Count)"
} }
catch { catch {
Write-Win11ISOLog "ERROR during mount/verify: $_" Write-Win11ISOLog "ERROR during mount/verify: $_"
@@ -162,10 +173,41 @@ function Invoke-WinUtilISOModify {
return return
} }
# ── Resolve selected edition index from the ComboBox ──
$selectedItem = $sync["WPFWin11ISOEditionComboBox"].SelectedItem
$selectedWimIndex = 1 # default fallback
if ($selectedItem -and $selectedItem -match '^(\d+):') {
$selectedWimIndex = [int]$Matches[1]
} elseif ($sync["Win11ISOImageInfo"]) {
$selectedWimIndex = $sync["Win11ISOImageInfo"][0].ImageIndex
}
$selectedEditionName = if ($selectedItem) { ($selectedItem -replace '^\d+:\s*', '') } else { "Unknown" }
Write-Win11ISOLog "Selected edition: $selectedEditionName (Index $selectedWimIndex)"
# Disable the modify button to prevent double-click # Disable the modify button to prevent double-click
$sync["WPFWin11ISOModifyButton"].IsEnabled = $false $sync["WPFWin11ISOModifyButton"].IsEnabled = $false
$workDir = Join-Path $env:TEMP "WinUtil_Win11ISO_$(Get-Date -Format 'yyyyMMdd_HHmmss')" $existingWorkDir = Get-Item -Path (Join-Path $env:TEMP "WinUtil_Win11ISO*") -ErrorAction SilentlyContinue |
Where-Object { $_.PSIsContainer } |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
$workDir = if ($existingWorkDir) {
Write-Win11ISOLog "Reusing existing temp directory: $($existingWorkDir.FullName)"
$existingWorkDir.FullName
} else {
Join-Path $env:TEMP "WinUtil_Win11ISO_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
}
# ── Resolve autounattend.xml content ──────────────────────────────────────
# Compiled winutil.ps1 sets $WinUtilAutounattendXml before main.ps1 runs.
# In dev/source mode fall back to reading tools\autounattend.xml directly.
$autounattendContent = if ($WinUtilAutounattendXml) {
$WinUtilAutounattendXml
} else {
$toolsXml = Join-Path $PSScriptRoot "..\..\tools\autounattend.xml"
if (Test-Path $toolsXml) { Get-Content $toolsXml -Raw } else { "" }
}
# ── Run modification in a background runspace ── # ── Run modification in a background runspace ──
$runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace() $runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
@@ -177,6 +219,9 @@ function Invoke-WinUtilISOModify {
$runspace.SessionStateProxy.SetVariable("driveLetter", $driveLetter) $runspace.SessionStateProxy.SetVariable("driveLetter", $driveLetter)
$runspace.SessionStateProxy.SetVariable("wimPath", $wimPath) $runspace.SessionStateProxy.SetVariable("wimPath", $wimPath)
$runspace.SessionStateProxy.SetVariable("workDir", $workDir) $runspace.SessionStateProxy.SetVariable("workDir", $workDir)
$runspace.SessionStateProxy.SetVariable("selectedWimIndex", $selectedWimIndex)
$runspace.SessionStateProxy.SetVariable("selectedEditionName", $selectedEditionName)
$runspace.SessionStateProxy.SetVariable("autounattendContent", $autounattendContent)
# 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" + `
@@ -217,6 +262,15 @@ function Invoke-WinUtilISOModify {
} }
try { try {
# ── Hide Steps 1-3 while modification is running; expand log to fill screen ──
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
$sync["WPFWin11ISOSelectSection"].Visibility = "Collapsed"
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
$expandedHeight = [Math]::Max(400, $sync.Window.ActualHeight - 100)
$sync["WPFWin11ISOStatusLog"].Height = $expandedHeight
})
# ── 1. Create working directory structure ── # ── 1. Create working directory structure ──
Log "Creating working directory: $workDir" Log "Creating working directory: $workDir"
$isoContents = Join-Path $workDir "iso_contents" $isoContents = Join-Path $workDir "iso_contents"
@@ -240,14 +294,14 @@ function Invoke-WinUtilISOModify {
# Ensure the file is writable # Ensure the file is writable
Set-ItemProperty -Path $localWim -Name IsReadOnly -Value $false Set-ItemProperty -Path $localWim -Name IsReadOnly -Value $false
# ── 4. Mount the first index of install.wim ── # ── 4. Mount the selected edition of install.wim ──
Log "Mounting install.wim (Index 1) at $mountDir..." Log "Mounting install.wim (Index ${selectedWimIndex}: $selectedEditionName) at $mountDir..."
Mount-WindowsImage -ImagePath $localWim -Index 1 -Path $mountDir -ErrorAction Stop | Out-Null Mount-WindowsImage -ImagePath $localWim -Index $selectedWimIndex -Path $mountDir -ErrorAction Stop | Out-Null
SetProgress "Modifying install.wim..." 45 SetProgress "Modifying install.wim..." 45
# ── 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 -Log { param($m) Log $m } Invoke-WinUtilISOScript -ScratchDir $mountDir -ISOContentsDir $isoContents -AutoUnattendXml $autounattendContent -Log { param($m) Log $m }
# ── 5. Save and dismount the WIM ── # ── 5. Save and dismount the WIM ──
SetProgress "Saving modified install.wim..." 65 SetProgress "Saving modified install.wim..." 65
@@ -265,16 +319,54 @@ function Invoke-WinUtilISOModify {
$sync["Win11ISOContentsDir"] = $isoContents $sync["Win11ISOContentsDir"] = $isoContents
SetProgress "Modification complete ✔" 100 SetProgress "Modification complete ✔" 100
Log "install.wim modification complete. Select an output option in Step 4." Log "install.wim modification complete. Choose an output option in Step 4."
# ── Reveal Step 4 on the UI thread ── # ── Reveal Step 4 on the UI thread ──
# Note: USB drive enumeration (Get-Disk) is intentionally deferred to
# when the user explicitly selects the USB option, to avoid blocking
# the UI thread here.
$sync["WPFWin11ISOOutputSection"].Dispatcher.Invoke([action]{ $sync["WPFWin11ISOOutputSection"].Dispatcher.Invoke([action]{
$sync["WPFWin11ISOOutputSection"].Visibility = "Visible" $sync["WPFWin11ISOOutputSection"].Visibility = "Visible"
Invoke-WinUtilISORefreshUSBDrives
}) })
} }
catch { catch {
Log "ERROR during modification: $_" Log "ERROR during modification: $_"
# ── Cleanup: dismount WIM if still mounted ──
try {
if (Test-Path $mountDir) {
$mountedImages = Get-WindowsImage -Mounted -ErrorAction SilentlyContinue |
Where-Object { $_.Path -eq $mountDir }
if ($mountedImages) {
Log "Cleaning up: dismounting install.wim (discarding changes)..."
Dismount-WindowsImage -Path $mountDir -Discard -ErrorAction SilentlyContinue | Out-Null
}
}
} catch {
Log "Warning: could not dismount install.wim during cleanup: $_"
}
# ── Cleanup: dismount the source ISO ──
try {
$mountedISO = Get-DiskImage -ImagePath $isoPath -ErrorAction SilentlyContinue
if ($mountedISO -and $mountedISO.Attached) {
Log "Cleaning up: dismounting source ISO..."
Dismount-DiskImage -ImagePath $isoPath -ErrorAction SilentlyContinue | Out-Null
}
} catch {
Log "Warning: could not dismount ISO during cleanup: $_"
}
# ── Cleanup: remove temp working directory ──
try {
if (Test-Path $workDir) {
Log "Cleaning up: removing temp directory $workDir..."
Remove-Item -Path $workDir -Recurse -Force -ErrorAction SilentlyContinue
}
} catch {
Log "Warning: could not remove temp directory during cleanup: $_"
}
$sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{ $sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{
[System.Windows.MessageBox]::Show( [System.Windows.MessageBox]::Show(
"An error occurred during install.wim modification:`n`n$_", "An error occurred during install.wim modification:`n`n$_",
@@ -288,6 +380,15 @@ function Invoke-WinUtilISOModify {
$sync.progressBarTextBlock.ToolTip = "" $sync.progressBarTextBlock.ToolTip = ""
$sync.ProgressBar.Value = 0 $sync.ProgressBar.Value = 0
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true $sync["WPFWin11ISOModifyButton"].IsEnabled = $true
# ── Only restore steps 1-3 if Step 4 was NOT successfully shown ──
# When modification succeeds, Step 4 is visible and steps 1-3 stay
# hidden until the user clicks Clean & Reset.
if ($sync["WPFWin11ISOOutputSection"].Visibility -ne "Visible") {
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
$sync["WPFWin11ISOMountSection"].Visibility = "Visible"
$sync["WPFWin11ISOModifySection"].Visibility = "Visible"
}
$sync["WPFWin11ISOStatusLog"].Height = 140
}) })
} }
}) | Out-Null }) | Out-Null
@@ -295,6 +396,53 @@ function Invoke-WinUtilISOModify {
$script.BeginInvoke() | Out-Null $script.BeginInvoke() | Out-Null
} }
function Invoke-WinUtilISOCleanAndReset {
<#
.SYNOPSIS
Deletes the temporary working directory created during ISO modification
and resets the entire ISO UI back to its initial state (Step 1 only).
#>
$workDir = $sync["Win11ISOWorkDir"]
if ($workDir -and (Test-Path $workDir)) {
$confirm = [System.Windows.MessageBox]::Show(
"This will delete the temporary working directory:`n`n$workDir`n`nAnd reset the interface back to the start.`n`nContinue?",
"Clean & Reset", "YesNo", "Warning")
if ($confirm -ne "Yes") { return }
try {
Write-Win11ISOLog "Deleting temp directory: $workDir"
Remove-Item -Path $workDir -Recurse -Force -ErrorAction Stop
Write-Win11ISOLog "Temp directory deleted."
} catch {
Write-Win11ISOLog "WARNING: could not fully delete temp directory: $_"
}
}
# Clear all stored ISO state
$sync["Win11ISOWorkDir"] = $null
$sync["Win11ISOContentsDir"] = $null
$sync["Win11ISOImagePath"] = $null
$sync["Win11ISODriveLetter"] = $null
$sync["Win11ISOWimPath"] = $null
$sync["Win11ISOImageInfo"] = $null
$sync["Win11ISOUSBDisks"] = $null
# Reset the UI to the initial state
$sync["WPFWin11ISOPath"].Text = "No ISO selected..."
$sync["WPFWin11ISOFileInfo"].Visibility = "Collapsed"
$sync["WPFWin11ISOVerifyResultPanel"].Visibility = "Collapsed"
$sync["WPFWin11ISOOptionUSB"].Visibility = "Collapsed"
$sync["WPFWin11ISOOutputSection"].Visibility = "Collapsed"
$sync["WPFWin11ISOModifySection"].Visibility = "Collapsed"
$sync["WPFWin11ISOMountSection"].Visibility = "Collapsed"
$sync["WPFWin11ISOSelectSection"].Visibility = "Visible"
$sync["WPFWin11ISOStatusLog"].Text = "Ready. Please select a Windows 11 ISO to begin."
$sync["WPFWin11ISOStatusLog"].Height = 140
$sync["WPFWin11ISOModifyButton"].IsEnabled = $true
}
function Invoke-WinUtilISOExport { function Invoke-WinUtilISOExport {
<# <#
.SYNOPSIS .SYNOPSIS
@@ -329,14 +477,30 @@ function Invoke-WinUtilISOExport {
$oscdimg = Get-ChildItem "C:\Program Files (x86)\Windows Kits" -Recurse -Filter "oscdimg.exe" -ErrorAction SilentlyContinue | $oscdimg = Get-ChildItem "C:\Program Files (x86)\Windows Kits" -Recurse -Filter "oscdimg.exe" -ErrorAction SilentlyContinue |
Select-Object -First 1 -ExpandProperty FullName Select-Object -First 1 -ExpandProperty FullName
if (-not $oscdimg) {
Write-Win11ISOLog "oscdimg.exe not found. Attempting to install via winget..."
Set-WinUtilProgressBar -Label "Installing oscdimg..." -Percent 5
try {
$winget = Get-Command winget -ErrorAction Stop
$result = & $winget install -e --id Microsoft.OSCDIMG --accept-package-agreements --accept-source-agreements 2>&1
Write-Win11ISOLog "winget output: $result"
# Re-scan for oscdimg after install
$oscdimg = Get-ChildItem "C:\Program Files (x86)\Windows Kits" -Recurse -Filter "oscdimg.exe" -ErrorAction SilentlyContinue |
Select-Object -First 1 -ExpandProperty FullName
} catch {
Write-Win11ISOLog "winget not available or install failed: $_"
}
if (-not $oscdimg) { if (-not $oscdimg) {
Set-WinUtilProgressBar -Label "" -Percent 0 Set-WinUtilProgressBar -Label "" -Percent 0
Write-Win11ISOLog "oscdimg.exe not found. Install Windows ADK to enable ISO export." Write-Win11ISOLog "oscdimg.exe still not found after install attempt."
[System.Windows.MessageBox]::Show( [System.Windows.MessageBox]::Show(
"oscdimg.exe was not found.`n`nTo export an ISO you need the Windows Assessment and Deployment Kit (ADK).`n`nDownload it from: https://learn.microsoft.com/windows-hardware/get-started/adk-install", "oscdimg.exe could not be found or installed automatically.`n`nPlease install it manually:`n winget install -e --id Microsoft.OSCDIMG`n`nOr install the Windows ADK from:`nhttps://learn.microsoft.com/windows-hardware/get-started/adk-install",
"Windows ADK Required", "OK", "Warning") "oscdimg Not Found", "OK", "Warning")
return return
} }
Write-Win11ISOLog "oscdimg.exe installed successfully."
}
# Build boot parameters (BIOS + UEFI dual-boot) # Build boot parameters (BIOS + UEFI dual-boot)
$bootData = "2#p0,e,b`"$contentsDir\boot\etfsboot.com`"#pEF,e,b`"$contentsDir\efi\microsoft\boot\efisys.bin`"" $bootData = "2#p0,e,b`"$contentsDir\boot\etfsboot.com`"#pEF,e,b`"$contentsDir\efi\microsoft\boot\efisys.bin`""

View File

@@ -32,6 +32,12 @@ function Invoke-WinUtilISOScript {
#> #>
param ( param (
[Parameter(Mandatory)][string]$ScratchDir, [Parameter(Mandatory)][string]$ScratchDir,
# Root directory of the extracted ISO contents. When supplied, autounattend.xml
# is written here so Windows Setup picks it up automatically at boot.
[string]$ISOContentsDir = "",
# Autounattend XML content. In compiled winutil.ps1 this comes from the embedded
# $WinUtilAutounattendXml here-string; in dev mode it is read from tools\autounattend.xml.
[string]$AutoUnattendXml = "",
[scriptblock]$Log = { param($m) Write-Output $m } [scriptblock]$Log = { param($m) Write-Output $m }
) )
@@ -131,11 +137,6 @@ function Invoke-WinUtilISOScript {
# ═════════════════════════════════════════════════════════════════════════ # ═════════════════════════════════════════════════════════════════════════
& $Log "Removing Edge..." & $Log "Removing Edge..."
Remove-Item -Path "$ScratchDir\Program Files (x86)\Microsoft\Edge" -Recurse -Force -ErrorAction SilentlyContinue Remove-Item -Path "$ScratchDir\Program Files (x86)\Microsoft\Edge" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "$ScratchDir\Program Files (x86)\Microsoft\EdgeUpdate" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -Path "$ScratchDir\Program Files (x86)\Microsoft\EdgeCore" -Recurse -Force -ErrorAction SilentlyContinue
& takeown /f "$ScratchDir\Windows\System32\Microsoft-Edge-Webview" /r | Out-Null
& icacls "$ScratchDir\Windows\System32\Microsoft-Edge-Webview" /grant "$($adminGroup.Value):(F)" /T /C | Out-Null
Remove-Item -Path "$ScratchDir\Windows\System32\Microsoft-Edge-Webview" -Recurse -Force -ErrorAction SilentlyContinue
# ═════════════════════════════════════════════════════════════════════════ # ═════════════════════════════════════════════════════════════════════════
# 3. Remove OneDrive # 3. Remove OneDrive
@@ -195,10 +196,24 @@ function Invoke-WinUtilISOScript {
& $Log "Enabling local accounts on OOBE..." & $Log "Enabling local accounts on OOBE..."
_ISOScript-SetReg 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE' 'BypassNRO' 'REG_DWORD' '1' _ISOScript-SetReg 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\OOBE' 'BypassNRO' 'REG_DWORD' '1'
if ($AutoUnattendXml) {
# ── Place autounattend.xml inside the WIM (Sysprep) ──────────────────
$sysprepDest = "$ScratchDir\Windows\System32\Sysprep\autounattend.xml" $sysprepDest = "$ScratchDir\Windows\System32\Sysprep\autounattend.xml"
Set-Content -Path $sysprepDest -Value $WinUtilAutounattendXml -Encoding UTF8 -Force Set-Content -Path $sysprepDest -Value $AutoUnattendXml -Encoding UTF8 -Force
& $Log "Written autounattend.xml to Sysprep directory." & $Log "Written autounattend.xml to Sysprep directory."
# ── Place autounattend.xml at the ISO / USB root ──────────────────────
# Windows Setup reads this file first (before booting into the OS),
# which is what drives the local-account / OOBE bypass at install time.
if ($ISOContentsDir -and (Test-Path $ISOContentsDir)) {
$isoDest = Join-Path $ISOContentsDir "autounattend.xml"
Set-Content -Path $isoDest -Value $AutoUnattendXml -Encoding UTF8 -Force
& $Log "Written autounattend.xml to ISO root ($isoDest)."
}
} else {
& $Log "Warning: autounattend.xml content is empty — skipping OOBE bypass file."
}
& $Log "Disabling reserved storage..." & $Log "Disabling reserved storage..."
_ISOScript-SetReg 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\ReserveManager' 'ShippedWithReserves' 'REG_DWORD' '0' _ISOScript-SetReg 'HKLM\zSOFTWARE\Microsoft\Windows\CurrentVersion\ReserveManager' 'ShippedWithReserves' 'REG_DWORD' '0'

View File

@@ -554,11 +554,18 @@ $sync["WPFWin11ISOModifyButton"].Add_Click({
Invoke-WinUtilISOModify Invoke-WinUtilISOModify
}) })
$sync["WPFWin11ISOExportButton"].Add_Click({ $sync["WPFWin11ISOChooseISOButton"].Add_Click({
Write-Debug "WPFWin11ISOExportButton clicked" Write-Debug "WPFWin11ISOChooseISOButton clicked"
$sync["WPFWin11ISOOptionUSB"].Visibility = "Collapsed"
Invoke-WinUtilISOExport Invoke-WinUtilISOExport
}) })
$sync["WPFWin11ISOChooseUSBButton"].Add_Click({
Write-Debug "WPFWin11ISOChooseUSBButton clicked"
$sync["WPFWin11ISOOptionUSB"].Visibility = "Visible"
Invoke-WinUtilISORefreshUSBDrives
})
$sync["WPFWin11ISORefreshUSBButton"].Add_Click({ $sync["WPFWin11ISORefreshUSBButton"].Add_Click({
Write-Debug "WPFWin11ISORefreshUSBButton clicked" Write-Debug "WPFWin11ISORefreshUSBButton clicked"
Invoke-WinUtilISORefreshUSBDrives Invoke-WinUtilISORefreshUSBDrives
@@ -569,6 +576,11 @@ $sync["WPFWin11ISOWriteUSBButton"].Add_Click({
Invoke-WinUtilISOWriteUSB Invoke-WinUtilISOWriteUSB
}) })
$sync["WPFWin11ISOCleanResetButton"].Add_Click({
Write-Debug "WPFWin11ISOCleanResetButton clicked"
Invoke-WinUtilISOCleanAndReset
})
# ────────────────────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────────────────────
$sync["Form"].ShowDialog() | out-null $sync["Form"].ShowDialog() | out-null

View File

@@ -1353,7 +1353,7 @@
<!-- ═══════════════════════════════════════════════════════════ --> <!-- ═══════════════════════════════════════════════════════════ -->
<!-- STEP 1 : Select Windows 11 ISO --> <!-- STEP 1 : Select Windows 11 ISO -->
<!-- ═══════════════════════════════════════════════════════════ --> <!-- ═══════════════════════════════════════════════════════════ -->
<Border Grid.Row="0" Style="{StaticResource BorderStyle}"> <Border Grid.Row="0" Name="WPFWin11ISOSelectSection" Style="{StaticResource BorderStyle}">
<Grid Margin="5"> <Grid Margin="5">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
@@ -1364,12 +1364,13 @@
<StackPanel Grid.Column="0" Margin="5,5,15,5"> <StackPanel Grid.Column="0" Margin="5,5,15,5">
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold" <TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8"> Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8">
Step 1 Select Windows 11 ISO Step 1 - Select Windows 11 ISO
</TextBlock> </TextBlock>
<TextBlock FontSize="{DynamicResource FontSize}" Foreground="{DynamicResource MainForegroundColor}" <TextBlock FontSize="{DynamicResource FontSize}" Foreground="{DynamicResource MainForegroundColor}"
TextWrapping="Wrap" Margin="0,0,0,12"> TextWrapping="Wrap" Margin="0,0,0,12">
Browse to your locally saved Windows 11 ISO file. Only official ISOs Browse to your locally saved Windows 11 ISO file. Only official ISOs
downloaded from Microsoft are supported. downloaded from Microsoft are supported. This is only meant for FRESH
and NEW Windows installs.
</TextBlock> </TextBlock>
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -1387,7 +1388,7 @@
Background="{DynamicResource MainBackgroundColor}"/> Background="{DynamicResource MainBackgroundColor}"/>
<Button Grid.Column="1" <Button Grid.Column="1"
Name="WPFWin11ISOBrowseButton" Name="WPFWin11ISOBrowseButton"
Content="Browse" Content="Browse"
Width="Auto" Padding="12,0" Width="Auto" Padding="12,0"
Height="{DynamicResource ButtonHeight}"/> Height="{DynamicResource ButtonHeight}"/>
</Grid> </Grid>
@@ -1408,7 +1409,7 @@
<StackPanel> <StackPanel>
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold" <TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
Foreground="OrangeRed" Margin="0,0,0,10"> Foreground="OrangeRed" Margin="0,0,0,10">
You must use an official Microsoft ISO !!WARNING!! You must use an official Microsoft ISO
</TextBlock> </TextBlock>
<TextBlock FontSize="{DynamicResource FontSize}" <TextBlock FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}" Foreground="{DynamicResource MainForegroundColor}"
@@ -1425,9 +1426,9 @@
<TextBlock FontSize="{DynamicResource FontSize}" <TextBlock FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}" Foreground="{DynamicResource MainForegroundColor}"
TextWrapping="Wrap" Margin="12,0,0,12"> TextWrapping="Wrap" Margin="12,0,0,12">
Edition : Windows 11 - Edition : Windows 11
<LineBreak/> Language : your preferred language <LineBreak/>- Language : your preferred language
<LineBreak/> Architecture : 64-bit (x64) <LineBreak/>- Architecture : 64-bit (x64)
</TextBlock> </TextBlock>
<Button Name="WPFWin11ISODownloadLink" <Button Name="WPFWin11ISODownloadLink"
Content="Open Microsoft Download Page" Content="Open Microsoft Download Page"
@@ -1455,7 +1456,7 @@
<StackPanel Grid.Column="0" Margin="0,0,20,0" VerticalAlignment="Top"> <StackPanel Grid.Column="0" Margin="0,0,20,0" VerticalAlignment="Top">
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold" <TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8"> Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8">
Step 2 Mount &amp; Verify ISO Step 2 - Mount &amp; Verify ISO
</TextBlock> </TextBlock>
<TextBlock FontSize="{DynamicResource FontSize}" <TextBlock FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}" Foreground="{DynamicResource MainForegroundColor}"
@@ -1490,12 +1491,15 @@
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold" <TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
Foreground="{DynamicResource MainForegroundColor}" Foreground="{DynamicResource MainForegroundColor}"
Margin="0,6,0,4"> Margin="0,6,0,4">
Available Editions: Select Edition:
</TextBlock> </TextBlock>
<TextBlock Name="WPFWin11ISOEditionList" <ComboBox Name="WPFWin11ISOEditionComboBox"
FontSize="{DynamicResource FontSize}" FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}" Foreground="{DynamicResource MainForegroundColor}"
TextWrapping="Wrap"/> Background="{DynamicResource MainBackgroundColor}"
BorderBrush="{DynamicResource BorderColor}"
HorizontalAlignment="Stretch"
Margin="0,0,0,0"/>
</StackPanel> </StackPanel>
</Border> </Border>
</Grid> </Grid>
@@ -1511,7 +1515,7 @@
<StackPanel Margin="5"> <StackPanel Margin="5">
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold" <TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold"
Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8"> Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,8">
Step 3 Modify install.wim Step 3 - Modify install.wim
</TextBlock> </TextBlock>
<TextBlock FontSize="{DynamicResource FontSize}" <TextBlock FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}" Foreground="{DynamicResource MainForegroundColor}"
@@ -1537,38 +1541,62 @@
Style="{StaticResource BorderStyle}" Style="{StaticResource BorderStyle}"
Visibility="Collapsed"> Visibility="Collapsed">
<StackPanel Margin="5"> <StackPanel Margin="5">
<TextBlock FontSize="{DynamicResource FontSize}" FontWeight="Bold" <!-- Header row: title + Clean & Reset button -->
Foreground="{DynamicResource MainForegroundColor}" Margin="0,0,0,12"> <Grid Margin="0,0,0,12">
Step 4 — Output: What would you like to do with the modified ISO?
</TextBlock>
<Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="{DynamicResource FontSize}" FontWeight="Bold"
<!-- Option 1: Export to ISO --> Foreground="{DynamicResource MainForegroundColor}"
<Border Grid.Column="0" Style="{StaticResource BorderStyle}"> VerticalAlignment="Center">
<StackPanel> Step 4 - Output: What would you like to do with the modified image?
<Button Name="WPFWin11ISOExportButton" </TextBlock>
Content="1 — Export to ISO" <Button Grid.Column="1"
HorizontalAlignment="Stretch" Name="WPFWin11ISOCleanResetButton"
Content="🗑 Clean &amp; Reset"
Foreground="OrangeRed"
Width="Auto" Padding="12,0" Width="Auto" Padding="12,0"
Height="{DynamicResource ButtonHeight}" Height="{DynamicResource ButtonHeight}"
Margin="0,0,0,10"/> ToolTip="Delete the temporary working directory and reset the interface back to Step 1"
Margin="12,0,0,0"/>
</Grid>
<!-- ── Choice prompt buttons ── -->
<Grid Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Name="WPFWin11ISOChooseISOButton"
Content="Save as an ISO File"
HorizontalAlignment="Stretch"
Width="Auto" Padding="12,0"
Height="{DynamicResource ButtonHeight}"/>
<Button Grid.Column="2"
Name="WPFWin11ISOChooseUSBButton"
Content="Write Directly to a USB Drive (erases drive)"
Foreground="OrangeRed"
HorizontalAlignment="Stretch"
Width="Auto" Padding="12,0"
Height="{DynamicResource ButtonHeight}"/>
</Grid>
<!-- ── USB write sub-panel (revealed on USB choice) ── -->
<Border Name="WPFWin11ISOOptionUSB"
Style="{StaticResource BorderStyle}"
Visibility="Collapsed"
Margin="0,8,0,0">
<StackPanel>
<TextBlock FontSize="{DynamicResource FontSize}" <TextBlock FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}" Foreground="{DynamicResource MainForegroundColor}"
TextWrapping="Wrap"> TextWrapping="Wrap" Margin="0,0,0,8">
Save the modified content as a new bootable ISO file. <Run FontWeight="Bold" Foreground="OrangeRed">!! All data on the selected USB drive will be permanently erased !!</Run>
You can store it, use it in a virtual machine, or later <LineBreak/>
burn it to USB with any tool of your choice. Select a removable USB drive below, then click Erase &amp; Write.
</TextBlock> </TextBlock>
</StackPanel>
</Border>
<!-- Option 2: Erase & Write to USB -->
<Border Grid.Column="1" Style="{StaticResource BorderStyle}">
<StackPanel>
<!-- USB drive selector row --> <!-- USB drive selector row -->
<Grid Margin="0,0,0,8"> <Grid Margin="0,0,0,8">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@@ -1588,23 +1616,15 @@
Height="{DynamicResource ButtonHeight}"/> Height="{DynamicResource ButtonHeight}"/>
</Grid> </Grid>
<Button Name="WPFWin11ISOWriteUSBButton" <Button Name="WPFWin11ISOWriteUSBButton"
Content="2 — Erase &amp; Write to USB" Content="Erase &amp; Write to USB"
Foreground="OrangeRed" Foreground="OrangeRed"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Width="Auto" Padding="12,0" Width="Auto" Padding="12,0"
Height="{DynamicResource ButtonHeight}" Height="{DynamicResource ButtonHeight}"
Margin="0,0,0,10"/> Margin="0,0,0,10"/>
<TextBlock FontSize="{DynamicResource FontSize}"
Foreground="{DynamicResource MainForegroundColor}"
TextWrapping="Wrap">
<Run FontWeight="Bold" Foreground="OrangeRed">!! All data on the selected USB drive will be erased !!</Run>
<LineBreak/>
Select a removable USB drive above, then click the button
to write the modified Windows 11 installation directly to it.
</TextBlock>
</StackPanel> </StackPanel>
</Border> </Border>
</Grid>
</StackPanel> </StackPanel>
</Border> </Border>