From 669ecd9c64c2aeb7348140aeb9f07fc512b6e1d2 Mon Sep 17 00:00:00 2001 From: Chris Titus Date: Wed, 25 Feb 2026 11:44:02 -0600 Subject: [PATCH] expand ui and fix clean and reset --- functions/private/Invoke-WinUtilISO.ps1 | 151 +++++++++++++++++++----- xaml/inputXML.xaml | 52 ++++---- 2 files changed, 143 insertions(+), 60 deletions(-) diff --git a/functions/private/Invoke-WinUtilISO.ps1 b/functions/private/Invoke-WinUtilISO.ps1 index a190ed9c..33cd1180 100644 --- a/functions/private/Invoke-WinUtilISO.ps1 +++ b/functions/private/Invoke-WinUtilISO.ps1 @@ -376,6 +376,7 @@ function Invoke-WinUtilISOModify { # the UI thread here. $sync["WPFWin11ISOOutputSection"].Dispatcher.Invoke([action]{ $sync["WPFWin11ISOOutputSection"].Visibility = "Visible" + $sync["WPFWin11ISOStatusLog"].Height = 300 }) } catch { @@ -480,12 +481,13 @@ function Invoke-WinUtilISOCheckExistingWork { $sync["WPFWin11ISOMountSection"].Visibility = "Collapsed" $sync["WPFWin11ISOModifySection"].Visibility = "Collapsed" $sync["WPFWin11ISOOutputSection"].Visibility = "Visible" + $sync["WPFWin11ISOStatusLog"].Height = 300 # Notify via the status log $dirName = $existingWorkDir.Name $modified = $existingWorkDir.LastWriteTime.ToString("yyyy-MM-dd HH:mm") Write-Win11ISOLog "Existing working directory found: $($existingWorkDir.FullName)" - Write-Win11ISOLog "Last modified: $modified — Skipping Steps 1-3 and resuming at Step 4." + Write-Win11ISOLog "Last modified: $modified - Skipping Steps 1-3 and resuming at Step 4." Write-Win11ISOLog "Click 'Clean & Reset' if you want to start over with a new ISO." [System.Windows.MessageBox]::Show( @@ -498,6 +500,8 @@ 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). + Deletion runs in a background runspace so the UI stays responsive and + progress is reported to the user. #> $workDir = $sync["Win11ISOWorkDir"] @@ -507,37 +511,126 @@ function Invoke-WinUtilISOCleanAndReset { "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 + # Disable button so it cannot be clicked twice + $sync["WPFWin11ISOCleanResetButton"].IsEnabled = $false - # 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 + $runspace = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace() + $runspace.ApartmentState = "STA" + $runspace.ThreadOptions = "ReuseThread" + $runspace.Open() + $runspace.SessionStateProxy.SetVariable("sync", $sync) + $runspace.SessionStateProxy.SetVariable("workDir", $workDir) + + $script = [Management.Automation.PowerShell]::Create() + $script.Runspace = $runspace + $script.AddScript({ + + function Log($msg) { + $ts = (Get-Date).ToString("HH:mm:ss") + $sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{ + $sync["WPFWin11ISOStatusLog"].Text += "`n[$ts] $msg" + $sync["WPFWin11ISOStatusLog"].CaretIndex = $sync["WPFWin11ISOStatusLog"].Text.Length + $sync["WPFWin11ISOStatusLog"].ScrollToEnd() + }) + } + function SetProgress($label, $pct) { + $sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{ + $sync.progressBarTextBlock.Text = $label + $sync.progressBarTextBlock.ToolTip = $label + $sync.ProgressBar.Value = [Math]::Max($pct, 5) + }) + } + + try { + if ($workDir -and (Test-Path $workDir)) { + Log "Scanning files to delete in: $workDir" + SetProgress "Scanning files..." 5 + + $allItems = @(Get-ChildItem -Path $workDir -Recurse -Force -ErrorAction SilentlyContinue) + $total = $allItems.Count + $deleted = 0 + + Log "Found $total items to delete." + + # Delete files first, then directories (deepest first) + $files = $allItems | Where-Object { -not $_.PSIsContainer } + $dirs = $allItems | Where-Object { $_.PSIsContainer } | + Sort-Object { $_.FullName.Length } -Descending + + foreach ($f in $files) { + try { Remove-Item -Path $f.FullName -Force -ErrorAction Stop } catch {} + $deleted++ + $pct = [math]::Round(($deleted / [Math]::Max($total,1)) * 85) + 5 + SetProgress "Deleting files... ($deleted / $total)" $pct + } + + foreach ($d in $dirs) { + try { Remove-Item -Path $d.FullName -Force -Recurse -ErrorAction Stop } catch {} + $deleted++ + $pct = [math]::Round(($deleted / [Math]::Max($total,1)) * 85) + 5 + SetProgress "Removing directories... ($deleted / $total)" $pct + } + + # Remove the root work directory itself + try { Remove-Item -Path $workDir -Force -Recurse -ErrorAction Stop } catch {} + + if (Test-Path $workDir) { + Log "WARNING: some items could not be deleted in $workDir" + } else { + Log "Temp directory deleted successfully." + } + } else { + Log "No temp directory found — resetting UI." + } + + SetProgress "Resetting UI..." 95 + Log "Resetting interface..." + + # ── Full UI reset on the dispatcher thread ────────────────────── + $sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{ + # Clear stored state + $sync["Win11ISOWorkDir"] = $null + $sync["Win11ISOContentsDir"] = $null + $sync["Win11ISOImagePath"] = $null + $sync["Win11ISODriveLetter"] = $null + $sync["Win11ISOWimPath"] = $null + $sync["Win11ISOImageInfo"] = $null + $sync["Win11ISOUSBDisks"] = $null + + # Reset UI elements + $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["WPFWin11ISOModifyButton"].IsEnabled = $true + $sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true + + $sync.progressBarTextBlock.Text = "" + $sync.progressBarTextBlock.ToolTip = "" + $sync.ProgressBar.Value = 0 + + $sync["WPFWin11ISOStatusLog"].Height = 140 + $sync["WPFWin11ISOStatusLog"].Text = "Ready. Please select a Windows 11 ISO to begin." + }) + } + catch { + Log "ERROR during Clean & Reset: $_" + $sync["WPFWin11ISOStatusLog"].Dispatcher.Invoke([action]{ + $sync.progressBarTextBlock.Text = "" + $sync.progressBarTextBlock.ToolTip = "" + $sync.ProgressBar.Value = 0 + $sync["WPFWin11ISOCleanResetButton"].IsEnabled = $true + }) + } + }) | Out-Null + + $script.BeginInvoke() | Out-Null } function Invoke-WinUtilISOExport { diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index 9381f44d..f4be786a 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -1377,8 +1377,7 @@ - - + @@ -1464,18 +1463,16 @@ Height="{DynamicResource ButtonHeight}"/> - - + - - + @@ -1529,18 +1526,16 @@ Margin="0,0,0,0"/> - - + - - + Step 3 - Modify install.wim @@ -1558,18 +1553,16 @@ HorizontalAlignment="Left" Width="Auto" Padding="12,0" Height="{DynamicResource ButtonHeight}"/> - - + - - + @@ -1654,14 +1647,12 @@ - - + - - + Status Log @@ -1677,7 +1668,6 @@ BorderThickness="1" Text="Ready. Please select a Windows 11 ISO to begin."/> -