@@ -376,6 +376,7 @@ function Invoke-WinUtilISOModify {
376376 # the UI thread here.
377377 $sync [" WPFWin11ISOOutputSection" ].Dispatcher.Invoke([action ]{
378378 $sync [" WPFWin11ISOOutputSection" ].Visibility = " Visible"
379+ $sync [" WPFWin11ISOStatusLog" ].Height = 300
379380 })
380381 }
381382 catch {
@@ -480,12 +481,13 @@ function Invoke-WinUtilISOCheckExistingWork {
480481 $sync [" WPFWin11ISOMountSection" ].Visibility = " Collapsed"
481482 $sync [" WPFWin11ISOModifySection" ].Visibility = " Collapsed"
482483 $sync [" WPFWin11ISOOutputSection" ].Visibility = " Visible"
484+ $sync [" WPFWin11ISOStatusLog" ].Height = 300
483485
484486 # Notify via the status log
485487 $dirName = $existingWorkDir.Name
486488 $modified = $existingWorkDir.LastWriteTime.ToString (" yyyy-MM-dd HH:mm" )
487489 Write-Win11ISOLog " Existing working directory found: $ ( $existingWorkDir.FullName ) "
488- Write-Win11ISOLog " Last modified: $modified — Skipping Steps 1-3 and resuming at Step 4."
490+ Write-Win11ISOLog " Last modified: $modified - Skipping Steps 1-3 and resuming at Step 4."
489491 Write-Win11ISOLog " Click 'Clean & Reset' if you want to start over with a new ISO."
490492
491493 [System.Windows.MessageBox ]::Show(
@@ -498,6 +500,8 @@ function Invoke-WinUtilISOCleanAndReset {
498500 . SYNOPSIS
499501 Deletes the temporary working directory created during ISO modification
500502 and resets the entire ISO UI back to its initial state (Step 1 only).
503+ Deletion runs in a background runspace so the UI stays responsive and
504+ progress is reported to the user.
501505 #>
502506
503507 $workDir = $sync [" Win11ISOWorkDir" ]
@@ -507,37 +511,126 @@ function Invoke-WinUtilISOCleanAndReset {
507511 " This will delete the temporary working directory:`n`n $workDir `n`n And reset the interface back to the start.`n`n Continue?" ,
508512 " Clean & Reset" , " YesNo" , " Warning" )
509513 if ($confirm -ne " Yes" ) { return }
514+ }
515+
516+ # Disable button so it cannot be clicked twice
517+ $sync [" WPFWin11ISOCleanResetButton" ].IsEnabled = $false
518+
519+ $runspace = [Management.Automation.Runspaces.RunspaceFactory ]::CreateRunspace()
520+ $runspace.ApartmentState = " STA"
521+ $runspace.ThreadOptions = " ReuseThread"
522+ $runspace.Open ()
523+ $runspace.SessionStateProxy.SetVariable (" sync" , $sync )
524+ $runspace.SessionStateProxy.SetVariable (" workDir" , $workDir )
525+
526+ $script = [Management.Automation.PowerShell ]::Create()
527+ $script.Runspace = $runspace
528+ $script.AddScript ({
529+
530+ function Log ($msg ) {
531+ $ts = (Get-Date ).ToString(" HH:mm:ss" )
532+ $sync [" WPFWin11ISOStatusLog" ].Dispatcher.Invoke([action ]{
533+ $sync [" WPFWin11ISOStatusLog" ].Text += " `n [$ts ] $msg "
534+ $sync [" WPFWin11ISOStatusLog" ].CaretIndex = $sync [" WPFWin11ISOStatusLog" ].Text.Length
535+ $sync [" WPFWin11ISOStatusLog" ].ScrollToEnd()
536+ })
537+ }
538+ function SetProgress ($label , $pct ) {
539+ $sync [" WPFWin11ISOStatusLog" ].Dispatcher.Invoke([action ]{
540+ $sync.progressBarTextBlock.Text = $label
541+ $sync.progressBarTextBlock.ToolTip = $label
542+ $sync.ProgressBar.Value = [Math ]::Max($pct , 5 )
543+ })
544+ }
510545
511546 try {
512- Write-Win11ISOLog " Deleting temp directory: $workDir "
513- Remove-Item - Path $workDir - Recurse - Force - ErrorAction Stop
514- Write-Win11ISOLog " Temp directory deleted."
515- } catch {
516- Write-Win11ISOLog " WARNING: could not fully delete temp directory: $_ "
547+ if ($workDir -and (Test-Path $workDir )) {
548+ Log " Scanning files to delete in: $workDir "
549+ SetProgress " Scanning files..." 5
550+
551+ $allItems = @ (Get-ChildItem - Path $workDir - Recurse - Force - ErrorAction SilentlyContinue)
552+ $total = $allItems.Count
553+ $deleted = 0
554+
555+ Log " Found $total items to delete."
556+
557+ # Delete files first, then directories (deepest first)
558+ $files = $allItems | Where-Object { -not $_.PSIsContainer }
559+ $dirs = $allItems | Where-Object { $_.PSIsContainer } |
560+ Sort-Object { $_.FullName.Length } - Descending
561+
562+ foreach ($f in $files ) {
563+ try { Remove-Item - Path $f.FullName - Force - ErrorAction Stop } catch {}
564+ $deleted ++
565+ $pct = [math ]::Round(($deleted / [Math ]::Max($total , 1 )) * 85 ) + 5
566+ SetProgress " Deleting files... ($deleted / $total )" $pct
567+ }
568+
569+ foreach ($d in $dirs ) {
570+ try { Remove-Item - Path $d.FullName - Force - Recurse - ErrorAction Stop } catch {}
571+ $deleted ++
572+ $pct = [math ]::Round(($deleted / [Math ]::Max($total , 1 )) * 85 ) + 5
573+ SetProgress " Removing directories... ($deleted / $total )" $pct
574+ }
575+
576+ # Remove the root work directory itself
577+ try { Remove-Item - Path $workDir - Force - Recurse - ErrorAction Stop } catch {}
578+
579+ if (Test-Path $workDir ) {
580+ Log " WARNING: some items could not be deleted in $workDir "
581+ } else {
582+ Log " Temp directory deleted successfully."
583+ }
584+ } else {
585+ Log " No temp directory found — resetting UI."
586+ }
587+
588+ SetProgress " Resetting UI..." 95
589+ Log " Resetting interface..."
590+
591+ # ── Full UI reset on the dispatcher thread ──────────────────────
592+ $sync [" WPFWin11ISOStatusLog" ].Dispatcher.Invoke([action ]{
593+ # Clear stored state
594+ $sync [" Win11ISOWorkDir" ] = $null
595+ $sync [" Win11ISOContentsDir" ] = $null
596+ $sync [" Win11ISOImagePath" ] = $null
597+ $sync [" Win11ISODriveLetter" ] = $null
598+ $sync [" Win11ISOWimPath" ] = $null
599+ $sync [" Win11ISOImageInfo" ] = $null
600+ $sync [" Win11ISOUSBDisks" ] = $null
601+
602+ # Reset UI elements
603+ $sync [" WPFWin11ISOPath" ].Text = " No ISO selected..."
604+ $sync [" WPFWin11ISOFileInfo" ].Visibility = " Collapsed"
605+ $sync [" WPFWin11ISOVerifyResultPanel" ].Visibility = " Collapsed"
606+ $sync [" WPFWin11ISOOptionUSB" ].Visibility = " Collapsed"
607+ $sync [" WPFWin11ISOOutputSection" ].Visibility = " Collapsed"
608+ $sync [" WPFWin11ISOModifySection" ].Visibility = " Collapsed"
609+ $sync [" WPFWin11ISOMountSection" ].Visibility = " Collapsed"
610+ $sync [" WPFWin11ISOSelectSection" ].Visibility = " Visible"
611+ $sync [" WPFWin11ISOModifyButton" ].IsEnabled = $true
612+ $sync [" WPFWin11ISOCleanResetButton" ].IsEnabled = $true
613+
614+ $sync.progressBarTextBlock.Text = " "
615+ $sync.progressBarTextBlock.ToolTip = " "
616+ $sync.ProgressBar.Value = 0
617+
618+ $sync [" WPFWin11ISOStatusLog" ].Height = 140
619+ $sync [" WPFWin11ISOStatusLog" ].Text = " Ready. Please select a Windows 11 ISO to begin."
620+ })
517621 }
518- }
622+ catch {
623+ Log " ERROR during Clean & Reset: $_ "
624+ $sync [" WPFWin11ISOStatusLog" ].Dispatcher.Invoke([action ]{
625+ $sync.progressBarTextBlock.Text = " "
626+ $sync.progressBarTextBlock.ToolTip = " "
627+ $sync.ProgressBar.Value = 0
628+ $sync [" WPFWin11ISOCleanResetButton" ].IsEnabled = $true
629+ })
630+ }
631+ }) | Out-Null
519632
520- # Clear all stored ISO state
521- $sync [" Win11ISOWorkDir" ] = $null
522- $sync [" Win11ISOContentsDir" ] = $null
523- $sync [" Win11ISOImagePath" ] = $null
524- $sync [" Win11ISODriveLetter" ] = $null
525- $sync [" Win11ISOWimPath" ] = $null
526- $sync [" Win11ISOImageInfo" ] = $null
527- $sync [" Win11ISOUSBDisks" ] = $null
528-
529- # Reset the UI to the initial state
530- $sync [" WPFWin11ISOPath" ].Text = " No ISO selected..."
531- $sync [" WPFWin11ISOFileInfo" ].Visibility = " Collapsed"
532- $sync [" WPFWin11ISOVerifyResultPanel" ].Visibility = " Collapsed"
533- $sync [" WPFWin11ISOOptionUSB" ].Visibility = " Collapsed"
534- $sync [" WPFWin11ISOOutputSection" ].Visibility = " Collapsed"
535- $sync [" WPFWin11ISOModifySection" ].Visibility = " Collapsed"
536- $sync [" WPFWin11ISOMountSection" ].Visibility = " Collapsed"
537- $sync [" WPFWin11ISOSelectSection" ].Visibility = " Visible"
538- $sync [" WPFWin11ISOStatusLog" ].Text = " Ready. Please select a Windows 11 ISO to begin."
539- $sync [" WPFWin11ISOStatusLog" ].Height = 140
540- $sync [" WPFWin11ISOModifyButton" ].IsEnabled = $true
633+ $script.BeginInvoke () | Out-Null
541634}
542635
543636function Invoke-WinUtilISOExport {
0 commit comments