mirror of
https://github.com/Raphire/Win11Debloat.git
synced 2026-05-18 11:46:18 +00:00
Add registry backup & restore (#566)
Starting from this commit, Win11Debloat will automatically create a registry backup every time the script is run. This registry backup can be used to revert any registry changes made by the script.
This commit is contained in:
121
Scripts/GUI/RestoreBackupDialogFeatureLists.ps1
Normal file
121
Scripts/GUI/RestoreBackupDialogFeatureLists.ps1
Normal file
@@ -0,0 +1,121 @@
|
||||
function New-RestoreDialogState {
|
||||
param(
|
||||
[string]$Result = 'Cancel',
|
||||
[string]$SelectedFile = $null,
|
||||
$Backup = $null
|
||||
)
|
||||
|
||||
return @{ Result = $Result; SelectedFile = $SelectedFile; Backup = $Backup }
|
||||
}
|
||||
|
||||
function Get-RestoreDialogFeatureDefinition {
|
||||
param(
|
||||
[string]$FeatureId,
|
||||
[hashtable]$Features
|
||||
)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($FeatureId) -or -not $Features) {
|
||||
return $null
|
||||
}
|
||||
|
||||
if ($Features.ContainsKey($FeatureId)) {
|
||||
return $Features[$FeatureId]
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Test-RestoreDialogFeatureCanAutoRevert {
|
||||
param(
|
||||
[string]$FeatureId,
|
||||
[hashtable]$Features
|
||||
)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($FeatureId)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
$featureDefinition = Get-RestoreDialogFeatureDefinition -FeatureId $FeatureId -Features $Features
|
||||
if ($featureDefinition) {
|
||||
return -not [string]::IsNullOrWhiteSpace([string]$featureDefinition.RegistryKey)
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
function Get-RestoreDialogFeatureDisplayLabel {
|
||||
param(
|
||||
[string]$FeatureId,
|
||||
[hashtable]$Features
|
||||
)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($FeatureId)) {
|
||||
return 'Unknown feature'
|
||||
}
|
||||
|
||||
$featureDefinition = Get-RestoreDialogFeatureDefinition -FeatureId $FeatureId -Features $Features
|
||||
if ($featureDefinition -and -not [string]::IsNullOrWhiteSpace([string]$featureDefinition.Label)) {
|
||||
return [string]$featureDefinition.Label
|
||||
}
|
||||
|
||||
return $FeatureId
|
||||
}
|
||||
|
||||
function Test-RestoreDialogFeatureVisibleInOverview {
|
||||
param(
|
||||
[string]$FeatureId,
|
||||
[hashtable]$Features
|
||||
)
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($FeatureId)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
$featureDefinition = Get-RestoreDialogFeatureDefinition -FeatureId $FeatureId -Features $Features
|
||||
if (-not $featureDefinition) {
|
||||
return $false
|
||||
}
|
||||
|
||||
return -not [string]::IsNullOrWhiteSpace([string]$featureDefinition.Category)
|
||||
}
|
||||
|
||||
function Get-SelectedFeatureIdsFromBackup {
|
||||
param($SelectedBackup)
|
||||
|
||||
return @(
|
||||
foreach ($featureId in @($SelectedBackup.SelectedFeatures)) {
|
||||
if (-not [string]::IsNullOrWhiteSpace([string]$featureId)) {
|
||||
[string]$featureId
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function Get-RestoreBackupFeatureLists {
|
||||
param(
|
||||
[string[]]$SelectedFeatureIds,
|
||||
[hashtable]$Features
|
||||
)
|
||||
|
||||
$revertibleFeaturesList = @()
|
||||
$nonRevertibleFeaturesList = @()
|
||||
|
||||
foreach ($featureId in $SelectedFeatureIds) {
|
||||
if (-not (Test-RestoreDialogFeatureVisibleInOverview -FeatureId $featureId -Features $Features)) {
|
||||
continue
|
||||
}
|
||||
|
||||
$displayItem = [PSCustomObject]@{ DisplayText = "- $(Get-RestoreDialogFeatureDisplayLabel -FeatureId $featureId -Features $Features)" }
|
||||
if (Test-RestoreDialogFeatureCanAutoRevert -FeatureId $featureId -Features $Features) {
|
||||
$revertibleFeaturesList += $displayItem
|
||||
}
|
||||
else {
|
||||
$nonRevertibleFeaturesList += $displayItem
|
||||
}
|
||||
}
|
||||
|
||||
return [PSCustomObject]@{
|
||||
Revertible = @($revertibleFeaturesList)
|
||||
NonRevertible = @($nonRevertibleFeaturesList)
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ function SetWindowThemeResources {
|
||||
$window.Resources.Add("ButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#3284cc")))
|
||||
$window.Resources.Add("CloseHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#c42b1c")))
|
||||
$window.Resources.Add("InformationIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#0078D4")))
|
||||
$window.Resources.Add("SuccessIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#107C10")))
|
||||
$window.Resources.Add("WarningIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFB900")))
|
||||
$window.Resources.Add("ErrorIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#E81123")))
|
||||
$window.Resources.Add("QuestionIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#0078D4")))
|
||||
|
||||
@@ -162,7 +162,7 @@ function Show-ApplyModal {
|
||||
foreach ($paramKey in $script:Params.Keys) {
|
||||
if ($script:Features.ContainsKey($paramKey) -and $script:Features[$paramKey].RequiresReboot -eq $true) {
|
||||
$feature = $script:Features[$paramKey]
|
||||
$rebootFeatures += "$($feature.Action) $($feature.Label)"
|
||||
$rebootFeatures += "$($feature.Label)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ function Show-ImportExportConfigWindow {
|
||||
[string]$Prompt,
|
||||
[string[]]$Categories = @('Applications', 'System Tweaks', 'Deployment Settings'),
|
||||
[string[]]$DisabledCategories = @(),
|
||||
[hashtable]$CategoryDetails = @()
|
||||
[hashtable]$CategoryDetails = @(),
|
||||
[string]$ActionLabel = 'OK'
|
||||
)
|
||||
|
||||
# Show overlay on owner window
|
||||
@@ -105,6 +106,7 @@ function Show-ImportExportConfigWindow {
|
||||
|
||||
$okBtn = $dlg.FindName('OkButton')
|
||||
$cancelBtn = $dlg.FindName('CancelButton')
|
||||
$okBtn.Content = $ActionLabel
|
||||
$okBtn.Add_Click({ $dlg.Tag = 'OK'; $dlg.Close() })
|
||||
$cancelBtn.Add_Click({ $dlg.Tag = 'Cancel'; $dlg.Close() })
|
||||
|
||||
@@ -379,8 +381,11 @@ function Export-Configuration {
|
||||
$deploymentSettings = Get-DeploymentSettings -Owner $Owner -UserSelectionCombo $UserSelectionCombo -OtherUsernameTextBox $OtherUsernameTextBox
|
||||
$categoryDetails = Build-CategoryDetails -AppCount $selectedApps.Count -TweakCount $tweakSettings.Count -DeploymentSettings $deploymentSettings
|
||||
|
||||
$categories = Show-ImportExportConfigWindow -Owner $Owner -UsesDarkMode $UsesDarkMode -Title 'Export Configuration' -Prompt 'Select which settings to include in the export:' -DisabledCategories $disabledCategories -CategoryDetails $categoryDetails
|
||||
if (-not $categories) { return }
|
||||
$categories = Show-ImportExportConfigWindow -Owner $Owner -UsesDarkMode $UsesDarkMode -Title 'Export Configuration' -Prompt 'Select the settings you wish to include in your export.' -DisabledCategories $disabledCategories -CategoryDetails $categoryDetails -ActionLabel 'Export Settings'
|
||||
if (-not $categories) {
|
||||
Write-Host 'Export canceled.'
|
||||
return
|
||||
}
|
||||
|
||||
$config = @{ Version = '1.0' }
|
||||
|
||||
@@ -401,12 +406,19 @@ function Export-Configuration {
|
||||
$saveDialog.DefaultExt = '.json'
|
||||
$saveDialog.FileName = "Win11Debloat-Config-$(Get-Date -Format 'yyyyMMdd').json"
|
||||
|
||||
if ($saveDialog.ShowDialog($Owner) -ne $true) { return }
|
||||
if ($saveDialog.ShowDialog($Owner) -ne $true) {
|
||||
Write-Host 'Export save dialog canceled.'
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Exporting configuration to '$($saveDialog.FileName)'... (Categories: $($categories -join ', '))"
|
||||
|
||||
if (SaveToFile -Config $config -FilePath $saveDialog.FileName) {
|
||||
Write-Host "Configuration exported successfully: $($saveDialog.FileName)"
|
||||
Show-MessageBox -Message "Configuration exported successfully." -Title 'Export Configuration' -Button 'OK' -Icon 'Information' | Out-Null
|
||||
}
|
||||
else {
|
||||
Write-Error "Failed to export configuration to '$($saveDialog.FileName)'"
|
||||
Show-MessageBox -Message "Failed to export configuration" -Title 'Error' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
}
|
||||
}
|
||||
@@ -425,36 +437,49 @@ function Import-Configuration {
|
||||
|
||||
# Show native open-file dialog
|
||||
$openDialog = New-Object Microsoft.Win32.OpenFileDialog
|
||||
$openDialog.Title = 'Import Configuration'
|
||||
$openDialog.Title = 'Select Configuration File'
|
||||
$openDialog.Filter = 'JSON files (*.json)|*.json|All files (*.*)|*.*'
|
||||
$openDialog.DefaultExt = '.json'
|
||||
|
||||
if ($openDialog.ShowDialog($Owner) -ne $true) { return }
|
||||
if ($openDialog.ShowDialog($Owner) -ne $true) {
|
||||
Write-Host 'Import file dialog canceled.'
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Importing configuration from '$($openDialog.FileName)'..."
|
||||
|
||||
$config = LoadJsonFile -filePath $openDialog.FileName -expectedVersion '1.0'
|
||||
if (-not $config) {
|
||||
Show-MessageBox -Message "Failed to read configuration file" -Title 'Error' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
Write-Error "Failed to read configuration file '$($openDialog.FileName)'"
|
||||
Show-MessageBox -Message "Failed to read configuration file" -Title 'Invalid Config' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $config.Version) {
|
||||
Show-MessageBox -Message "Invalid configuration file format." -Title 'Error' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
Write-Error "Invalid configuration file format: '$($openDialog.FileName)'"
|
||||
Show-MessageBox -Message "Invalid configuration file format." -Title 'Invalid Config' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
$availableCategories = Get-AvailableImportExportCategories -Config $config
|
||||
|
||||
if ($availableCategories.Count -eq 0) {
|
||||
Show-MessageBox -Message "The configuration file contains no importable data." -Title 'Import Configuration' -Button 'OK' -Icon 'Information' | Out-Null
|
||||
Write-Warning "Configuration file '$($openDialog.FileName)' contains no importable data."
|
||||
Show-MessageBox -Message "The selected file contains no importable data." -Title 'Invalid Config' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Available categories in config: $($availableCategories -join ', ')"
|
||||
|
||||
$appCount = @($config.Apps | Where-Object { $_ -is [string] -and -not [string]::IsNullOrWhiteSpace($_) }).Count
|
||||
$tweakCount = @($config.Tweaks | Where-Object { $_ -and $_.Name -and $_.Value -eq $true }).Count
|
||||
$categoryDetails = Build-CategoryDetails -AppCount $appCount -TweakCount $tweakCount -DeploymentSettings @($config.Deployment)
|
||||
|
||||
$categories = Show-ImportExportConfigWindow -Owner $Owner -UsesDarkMode $UsesDarkMode -Title 'Import Configuration' -Prompt 'Select which settings to import:' -Categories $availableCategories -CategoryDetails $categoryDetails
|
||||
if (-not $categories) { return }
|
||||
$categories = Show-ImportExportConfigWindow -Owner $Owner -UsesDarkMode $UsesDarkMode -Title 'Import Configuration' -Prompt 'Select the settings you wish to import. You can review and modify them before they are applied.' -Categories $availableCategories -CategoryDetails $categoryDetails -ActionLabel 'Import Settings'
|
||||
if (-not $categories) {
|
||||
Write-Host 'Import canceled.'
|
||||
return
|
||||
}
|
||||
|
||||
if ($categories -contains 'Applications' -and $config.Apps) {
|
||||
$appIds = @(
|
||||
@@ -464,6 +489,7 @@ function Import-Configuration {
|
||||
Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
||||
)
|
||||
|
||||
Write-Host "Importing $($appIds.Count) app selection(s)."
|
||||
Apply-ImportedApplications -AppsPanel $AppsPanel -AppIds $appIds
|
||||
|
||||
if ($OnAppsImported) {
|
||||
@@ -471,12 +497,16 @@ function Import-Configuration {
|
||||
}
|
||||
}
|
||||
if ($categories -contains 'System Tweaks' -and $config.Tweaks) {
|
||||
$tweakCount = @($config.Tweaks).Count
|
||||
Write-Host "Importing $tweakCount tweak(s)."
|
||||
Apply-ImportedTweakSettings -Owner $Owner -UiControlMappings $UiControlMappings -TweakSettings @($config.Tweaks)
|
||||
}
|
||||
if ($categories -contains 'Deployment Settings' -and $config.Deployment) {
|
||||
Write-Host 'Importing deployment settings.'
|
||||
Apply-ImportedDeploymentSettings -Owner $Owner -UserSelectionCombo $UserSelectionCombo -OtherUsernameTextBox $OtherUsernameTextBox -DeploymentSettings @($config.Deployment)
|
||||
}
|
||||
|
||||
Write-Host 'Configuration imported successfully.'
|
||||
Show-MessageBox -Message "Configuration imported successfully." -Title 'Import Configuration' -Button 'OK' -Icon 'Information' | Out-Null
|
||||
|
||||
if ($OnImportCompleted) {
|
||||
|
||||
@@ -96,6 +96,7 @@ function Show-MainWindow {
|
||||
$menuAbout = $window.FindName('MenuAbout')
|
||||
$importConfigBtn = $window.FindName('ImportConfigBtn')
|
||||
$exportConfigBtn = $window.FindName('ExportConfigBtn')
|
||||
$restoreBackupBtn = $window.FindName('RestoreBackupBtn')
|
||||
|
||||
$windowStateNormal = [System.Windows.WindowState]::Normal
|
||||
$windowStateMaximized = [System.Windows.WindowState]::Maximized
|
||||
@@ -234,7 +235,7 @@ function Show-MainWindow {
|
||||
})
|
||||
|
||||
$menuLogs.Add_Click({
|
||||
$logsFolder = Join-Path $PSScriptRoot "../../Logs"
|
||||
$logsFolder = Join-Path (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) 'Logs'
|
||||
if (Test-Path $logsFolder) {
|
||||
Start-Process "explorer.exe" -ArgumentList $logsFolder
|
||||
}
|
||||
@@ -247,22 +248,45 @@ function Show-MainWindow {
|
||||
Show-AboutDialog -Owner $window
|
||||
})
|
||||
|
||||
# --- Import/Export Configuration ---
|
||||
$exportConfigBtn.Add_Click({
|
||||
Export-Configuration -Owner $window -UsesDarkMode $usesDarkMode -AppsPanel $appsPanel -UiControlMappings $script:UiControlMappings -UserSelectionCombo $userSelectionCombo -OtherUsernameTextBox $otherUsernameTextBox
|
||||
try {
|
||||
Export-Configuration -Owner $window -UsesDarkMode $usesDarkMode -AppsPanel $appsPanel -UiControlMappings $script:UiControlMappings -UserSelectionCombo $userSelectionCombo -OtherUsernameTextBox $otherUsernameTextBox
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Export configuration failed: $($_.Exception.Message)"
|
||||
Show-MessageBox -Owner $window -Message "Unable to open export configuration dialog: $($_.Exception.Message)" -Title 'Export Configuration Failed' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
}
|
||||
})
|
||||
|
||||
$importConfigBtn.Add_Click({
|
||||
Import-Configuration -Owner $window -UsesDarkMode $usesDarkMode -AppsPanel $appsPanel -UiControlMappings $script:UiControlMappings -UserSelectionCombo $userSelectionCombo -OtherUsernameTextBox $otherUsernameTextBox -OnAppsImported { UpdateAppSelectionStatus; UpdatePresetStates } -OnImportCompleted {
|
||||
$tabControl.SelectedIndex = 3
|
||||
UpdateNavigationButtons
|
||||
try {
|
||||
Import-Configuration -Owner $window -UsesDarkMode $usesDarkMode -AppsPanel $appsPanel -UiControlMappings $script:UiControlMappings -UserSelectionCombo $userSelectionCombo -OtherUsernameTextBox $otherUsernameTextBox -OnAppsImported { UpdateAppSelectionStatus; UpdatePresetStates } -OnImportCompleted {
|
||||
$tabControl.SelectedIndex = 3
|
||||
UpdateNavigationButtons
|
||||
|
||||
$window.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Loaded, [action]{
|
||||
Show-Bubble -TargetControl $reviewChangesBtn -Message 'View the selected changes here'
|
||||
}) | Out-Null
|
||||
$window.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Loaded, [action]{
|
||||
Show-Bubble -TargetControl $reviewChangesBtn -Message 'View the selected changes here'
|
||||
}) | Out-Null
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Import configuration failed: $($_.Exception.Message)"
|
||||
Show-MessageBox -Owner $window -Message "Unable to open import configuration dialog: $($_.Exception.Message)" -Title 'Import Configuration Failed' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
}
|
||||
})
|
||||
|
||||
if ($restoreBackupBtn) {
|
||||
$restoreBackupBtn.Add_Click({
|
||||
try {
|
||||
Show-RestoreBackupWindow -Owner $window
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Restore backup action failed: $($_.Exception.Message)"
|
||||
Show-MessageBox -Owner $window -Message "Unable to open restore backup dialog: $($_.Exception.Message)" -Title 'Restore Backup Failed' -Button 'OK' -Icon 'Error' | Out-Null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$closeBtn.Add_Click({
|
||||
$window.Close()
|
||||
})
|
||||
@@ -352,6 +376,20 @@ function Show-MainWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function ClearTweakSelections {
|
||||
if (-not $script:UiControlMappings) { return }
|
||||
|
||||
foreach ($controlName in $script:UiControlMappings.Keys) {
|
||||
$control = $window.FindName($controlName)
|
||||
if ($control -is [System.Windows.Controls.CheckBox]) {
|
||||
$control.IsChecked = $false
|
||||
}
|
||||
elseif ($control -is [System.Windows.Controls.ComboBox]) {
|
||||
$control.SelectedIndex = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function AnimateDropdownArrow {
|
||||
param(
|
||||
[System.Windows.Controls.TextBlock]$arrow,
|
||||
@@ -843,7 +881,7 @@ function Show-MainWindow {
|
||||
if ($feature.FeatureId -match '^Disable') { $opt = 'Disable' } elseif ($feature.FeatureId -match '^Enable') { $opt = 'Enable' }
|
||||
$items = @('No Change', $opt)
|
||||
$comboName = ("Feature_{0}_Combo" -f $feature.FeatureId) -replace '[^a-zA-Z0-9_]',''
|
||||
$combo = CreateLabeledCombo -parent $panel -labelText ($feature.Action + ' ' + $feature.Label) -comboName $comboName -items $items
|
||||
$combo = CreateLabeledCombo -parent $panel -labelText $feature.Label -comboName $comboName -items $items
|
||||
# attach tooltip from Features.json if present
|
||||
if ($feature.ToolTip) {
|
||||
$tipBlock = New-Object System.Windows.Controls.TextBlock
|
||||
@@ -855,7 +893,7 @@ function Show-MainWindow {
|
||||
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
|
||||
if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
|
||||
}
|
||||
$script:UiControlMappings[$comboName] = @{ Type='feature'; FeatureId = $feature.FeatureId; Action = $feature.Action; Label = $feature.Label; Category = $categoryName }
|
||||
$script:UiControlMappings[$comboName] = @{ Type='feature'; FeatureId = $feature.FeatureId; Label = $feature.Label; Category = $categoryName }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -863,7 +901,7 @@ function Show-MainWindow {
|
||||
# Build a feature-label lookup so GenerateOverview can resolve feature IDs without reloading JSON
|
||||
$script:FeatureLabelLookup = @{}
|
||||
foreach ($f in $featuresJson.Features) {
|
||||
$script:FeatureLabelLookup[$f.FeatureId] = $f.Action + ' ' + $f.Label
|
||||
$script:FeatureLabelLookup[$f.FeatureId] = $f.Label
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,8 +1546,6 @@ function Show-MainWindow {
|
||||
# Show "Current user only" option, hide "Target user only" option
|
||||
$appRemovalScopeCurrentUser.Visibility = 'Visible'
|
||||
$appRemovalScopeTargetUser.Visibility = 'Collapsed'
|
||||
# Enable app removal scope selection for current user
|
||||
$appRemovalScopeCombo.IsEnabled = $true
|
||||
$appRemovalScopeCombo.SelectedIndex = 0
|
||||
}
|
||||
1 {
|
||||
@@ -1519,8 +1555,6 @@ function Show-MainWindow {
|
||||
# Hide "Current user only" option, show "Target user only" option
|
||||
$appRemovalScopeCurrentUser.Visibility = 'Collapsed'
|
||||
$appRemovalScopeTargetUser.Visibility = 'Visible'
|
||||
# Enable app removal scope selection for other user
|
||||
$appRemovalScopeCombo.IsEnabled = $true
|
||||
$appRemovalScopeCombo.SelectedIndex = 0
|
||||
}
|
||||
2 {
|
||||
@@ -1531,10 +1565,12 @@ function Show-MainWindow {
|
||||
$appRemovalScopeCurrentUser.Visibility = 'Collapsed'
|
||||
$appRemovalScopeTargetUser.Visibility = 'Collapsed'
|
||||
# Lock app removal scope to "All users" when applying to sysprep
|
||||
$appRemovalScopeCombo.IsEnabled = $false
|
||||
$appRemovalScopeCombo.SelectedIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
# Keep enabled/disabled state in sync with both app selection and user mode.
|
||||
UpdateAppSelectionStatus
|
||||
})
|
||||
|
||||
# Helper function to update app removal scope description
|
||||
@@ -1577,38 +1613,16 @@ function Show-MainWindow {
|
||||
return $true
|
||||
}
|
||||
|
||||
$username = $otherUsernameTextBox.Text.Trim()
|
||||
|
||||
$errorBrush = $window.Resources['ValidationErrorColor']
|
||||
$successBrush = $window.Resources['ValidationSuccessColor']
|
||||
$validationResult = Test-TargetUserName -UserName $otherUsernameTextBox.Text
|
||||
|
||||
if ($username.Length -eq 0) {
|
||||
$usernameValidationMessage.Text = "Please enter a username"
|
||||
$usernameValidationMessage.Foreground = $errorBrush
|
||||
return $false
|
||||
}
|
||||
|
||||
if ($username -eq $env:USERNAME) {
|
||||
$usernameValidationMessage.Text = "Cannot enter your own username, use 'Current User' option instead"
|
||||
$usernameValidationMessage.Foreground = $errorBrush
|
||||
return $false
|
||||
}
|
||||
|
||||
$userExists = CheckIfUserExists -Username $username
|
||||
|
||||
if ($userExists) {
|
||||
if (TestIfUserIsLoggedIn -Username $username) {
|
||||
$usernameValidationMessage.Text = "User '$username' is currently logged in. Please sign out that user first."
|
||||
$usernameValidationMessage.Foreground = $errorBrush
|
||||
return $false
|
||||
}
|
||||
|
||||
$usernameValidationMessage.Text = "User found: $username"
|
||||
$usernameValidationMessage.Text = $validationResult.Message
|
||||
if ($validationResult.IsValid) {
|
||||
$usernameValidationMessage.Foreground = $successBrush
|
||||
return $true
|
||||
}
|
||||
|
||||
$usernameValidationMessage.Text = "User not found, please enter a valid username"
|
||||
$usernameValidationMessage.Foreground = $errorBrush
|
||||
return $false
|
||||
}
|
||||
@@ -1655,7 +1669,7 @@ function Show-MainWindow {
|
||||
}
|
||||
elseif ($mapping.Type -eq 'feature') {
|
||||
$label = $script:FeatureLabelLookup[$mapping.FeatureId]
|
||||
if (-not $label) { $label = $mapping.Action + ' ' + $mapping.Label }
|
||||
if (-not $label) { $label = $mapping.Label }
|
||||
$changesList += $label
|
||||
}
|
||||
}
|
||||
@@ -2210,18 +2224,7 @@ function Show-MainWindow {
|
||||
# Clear All Tweaks button
|
||||
$clearAllTweaksBtn = $window.FindName('ClearAllTweaksBtn')
|
||||
$clearAllTweaksBtn.Add_Click({
|
||||
# Reset all ComboBoxes to index 0 (No Change) and uncheck all CheckBoxes
|
||||
if ($script:UiControlMappings) {
|
||||
foreach ($comboName in $script:UiControlMappings.Keys) {
|
||||
$control = $window.FindName($comboName)
|
||||
if ($control -is [System.Windows.Controls.CheckBox]) {
|
||||
$control.IsChecked = $false
|
||||
}
|
||||
elseif ($control -is [System.Windows.Controls.ComboBox]) {
|
||||
$control.SelectedIndex = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
ClearTweakSelections
|
||||
UpdateTweakPresetStates
|
||||
})
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ function Show-MessageBox {
|
||||
[string]$Button = 'OK',
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateSet('None', 'Information', 'Warning', 'Error', 'Question')]
|
||||
[ValidateSet('None', 'Information', 'Success', 'Warning', 'Error', 'Question')]
|
||||
[string]$Icon = 'None',
|
||||
|
||||
[Parameter(Mandatory=$false)]
|
||||
@@ -90,6 +90,11 @@ function Show-MessageBox {
|
||||
$iconText.Foreground = $msgWindow.FindResource('InformationIconColor')
|
||||
$iconText.Visibility = 'Visible'
|
||||
}
|
||||
'Success' {
|
||||
$iconText.Text = [char]0xE73E
|
||||
$iconText.Foreground = $msgWindow.FindResource('SuccessIconColor')
|
||||
$iconText.Visibility = 'Visible'
|
||||
}
|
||||
'Warning' {
|
||||
$iconText.Text = [char]0xE7BA
|
||||
$iconText.Foreground = $msgWindow.FindResource('WarningIconColor')
|
||||
|
||||
403
Scripts/GUI/Show-RestoreBackupDialog.ps1
Normal file
403
Scripts/GUI/Show-RestoreBackupDialog.ps1
Normal file
@@ -0,0 +1,403 @@
|
||||
function Show-RestoreBackupDialog {
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[System.Windows.Window]$Owner = $null
|
||||
)
|
||||
|
||||
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
|
||||
|
||||
$usesDarkMode = GetSystemUsesDarkMode
|
||||
$ownerWindow = if ($Owner) { $Owner } else { $script:GuiWindow }
|
||||
|
||||
$overlay = $null
|
||||
$overlayWasAlreadyVisible = $false
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$overlay = $ownerWindow.FindName('ModalOverlay')
|
||||
if ($overlay) {
|
||||
$overlayWasAlreadyVisible = ($overlay.Visibility -eq 'Visible')
|
||||
if (-not $overlayWasAlreadyVisible) {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
$schemaPath = $script:RestoreBackupWindowSchema
|
||||
if (-not $schemaPath -or -not (Test-Path $schemaPath)) {
|
||||
throw 'Restore backup window schema file could not be found.'
|
||||
}
|
||||
|
||||
$xaml = Get-Content -Path $schemaPath -Raw
|
||||
|
||||
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
|
||||
try {
|
||||
$window = [System.Windows.Markup.XamlReader]::Load($reader)
|
||||
}
|
||||
finally {
|
||||
$reader.Close()
|
||||
}
|
||||
|
||||
if ($ownerWindow) {
|
||||
try {
|
||||
$window.Owner = $ownerWindow
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
try {
|
||||
SetWindowThemeResources -window $window -usesDarkMode $usesDarkMode
|
||||
}
|
||||
catch { }
|
||||
|
||||
$titleBar = $window.FindName('TitleBar')
|
||||
$titleText = $window.FindName('TitleText')
|
||||
$closeBtn = $window.FindName('CloseBtn')
|
||||
$backBtn = $window.FindName('BackBtn')
|
||||
$primaryActionBtn = $window.FindName('PrimaryActionBtn')
|
||||
$chooseRegistryBtn = $window.FindName('ChooseRegistryBtn')
|
||||
$chooseStartMenuBtn = $window.FindName('ChooseStartMenuBtn')
|
||||
$restoreModeTabs = $window.FindName('RestoreModeTabs')
|
||||
$startMenuIntroPanel = $window.FindName('StartMenuIntroPanel')
|
||||
$startMenuScopeCombo = $window.FindName('StartMenuScopeCombo')
|
||||
$startMenuAutoBackupCheck = $window.FindName('StartMenuAutoBackupCheck')
|
||||
$introInfoPanel = $window.FindName('IntroInfoPanel')
|
||||
$overviewPanel = $window.FindName('OverviewPanel')
|
||||
$overviewFeaturesSection = $window.FindName('OverviewFeaturesSection')
|
||||
$overviewSummaryText = $window.FindName('OverviewSummaryText')
|
||||
$backupFileText = $window.FindName('BackupFileText')
|
||||
$backupCreatedText = $window.FindName('BackupCreatedText')
|
||||
$backupTargetText = $window.FindName('BackupTargetText')
|
||||
$featuresItemsControl = $window.FindName('FeaturesItemsControl')
|
||||
$nonRevertibleSeparator = $window.FindName('NonRevertibleSeparator')
|
||||
$nonRevertiblePanel = $window.FindName('NonRevertiblePanel')
|
||||
$nonRevertibleFeaturesItemsControl = $window.FindName('NonRevertibleFeaturesItemsControl')
|
||||
$nonRevertibleWikiLink = $window.FindName('NonRevertibleWikiLink')
|
||||
|
||||
$titleBar.Add_MouseLeftButtonDown({ $window.DragMove() })
|
||||
$window.Tag = New-RestoreDialogState
|
||||
$chooseRegistryBtn.IsDefault = $true
|
||||
|
||||
$state = @{ WizardStep = 'SelectType'; SelectedRegistryBackup = $null; SelectedStartMenuBackupFilePath = $null }
|
||||
|
||||
$getStartMenuScopeInfo = {
|
||||
$isAllUsersScope = ($startMenuScopeCombo.SelectedItem.Tag -eq 'AllUsers')
|
||||
$scopeValue = if ($isAllUsersScope) { 'AllUsers' } else { 'CurrentUser' }
|
||||
$summaryScopeText = if ($isAllUsersScope) { 'all users' } else { 'the current user' }
|
||||
|
||||
return [PSCustomObject]@{
|
||||
Scope = $scopeValue
|
||||
Target = $scopeValue
|
||||
SummaryText = $summaryScopeText
|
||||
}
|
||||
}
|
||||
|
||||
$showStartMenuIntroState = {
|
||||
$backupFileText.Text = 'Not selected'
|
||||
$backupCreatedText.Text = 'N/A'
|
||||
$overviewSummaryText.Visibility = 'Collapsed'
|
||||
$overviewPanel.Visibility = 'Collapsed'
|
||||
$startMenuIntroPanel.Visibility = 'Visible'
|
||||
$restoreModeTabs.SelectedIndex = 2
|
||||
}
|
||||
|
||||
$showStartMenuOverviewState = {
|
||||
param([string]$BackupFilePath)
|
||||
|
||||
$scopeInfo = & $getStartMenuScopeInfo
|
||||
$backupTargetText.Text = GetFriendlyRegistryBackupTarget -Target $scopeInfo.Target
|
||||
$overviewSummaryText.Text = "This will replace the current Start Menu pinned apps layout for $($scopeInfo.SummaryText) with the selected backup."
|
||||
$backupFileText.Text = Split-Path -Path $BackupFilePath -Leaf
|
||||
|
||||
$createdText = 'Unknown'
|
||||
try {
|
||||
$createdText = (Get-Item -LiteralPath $BackupFilePath -ErrorAction Stop).LastWriteTime.ToString('yyyy-MM-dd HH:mm')
|
||||
}
|
||||
catch { }
|
||||
$backupCreatedText.Text = $createdText
|
||||
|
||||
$overviewFeaturesSection.Visibility = 'Collapsed'
|
||||
$overviewSummaryText.Visibility = 'Visible'
|
||||
$nonRevertibleSeparator.Visibility = 'Collapsed'
|
||||
$nonRevertiblePanel.Visibility = 'Collapsed'
|
||||
$introInfoPanel.Visibility = 'Collapsed'
|
||||
$overviewPanel.Visibility = 'Visible'
|
||||
$restoreModeTabs.SelectedIndex = 1
|
||||
}
|
||||
|
||||
$updateStartMenuOverviewPanel = {
|
||||
if ($state.WizardStep -ne 'StartMenu') {
|
||||
return
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($state.SelectedStartMenuBackupFilePath)) {
|
||||
& $showStartMenuIntroState
|
||||
return
|
||||
}
|
||||
|
||||
& $showStartMenuOverviewState $state.SelectedStartMenuBackupFilePath
|
||||
}
|
||||
|
||||
$updateStartMenuPrimaryActionText = {
|
||||
if ($state.WizardStep -ne 'StartMenu') {
|
||||
return
|
||||
}
|
||||
|
||||
$isAutoBackupEnabled = ($startMenuAutoBackupCheck.IsChecked -eq $true)
|
||||
$hasSelectedManualFile = -not [string]::IsNullOrWhiteSpace($state.SelectedStartMenuBackupFilePath)
|
||||
if ($isAutoBackupEnabled -or $hasSelectedManualFile) {
|
||||
$primaryActionBtn.Content = 'Restore backup'
|
||||
}
|
||||
else {
|
||||
$primaryActionBtn.Content = 'Select backup file'
|
||||
}
|
||||
}
|
||||
|
||||
$refreshStartMenuUi = {
|
||||
& $updateStartMenuOverviewPanel
|
||||
& $updateStartMenuPrimaryActionText
|
||||
}
|
||||
|
||||
$enterSelectTypeStep = {
|
||||
$titleText.Text = 'Restore Backup'
|
||||
$restoreModeTabs.SelectedIndex = 0
|
||||
$backBtn.Visibility = 'Visible'
|
||||
$backBtn.Content = 'Cancel'
|
||||
$primaryActionBtn.Visibility = 'Collapsed'
|
||||
$chooseRegistryBtn.IsDefault = $true
|
||||
$primaryActionBtn.IsDefault = $false
|
||||
}
|
||||
|
||||
$enterRegistryStep = {
|
||||
$titleText.Text = 'Restore Registry Backup'
|
||||
$restoreModeTabs.SelectedIndex = 1
|
||||
$introInfoPanel.Visibility = 'Visible'
|
||||
$overviewPanel.Visibility = 'Collapsed'
|
||||
$overviewFeaturesSection.Visibility = 'Visible'
|
||||
$overviewSummaryText.Visibility = 'Collapsed'
|
||||
$backBtn.Visibility = 'Visible'
|
||||
$backBtn.Content = 'Back'
|
||||
$primaryActionBtn.Visibility = 'Visible'
|
||||
$primaryActionBtn.Content = 'Select backup file'
|
||||
$primaryActionBtn.IsDefault = $true
|
||||
$chooseRegistryBtn.IsDefault = $false
|
||||
}
|
||||
|
||||
$enterStartMenuStep = {
|
||||
$titleText.Text = 'Restore Start Menu Backup'
|
||||
$restoreModeTabs.SelectedIndex = 2
|
||||
$backBtn.Visibility = 'Visible'
|
||||
$backBtn.Content = 'Back'
|
||||
$primaryActionBtn.Visibility = 'Visible'
|
||||
$primaryActionBtn.IsDefault = $true
|
||||
$chooseRegistryBtn.IsDefault = $false
|
||||
& $refreshStartMenuUi
|
||||
}
|
||||
|
||||
$showRegistryOverview = {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
$SelectedBackup,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SelectedBackupFilePath
|
||||
)
|
||||
|
||||
$createdText = if ([string]::IsNullOrWhiteSpace($SelectedBackup.CreatedAt)) {
|
||||
'Unknown'
|
||||
}
|
||||
else {
|
||||
try {
|
||||
[DateTime]::Parse($SelectedBackup.CreatedAt).ToString('yyyy-MM-dd HH:mm')
|
||||
}
|
||||
catch {
|
||||
$SelectedBackup.CreatedAt
|
||||
}
|
||||
}
|
||||
|
||||
$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)"
|
||||
|
||||
if ($revertibleFeaturesList.Count -eq 0) {
|
||||
throw 'The selected backup does not contain any changes that can be restored.'
|
||||
}
|
||||
|
||||
$backupFileText.Text = Split-Path $SelectedBackupFilePath -Leaf
|
||||
$backupCreatedText.Text = $createdText
|
||||
$backupTargetText.Text = GetFriendlyRegistryBackupTarget -Target ([string]$SelectedBackup.Target)
|
||||
$featuresItemsControl.ItemsSource = $revertibleFeaturesList
|
||||
$overviewFeaturesSection.Visibility = 'Visible'
|
||||
$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' }
|
||||
$introInfoPanel.Visibility = 'Collapsed'
|
||||
$overviewPanel.Visibility = 'Visible'
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
$handleRegistryPrimaryAction = {
|
||||
if ($state.SelectedRegistryBackup) {
|
||||
$window.Tag = @{
|
||||
Result = 'RestoreRegistry'
|
||||
Backup = $state.SelectedRegistryBackup
|
||||
}
|
||||
$window.DialogResult = $true
|
||||
$window.Close()
|
||||
return
|
||||
}
|
||||
|
||||
$openDialog = New-Object Microsoft.Win32.OpenFileDialog
|
||||
$openDialog.Title = 'Select Registry Backup File'
|
||||
$openDialog.Filter = 'Registry backup (*.json)|*.json|All files (*.*)|*.*'
|
||||
$openDialog.DefaultExt = '.json'
|
||||
$openDialog.InitialDirectory = $script:RegistryBackupsPath
|
||||
|
||||
if ($openDialog.ShowDialog($window) -ne $true) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Backup file selected: $($openDialog.FileName)"
|
||||
$selectedBackup = Load-RegistryBackupFromFile -FilePath $openDialog.FileName
|
||||
|
||||
if (-not (& $showRegistryOverview -SelectedBackup $selectedBackup -SelectedBackupFilePath $openDialog.FileName)) {
|
||||
return
|
||||
}
|
||||
|
||||
$state.SelectedRegistryBackup = $selectedBackup
|
||||
$primaryActionBtn.Content = 'Restore from backup'
|
||||
}
|
||||
|
||||
$handleStartMenuPrimaryAction = {
|
||||
$scope = (& $getStartMenuScopeInfo).Scope
|
||||
$useManualBackupFile = -not ($startMenuAutoBackupCheck.IsChecked -eq $true)
|
||||
|
||||
if ($useManualBackupFile -and [string]::IsNullOrWhiteSpace($state.SelectedStartMenuBackupFilePath)) {
|
||||
$openDialog = New-Object Microsoft.Win32.OpenFileDialog
|
||||
$openDialog.Title = 'Select Start Menu Backup File'
|
||||
$openDialog.Filter = 'Start Menu backup (*.bak)|*.bak'
|
||||
$openDialog.InitialDirectory = "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState"
|
||||
$openDialog.DefaultExt = '.bak'
|
||||
|
||||
if ($openDialog.ShowDialog($window) -ne $true) {
|
||||
return
|
||||
}
|
||||
|
||||
$state.SelectedStartMenuBackupFilePath = $openDialog.FileName
|
||||
Write-Host "Selected Start Menu backup file: $($state.SelectedStartMenuBackupFilePath)"
|
||||
& $refreshStartMenuUi
|
||||
return
|
||||
}
|
||||
|
||||
$window.Tag = @{
|
||||
Result = 'RestoreStartMenu'
|
||||
StartMenuScope = $scope
|
||||
UseManualBackupFile = $useManualBackupFile
|
||||
BackupFilePath = $state.SelectedStartMenuBackupFilePath
|
||||
}
|
||||
$window.DialogResult = $true
|
||||
$window.Close()
|
||||
}
|
||||
|
||||
$setWizardStep = {
|
||||
param([string]$step)
|
||||
|
||||
$state.WizardStep = $step
|
||||
|
||||
switch ($step) {
|
||||
'SelectType' { & $enterSelectTypeStep }
|
||||
'Registry' { & $enterRegistryStep }
|
||||
'StartMenu' { & $enterStartMenuStep }
|
||||
}
|
||||
}
|
||||
|
||||
$startMenuAutoBackupCheck.Add_Checked({
|
||||
$state.SelectedStartMenuBackupFilePath = $null
|
||||
& $refreshStartMenuUi
|
||||
})
|
||||
$startMenuAutoBackupCheck.Add_Unchecked({
|
||||
& $refreshStartMenuUi
|
||||
})
|
||||
|
||||
$startMenuScopeCombo.Add_SelectionChanged({
|
||||
& $refreshStartMenuUi
|
||||
})
|
||||
|
||||
$nonRevertibleWikiLink.Add_MouseLeftButtonUp({
|
||||
try {
|
||||
Start-Process 'https://github.com/Raphire/Win11Debloat/wiki/Reverting-Changes' | Out-Null
|
||||
}
|
||||
catch { }
|
||||
})
|
||||
|
||||
$closeBtn.Add_Click({
|
||||
$window.Tag = New-RestoreDialogState
|
||||
$window.DialogResult = $false
|
||||
$window.Close()
|
||||
})
|
||||
|
||||
$chooseRegistryBtn.Add_Click({ & $setWizardStep 'Registry' })
|
||||
$chooseStartMenuBtn.Add_Click({ & $setWizardStep 'StartMenu' })
|
||||
|
||||
$backBtn.Add_Click({
|
||||
if ($state.WizardStep -eq 'SelectType') {
|
||||
$window.Tag = New-RestoreDialogState
|
||||
$window.DialogResult = $false
|
||||
$window.Close()
|
||||
return
|
||||
}
|
||||
|
||||
if ($state.WizardStep -eq 'Registry') {
|
||||
$state.SelectedRegistryBackup = $null
|
||||
}
|
||||
|
||||
if ($state.WizardStep -eq 'StartMenu') {
|
||||
$state.SelectedStartMenuBackupFilePath = $null
|
||||
$startMenuAutoBackupCheck.IsChecked = $true
|
||||
}
|
||||
|
||||
& $setWizardStep 'SelectType'
|
||||
})
|
||||
|
||||
$primaryActionBtn.Add_Click({
|
||||
switch ($state.WizardStep) {
|
||||
'Registry' { & $handleRegistryPrimaryAction }
|
||||
'StartMenu' { & $handleStartMenuPrimaryAction }
|
||||
}
|
||||
})
|
||||
|
||||
$window.Add_KeyDown({
|
||||
param($source, $e)
|
||||
if ($e.Key -eq 'Escape') {
|
||||
$window.Tag = New-RestoreDialogState
|
||||
$window.DialogResult = $false
|
||||
$window.Close()
|
||||
}
|
||||
})
|
||||
|
||||
& $setWizardStep 'SelectType'
|
||||
|
||||
try {
|
||||
$null = $window.ShowDialog()
|
||||
}
|
||||
catch {
|
||||
$innerMessage = if ($_.Exception.InnerException) { $_.Exception.InnerException.Message } else { 'None' }
|
||||
throw "Failed to show restore backup dialog. Error: $($_.Exception.Message) Inner: $innerMessage"
|
||||
}
|
||||
finally {
|
||||
if ($overlay -and -not $overlayWasAlreadyVisible) {
|
||||
try {
|
||||
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
return $window.Tag
|
||||
}
|
||||
88
Scripts/GUI/Show-RestoreBackupWindow.ps1
Normal file
88
Scripts/GUI/Show-RestoreBackupWindow.ps1
Normal file
@@ -0,0 +1,88 @@
|
||||
function Show-RestoreBackupWindow {
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[System.Windows.Window]$Owner = $null
|
||||
)
|
||||
|
||||
try {
|
||||
Write-Host 'Opening restore backup dialog.'
|
||||
|
||||
$dialogResult = Show-RestoreBackupDialog -Owner $Owner
|
||||
if (-not $dialogResult -or $dialogResult.Result -eq 'Cancel') {
|
||||
Write-Host 'Restore canceled by user.'
|
||||
return
|
||||
}
|
||||
|
||||
$successMessage = $null
|
||||
$warningMessage = $null
|
||||
|
||||
if ($dialogResult.Result -eq 'RestoreRegistry') {
|
||||
$backup = $dialogResult.Backup
|
||||
if (-not $backup) {
|
||||
throw 'Registry backup restore requested without a selected backup.'
|
||||
}
|
||||
|
||||
Write-Host "User confirmed registry restore for $($backup.Target)."
|
||||
Restore-RegistryBackupState -Backup $backup
|
||||
$successMessage = 'Registry backup restored successfully.'
|
||||
}
|
||||
elseif ($dialogResult.Result -eq 'RestoreStartMenu') {
|
||||
$scope = $dialogResult.StartMenuScope
|
||||
$useManualBackupFile = ($dialogResult.UseManualBackupFile -eq $true)
|
||||
$backupFilePath = $null
|
||||
if ($dialogResult -is [hashtable] -and $dialogResult.ContainsKey('BackupFilePath')) {
|
||||
$backupFilePath = $dialogResult['BackupFilePath']
|
||||
}
|
||||
elseif ($dialogResult.PSObject.Properties.Match('BackupFilePath').Count -gt 0) {
|
||||
$backupFilePath = $dialogResult.BackupFilePath
|
||||
}
|
||||
|
||||
if ($useManualBackupFile -and [string]::IsNullOrWhiteSpace($backupFilePath)) {
|
||||
throw 'Start Menu restore canceled: no backup file selected.'
|
||||
}
|
||||
|
||||
$result = if ($scope -eq 'AllUsers') {
|
||||
RestoreStartMenuForAllUsers -BackupFilePath $backupFilePath
|
||||
}
|
||||
else {
|
||||
RestoreStartMenu -BackupFilePath $backupFilePath
|
||||
}
|
||||
|
||||
$resultEntries = @($result)
|
||||
$successCount = @($resultEntries | Where-Object { $_.Result -eq $true }).Count
|
||||
$failedEntries = @($resultEntries | Where-Object { $_.Result -ne $true })
|
||||
|
||||
if ($successCount -eq 0) {
|
||||
$errorSummary = ($resultEntries | ForEach-Object { $_.Message }) -join [Environment]::NewLine
|
||||
throw "Failed to restore the Start Menu backup.`n$errorSummary"
|
||||
}
|
||||
|
||||
if ($failedEntries.Count -gt 0) {
|
||||
$failureSummary = ($failedEntries | ForEach-Object { $_.Message }) -join [Environment]::NewLine
|
||||
$warningMessage = "The Start Menu backup was successfully restored for $successCount user(s).`nSome users could not be restored:`n$failureSummary"
|
||||
}
|
||||
else {
|
||||
if ($scope -eq 'AllUsers') {
|
||||
$successMessage = "The Start Menu backup was successfully restored for all users. The changes will apply the next time users sign in."
|
||||
}
|
||||
else {
|
||||
$successMessage = "The Start Menu backup was successfully restored for the current user. The changes will apply the next time you sign in."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($warningMessage) {
|
||||
Write-Host "$warningMessage"
|
||||
Show-MessageBox -Title 'Backup Restored' -Message $warningMessage -Icon Warning
|
||||
}
|
||||
elseif ($successMessage) {
|
||||
Write-Host "$successMessage"
|
||||
Show-MessageBox -Title 'Backup Restored' -Message $successMessage -Icon Success
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user