From 6dbaac05134e02dbb0fd16186301c27ba65aac9d Mon Sep 17 00:00:00 2001
From: Jeffrey <9938813+Raphire@users.noreply.github.com>
Date: Wed, 27 May 2026 22:05:06 +0200
Subject: [PATCH] Properly show re-applied features in registry backup
overview, properly show applied tweaks checkbox state after registry backup
restoration
---
Schemas/RestoreBackupWindow.xaml | 35 ++++++++++++-
.../GUI/RestoreBackupDialogFeatureLists.ps1 | 50 ++++++++++++++++++-
Scripts/GUI/Show-MainWindow.ps1 | 38 ++++++++++----
Scripts/GUI/Show-RestoreBackupDialog.ps1 | 44 +++++++++++++---
Scripts/GUI/Show-RestoreBackupWindow.ps1 | 16 +++++-
5 files changed, 161 insertions(+), 22 deletions(-)
diff --git a/Schemas/RestoreBackupWindow.xaml b/Schemas/RestoreBackupWindow.xaml
index 1807953..38d7a69 100644
--- a/Schemas/RestoreBackupWindow.xaml
+++ b/Schemas/RestoreBackupWindow.xaml
@@ -222,6 +222,8 @@
+
+
@@ -282,9 +284,38 @@
Visibility="Collapsed"
Text="This will restore the Start Menu pinned apps layout for the current user."/>
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1 b/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1
index c942cc7..7bbda18 100644
--- a/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1
+++ b/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1
@@ -79,13 +79,53 @@ function Test-RestoreDialogFeatureVisibleInOverview {
return -not [string]::IsNullOrWhiteSpace([string]$featureDefinition.Category)
}
-function Get-SelectedFeatureIdsFromBackup {
+function Get-SelectedForwardFeatureIdsFromBackup {
+ param($SelectedBackup)
+
+ $selectedFeatureIds = New-Object System.Collections.Generic.List[string]
+ $seenSelectedFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase)
+
+ foreach ($featureId in @($SelectedBackup.SelectedFeatures)) {
+ if ([string]::IsNullOrWhiteSpace([string]$featureId)) {
+ continue
+ }
+
+ $normalizedId = [string]$featureId
+ if ($seenSelectedFeatureIds.Add($normalizedId)) {
+ $selectedFeatureIds.Add($normalizedId)
+ }
+ }
+
+ return @($selectedFeatureIds.ToArray())
+}
+
+function Get-SelectedUndoFeatureIdsFromBackup {
+ param($SelectedBackup)
+
+ $selectedUndoFeatureIds = New-Object System.Collections.Generic.List[string]
+ $seenUndoFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase)
+
+ foreach ($featureId in @($SelectedBackup.SelectedUndoFeatures)) {
+ if ([string]::IsNullOrWhiteSpace([string]$featureId)) {
+ continue
+ }
+
+ $normalizedId = [string]$featureId
+ if ($seenUndoFeatureIds.Add($normalizedId)) {
+ $selectedUndoFeatureIds.Add($normalizedId)
+ }
+ }
+
+ return @($selectedUndoFeatureIds.ToArray())
+}
+
+function Get-CombinedSelectedFeatureIdsFromBackup {
param($SelectedBackup)
$featureIds = New-Object System.Collections.Generic.List[string]
$seenIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase)
- foreach ($featureId in @($SelectedBackup.SelectedFeatures) + @($SelectedBackup.SelectedUndoFeatures)) {
+ foreach ($featureId in @(Get-SelectedForwardFeatureIdsFromBackup -SelectedBackup $SelectedBackup) + @(Get-SelectedUndoFeatureIdsFromBackup -SelectedBackup $SelectedBackup)) {
if ([string]::IsNullOrWhiteSpace([string]$featureId)) {
continue
}
@@ -99,6 +139,12 @@ function Get-SelectedFeatureIdsFromBackup {
return @($featureIds.ToArray())
}
+function Get-SelectedFeatureIdsFromBackup {
+ param($SelectedBackup)
+
+ return @(Get-CombinedSelectedFeatureIdsFromBackup -SelectedBackup $SelectedBackup)
+}
+
function Get-RestoreBackupFeatureLists {
param(
[string[]]$SelectedFeatureIds,
diff --git a/Scripts/GUI/Show-MainWindow.ps1 b/Scripts/GUI/Show-MainWindow.ps1
index 636c1ee..5cb28fb 100644
--- a/Scripts/GUI/Show-MainWindow.ps1
+++ b/Scripts/GUI/Show-MainWindow.ps1
@@ -278,7 +278,15 @@ function Show-MainWindow {
if ($restoreBackupBtn) {
$restoreBackupBtn.Add_Click({
try {
- Show-RestoreBackupWindow -Owner $window
+ $restoreResult = Show-RestoreBackupWindow -Owner $window
+ if ($restoreResult -and $restoreResult.RestoredRegistry -eq $true) {
+ RefreshCurrentTweakSystemState -ApplyToUi:$false
+
+ if ($ShowCurrentlyAppliedTweaksCheckBox -and $ShowCurrentlyAppliedTweaksCheckBox.IsChecked -eq $true) {
+ ResetTweaksToSystemState -loadSystemState $true
+ UpdateTweakPresetStates
+ }
+ }
}
catch {
Write-Warning "Restore backup action failed: $($_.Exception.Message)"
@@ -905,10 +913,9 @@ function Show-MainWindow {
}
}
- # Reads current registry state and sets each tweak control to reflect whether that tweak is
- # currently applied. Also stores the initial state on each control as a NoteProperty so the
- # apply handler can detect which controls actually changed.
- function LoadCurrentTweakStateIntoUI {
+ function RefreshCurrentTweakSystemState {
+ param([bool]$ApplyToUi)
+
if (-not $script:UiControlMappings) { return }
if (-not $script:Features) { return }
@@ -930,9 +937,12 @@ function Show-MainWindow {
if ($control -is [System.Windows.Controls.CheckBox] -and $mapping.Type -eq 'feature') {
$applied = $false
try { $applied = [bool](Test-FeatureApplied -FeatureId $mapping.FeatureId) } catch {}
- $control.IsChecked = $applied
- Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialState' -Value $applied -Force
Add-Member -InputObject $control -MemberType NoteProperty -Name 'SystemState' -Value $applied -Force
+
+ if ($ApplyToUi) {
+ $control.IsChecked = $applied
+ Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialState' -Value $applied -Force
+ }
}
elseif ($control -is [System.Windows.Controls.ComboBox] -and $mapping.Type -eq 'group') {
$groupId = $null
@@ -941,13 +951,23 @@ function Show-MainWindow {
if ($groupId -and $groupMap.ContainsKey($groupId)) {
try { $activeIndex = Get-CurrentGroupActiveIndex -Group $groupMap[$groupId] } catch {}
}
- $control.SelectedIndex = $activeIndex
- Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialIndex' -Value $activeIndex -Force
Add-Member -InputObject $control -MemberType NoteProperty -Name 'SystemIndex' -Value $activeIndex -Force
+
+ if ($ApplyToUi) {
+ $control.SelectedIndex = $activeIndex
+ Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialIndex' -Value $activeIndex -Force
+ }
}
}
}
+ # Reads current registry state and sets each tweak control to reflect whether that tweak is
+ # currently applied. Also stores the initial state on each control as a NoteProperty so the
+ # apply handler can detect which controls actually changed.
+ function LoadCurrentTweakStateIntoUI {
+ RefreshCurrentTweakSystemState -ApplyToUi:$true
+ }
+
# Helper function to load apps and populate the app list panel
function script:LoadAppsWithList($listOfApps) {
$script:MainWindowLastSelectedCheckbox = $null
diff --git a/Scripts/GUI/Show-RestoreBackupDialog.ps1 b/Scripts/GUI/Show-RestoreBackupDialog.ps1
index e53e1ab..9ec68f2 100644
--- a/Scripts/GUI/Show-RestoreBackupDialog.ps1
+++ b/Scripts/GUI/Show-RestoreBackupDialog.ps1
@@ -70,6 +70,9 @@ function Show-RestoreBackupDialog {
$backupCreatedText = $window.FindName('BackupCreatedText')
$backupTargetText = $window.FindName('BackupTargetText')
$featuresItemsControl = $window.FindName('FeaturesItemsControl')
+ $reappliedSeparator = $window.FindName('ReappliedSeparator')
+ $reappliedPanel = $window.FindName('ReappliedPanel')
+ $reappliedFeaturesItemsControl = $window.FindName('ReappliedFeaturesItemsControl')
$nonRevertibleSeparator = $window.FindName('NonRevertibleSeparator')
$nonRevertiblePanel = $window.FindName('NonRevertiblePanel')
$nonRevertibleFeaturesItemsControl = $window.FindName('NonRevertibleFeaturesItemsControl')
@@ -119,6 +122,8 @@ function Show-RestoreBackupDialog {
$overviewFeaturesSection.Visibility = 'Collapsed'
$overviewSummaryText.Visibility = 'Visible'
+ $reappliedSeparator.Visibility = 'Collapsed'
+ $reappliedPanel.Visibility = 'Collapsed'
$nonRevertibleSeparator.Visibility = 'Collapsed'
$nonRevertiblePanel.Visibility = 'Collapsed'
$introInfoPanel.Visibility = 'Collapsed'
@@ -215,13 +220,33 @@ function Show-RestoreBackupDialog {
}
}
- $selectedFeatureIds = Get-SelectedFeatureIdsFromBackup -SelectedBackup $SelectedBackup
- $featureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds $selectedFeatureIds -Features $script:Features
- $revertibleFeaturesList = @($featureLists.Revertible)
- $nonRevertibleFeaturesList = @($featureLists.NonRevertible)
- Write-Host "Backup overview prepared. Revertible=$($revertibleFeaturesList.Count), NonRevertible=$($nonRevertibleFeaturesList.Count)"
+ $selectedForwardFeatureIds = @(Get-SelectedForwardFeatureIdsFromBackup -SelectedBackup $SelectedBackup)
+ $selectedUndoFeatureIds = @(Get-SelectedUndoFeatureIdsFromBackup -SelectedBackup $SelectedBackup)
- if ($revertibleFeaturesList.Count -eq 0) {
+ $seenForwardFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase)
+ foreach ($featureId in $selectedForwardFeatureIds) {
+ [void]$seenForwardFeatureIds.Add([string]$featureId)
+ }
+
+ $filteredUndoFeatureIds = New-Object System.Collections.Generic.List[string]
+ foreach ($featureId in $selectedUndoFeatureIds) {
+ if ($seenForwardFeatureIds.Contains([string]$featureId)) {
+ continue
+ }
+
+ $filteredUndoFeatureIds.Add([string]$featureId)
+ }
+
+ $forwardFeatureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds $selectedForwardFeatureIds -Features $script:Features
+ $undoFeatureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds @($filteredUndoFeatureIds.ToArray()) -Features $script:Features
+ $combinedFeatureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds (Get-SelectedFeatureIdsFromBackup -SelectedBackup $SelectedBackup) -Features $script:Features
+
+ $revertibleFeaturesList = @($forwardFeatureLists.Revertible)
+ $reappliedFeaturesList = @($undoFeatureLists.Revertible)
+ $nonRevertibleFeaturesList = @($combinedFeatureLists.NonRevertible)
+ Write-Host "Backup overview prepared. Reverted=$($revertibleFeaturesList.Count), ReApplied=$($reappliedFeaturesList.Count), NonRevertible=$($nonRevertibleFeaturesList.Count)"
+
+ if ($revertibleFeaturesList.Count -eq 0 -and $reappliedFeaturesList.Count -eq 0) {
throw 'The selected backup does not contain any changes that can be restored.'
}
@@ -229,13 +254,16 @@ function Show-RestoreBackupDialog {
$backupCreatedText.Text = $createdText
$backupTargetText.Text = GetFriendlyRegistryBackupTarget -Target ([string]$SelectedBackup.Target)
$featuresItemsControl.ItemsSource = $revertibleFeaturesList
- $overviewFeaturesSection.Visibility = 'Visible'
+ $overviewFeaturesSection.Visibility = if ($revertibleFeaturesList.Count -gt 0) { 'Visible' } else { 'Collapsed' }
+ $reappliedFeaturesItemsControl.ItemsSource = $reappliedFeaturesList
+ if ($reappliedFeaturesList.Count -gt 0) { $reappliedPanel.Visibility = 'Visible' } else { $reappliedPanel.Visibility = 'Collapsed' }
+ if ($revertibleFeaturesList.Count -gt 0 -and $reappliedFeaturesList.Count -gt 0) { $reappliedSeparator.Visibility = 'Visible' } else { $reappliedSeparator.Visibility = 'Collapsed' }
$overviewSummaryText.Visibility = 'Collapsed'
$nonRevertibleFeaturesItemsControl.ItemsSource = $nonRevertibleFeaturesList
$hasNonRevertibleItems = ($nonRevertibleFeaturesList.Count -gt 0)
if ($hasNonRevertibleItems) { $nonRevertiblePanel.Visibility = 'Visible' } else { $nonRevertiblePanel.Visibility = 'Collapsed' }
- if ($hasNonRevertibleItems) { $nonRevertibleSeparator.Visibility = 'Visible' } else { $nonRevertibleSeparator.Visibility = 'Collapsed' }
+ if ($hasNonRevertibleItems -and ($revertibleFeaturesList.Count -gt 0 -or $reappliedFeaturesList.Count -gt 0)) { $nonRevertibleSeparator.Visibility = 'Visible' } else { $nonRevertibleSeparator.Visibility = 'Collapsed' }
$introInfoPanel.Visibility = 'Collapsed'
$overviewPanel.Visibility = 'Visible'
diff --git a/Scripts/GUI/Show-RestoreBackupWindow.ps1 b/Scripts/GUI/Show-RestoreBackupWindow.ps1
index 1c15dd1..6fc9c41 100644
--- a/Scripts/GUI/Show-RestoreBackupWindow.ps1
+++ b/Scripts/GUI/Show-RestoreBackupWindow.ps1
@@ -7,10 +7,15 @@ function Show-RestoreBackupWindow {
try {
Write-Host 'Opening restore backup dialog.'
+ $restoreResult = [PSCustomObject]@{
+ RestoredRegistry = $false
+ RestoredStartMenu = $false
+ }
+
$dialogResult = Show-RestoreBackupDialog -Owner $Owner
if (-not $dialogResult -or $dialogResult.Result -eq 'Cancel') {
Write-Host 'Restore canceled by user.'
- return
+ return $restoreResult
}
$successMessage = $null
@@ -24,6 +29,7 @@ function Show-RestoreBackupWindow {
Write-Host "User confirmed registry restore for $($backup.Target)."
Restore-RegistryBackupState -Backup $backup
+ $restoreResult.RestoredRegistry = $true
$successMessage = 'Registry backup restored successfully. Some changes may require a sign out or restart to take effect.'
}
elseif ($dialogResult.Result -eq 'RestoreStartMenu') {
@@ -69,6 +75,8 @@ function Show-RestoreBackupWindow {
$successMessage = "The Start Menu backup was successfully restored for the current user. The changes will apply the next time you sign in."
}
}
+
+ $restoreResult.RestoredStartMenu = $true
}
if ($warningMessage) {
@@ -79,10 +87,16 @@ function Show-RestoreBackupWindow {
Write-Host "$successMessage"
Show-MessageBox -Title 'Backup Restored' -Message $successMessage -Icon Success
}
+
+ return $restoreResult
}
catch {
$errorMessage = if ($_.Exception.Message) { $_.Exception.Message } else { 'An unexpected error occurred.' }
Write-Error "Restore operation failed: $errorMessage"
Show-MessageBox -Title 'Error' -Message "Restore failed: $errorMessage" -Icon Error
+ return [PSCustomObject]@{
+ RestoredRegistry = $false
+ RestoredStartMenu = $false
+ }
}
}