From e8c1401cce83dabde0c6cdfdc5551193fe1cc76e Mon Sep 17 00:00:00 2001 From: GabiNun2 Date: Sun, 21 Jun 2026 17:57:41 +0300 Subject: [PATCH] feat: add config-driven AppX package removal tab - Add config/appx.json with curated list of removable AppX packages - Add AppX Removal tab (WPFTab6) with Select All, Clear, and Remove buttons - Reuse existing Invoke-WPFUIElements engine for minimal code footprint - Add Invoke-WPFAppxRemoval.ps1 for background runspace package removal - Add theme colors for the new tab button in light and dark modes --- Compile.ps1 | 11 ++ config/appx.json | 146 ++++++++++++++++++ config/themes.json | 4 + functions/public/Invoke-WPFAppxRemoval.ps1 | 50 ++++++ functions/public/Invoke-WPFButton.ps1 | 17 ++ .../Invoke-WPFSelectedCheckboxesUpdate.ps1 | 11 ++ scripts/main.ps1 | 7 + scripts/start.ps1 | 1 + xaml/inputXML.xaml | 53 +++++++ 9 files changed, 300 insertions(+) create mode 100644 config/appx.json create mode 100644 functions/public/Invoke-WPFAppxRemoval.ps1 diff --git a/Compile.ps1 b/Compile.ps1 index 22f29bb6..f7935ea7 100644 --- a/Compile.ps1 +++ b/Compile.ps1 @@ -23,6 +23,17 @@ Get-ChildItem config | ForEach-Object { $obj = [pscustomobject]$fixed } + if ($_.Name -eq "appx.json") { + $fixed = [ordered]@{} + foreach ($p in $obj.PSObject.Properties) { + $keyName = "WPFAppx$($p.Name -replace '\.', '_')" + $val = $p.Value + $val | Add-Member -MemberType NoteProperty -Name "PackageId" -Value $p.Name -Force + $fixed[$keyName] = $val + } + $obj = [pscustomobject]$fixed + } + $json = $obj | ConvertTo-Json -Depth 10 $sync.configs[$_.BaseName] = $obj diff --git a/config/appx.json b/config/appx.json new file mode 100644 index 00000000..17fdc9d6 --- /dev/null +++ b/config/appx.json @@ -0,0 +1,146 @@ +{ + "Microsoft.WindowsFeedbackHub": { + "Category": "Telemetry & Diagnostics", + "Content": "Feedback Hub", + "Description": "Feedback Hub is a Microsoft application for gathering user feedback on Windows.", + "Panel": "0" + }, + "Microsoft.BingNews": { + "Category": "Bing & Web Services", + "Content": "Bing News", + "Description": "Pre-installed Bing News application.", + "Panel": "0" + }, + "Microsoft.BingSearch": { + "Category": "Bing & Web Services", + "Content": "Bing Search", + "Description": "Pre-installed Bing Search application.", + "Panel": "0" + }, + "Microsoft.BingWeather": { + "Category": "Bing & Web Services", + "Content": "Bing Weather", + "Description": "Pre-installed Bing Weather application.", + "Panel": "0" + }, + "Clipchamp.Clipchamp": { + "Category": "Microsoft Apps", + "Content": "Clipchamp", + "Description": "Clipchamp is Microsoft's pre-installed video editor.", + "Panel": "1" + }, + "Microsoft.Todos": { + "Category": "Utilities & Productivity", + "Content": "To Do", + "Description": "Microsoft To Do task manager application.", + "Panel": "1" + }, + "Microsoft.PowerAutomateDesktop": { + "Category": "Utilities & Productivity", + "Content": "Power Automate", + "Description": "Power Automate Desktop flow designer.", + "Panel": "1" + }, + "Microsoft.MicrosoftSolitaireCollection": { + "Category": "Xbox & Gaming", + "Content": "Microsoft Solitaire Collection", + "Description": "Pre-installed Solitaire collection game.", + "Panel": "0" + }, + "Microsoft.WindowsSoundRecorder": { + "Category": "Utilities & Productivity", + "Content": "Sound Recorder", + "Description": "Windows Voice Recorder / Sound Recorder app.", + "Panel": "1" + }, + "Microsoft.MicrosoftStickyNotes": { + "Category": "Utilities & Productivity", + "Content": "Sticky Notes", + "Description": "Sticky Notes application for quick note taking.", + "Panel": "1" + }, + "Microsoft.Windows.DevHome": { + "Category": "Microsoft Apps", + "Content": "Dev Home", + "Description": "Dev Home control center and developer tools app.", + "Panel": "1" + }, + "Microsoft.Paint": { + "Category": "Utilities & Productivity", + "Content": "Paint", + "Description": "Classic image editing application.", + "Panel": "1" + }, + "Microsoft.OutlookForWindows": { + "Category": "Microsoft Apps", + "Content": "Outlook for Windows", + "Description": "Pre-installed new Outlook application.", + "Panel": "1" + }, + "Microsoft.WindowsAlarms": { + "Category": "Utilities & Productivity", + "Content": "Windows Clock", + "Description": "Windows Alarm & Clock application.", + "Panel": "1" + }, + "Microsoft.GetHelp": { + "Category": "Microsoft Apps", + "Content": "Get Help", + "Description": "Microsoft Get Help assistant app.", + "Panel": "1" + }, + "Microsoft.ZuneMusic": { + "Category": "Microsoft Apps", + "Content": "Windows Media Player", + "Description": "Pre-installed Zune Music / Media Player application.", + "Panel": "1" + }, + "MicrosoftCorporationII.QuickAssist": { + "Category": "Utilities & Productivity", + "Content": "Quick Assist", + "Description": "Microsoft Quick Assist remote support app.", + "Panel": "1" + }, + "MSTeams": { + "Category": "Microsoft Apps", + "Content": "Microsoft Teams", + "Description": "Microsoft Teams chat and collaboration tool.", + "Panel": "1" + }, + "Microsoft.XboxIdentityProvider": { + "Category": "Xbox & Gaming", + "Content": "Xbox Identity Provider", + "Description": "Provides authentication services for Xbox Live connectivity.", + "Panel": "0" + }, + "Microsoft.XboxSpeechToTextOverlay": { + "Category": "Xbox & Gaming", + "Content": "Xbox Speech to Text Overlay", + "Description": "Accessibility overlay for converting Xbox party chat to text.", + "Panel": "0" + }, + "Microsoft.GamingApp": { + "Category": "Xbox & Gaming", + "Content": "Xbox App", + "Description": "The main Xbox App for gaming on Windows.", + "Panel": "0" + }, + "Microsoft.Xbox.TCUI": { + "Category": "Xbox & Gaming", + "Content": "Xbox TCUI", + "Description": "Xbox Live UI component.", + "Panel": "0" + }, + "Microsoft.XboxGamingOverlay": { + "Category": "Xbox & Gaming", + "Content": "Xbox Game Bar", + "Description": "Xbox Game Bar overlay for gaming captures and social tools.", + "Panel": "0" + }, + "Microsoft.MicrosoftOfficeHub": { + "Category": "Microsoft Apps", + "Content": "Office (365) Hub", + "Description": "Microsoft 365 dashboard application.", + "Panel": "1" + } +} diff --git a/config/themes.json b/config/themes.json index e739e0c4..7416c2f5 100644 --- a/config/themes.json +++ b/config/themes.json @@ -65,11 +65,13 @@ "ButtonConfigBackgroundColor": "#F7F7F7", "ButtonUpdatesBackgroundColor": "#F7F7F7", "ButtonWin11ISOBackgroundColor": "#F7F7F7", + "ButtonAppxBackgroundColor": "#F7F7F7", "ButtonInstallForegroundColor": "#232629", "ButtonTweaksForegroundColor": "#232629", "ButtonConfigForegroundColor": "#232629", "ButtonUpdatesForegroundColor": "#232629", "ButtonWin11ISOForegroundColor": "#232629", + "ButtonAppxForegroundColor": "#232629", "ButtonBackgroundColor": "#F5F5F5", "ButtonBackgroundPressedColor": "#1A1A1A", "ButtonBackgroundMouseoverColor": "#C2C2C2", @@ -105,11 +107,13 @@ "ButtonConfigBackgroundColor": "#444444", "ButtonUpdatesBackgroundColor": "#555555", "ButtonWin11ISOBackgroundColor": "#666666", + "ButtonAppxBackgroundColor": "#777777", "ButtonInstallForegroundColor": "#F7F7F7", "ButtonTweaksForegroundColor": "#F7F7F7", "ButtonConfigForegroundColor": "#F7F7F7", "ButtonUpdatesForegroundColor": "#F7F7F7", "ButtonWin11ISOForegroundColor": "#F7F7F7", + "ButtonAppxForegroundColor": "#F7F7F7", "ButtonBackgroundColor": "#1E3747", "ButtonBackgroundPressedColor": "#F7F7F7", "ButtonBackgroundMouseoverColor": "#3B4252", diff --git a/functions/public/Invoke-WPFAppxRemoval.ps1 b/functions/public/Invoke-WPFAppxRemoval.ps1 new file mode 100644 index 00000000..a5822d3d --- /dev/null +++ b/functions/public/Invoke-WPFAppxRemoval.ps1 @@ -0,0 +1,50 @@ +function Invoke-WPFAppxRemoval { + <# + .SYNOPSIS + Removes the selected AppX packages in a background runspace. + #> + + if ($sync.ProcessRunning) { + $msg = "A process is currently running. Please wait for it to finish." + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + $selected = @($sync.selectedAppx) + if ($selected.Count -eq 0) { + $msg = "Please select the AppX packages you wish to remove." + [System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning) + return + } + + $totalSteps = $selected.Count + $completedSteps = 0 + + Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" } + + $handle = Invoke-WPFRunspace -ParameterList @(("selected", $selected), ("completedSteps", $completedSteps), ("totalSteps", $totalSteps)) -ScriptBlock { + param($selected, $completedSteps, $totalSteps) + + $sync.ProcessRunning = $true + + for ($i = 0; $i -lt $selected.Count; $i++) { + $key = $selected[$i] + $appInfo = $sync.configs.appxHashtable.$key + $packageId = $appInfo.PackageId + $friendlyName = $appInfo.content + + Set-WinUtilProgressBar -Label "Removing $friendlyName" -Percent ($completedSteps / $totalSteps * 100) + Remove-WinUtilAPPX -Name $packageId + $completedSteps++ + $progress = $completedSteps / $totalSteps + Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value $progress } + } + + Set-WinUtilProgressBar -Label "AppX Removal finished" -Percent 100 + $sync.ProcessRunning = $false + Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" } + Write-Host "=================================" + Write-Host "-- AppX Removal Finished ---" + Write-Host "=================================" + } +} diff --git a/functions/public/Invoke-WPFButton.ps1 b/functions/public/Invoke-WPFButton.ps1 index f7419f64..199d7698 100644 --- a/functions/public/Invoke-WPFButton.ps1 +++ b/functions/public/Invoke-WPFButton.ps1 @@ -65,6 +65,23 @@ function Invoke-WPFButton { "WPFUpdatessecurity" {Invoke-WPFUpdatessecurity} "WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"} "WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"} + "WPFSelectAllAppx" { + $sync.configs.appxHashtable.Keys | ForEach-Object { + if ($sync.$_) { + $sync.$_.IsChecked = $true + } + } + } + "WPFClearAppxSelection" { + $sync.configs.appxHashtable.Keys | ForEach-Object { + if ($sync.$_) { + $sync.$_.IsChecked = $false + } + } + } + "WPFRemoveSelectedAppx" { + Invoke-WPFAppxRemoval + } "WPFCloseButton" {$sync.Form.Close(); Write-Host "Bye bye!"} "WPFMinimizeButton" {$sync.Form.WindowState = [Windows.WindowState]::Minimized} "WPFselectedAppsButton" {$sync.selectedAppsPopup.IsOpen = -not $sync.selectedAppsPopup.IsOpen} diff --git a/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 b/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 index 653efad6..04f300b3 100644 --- a/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 +++ b/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 @@ -30,6 +30,7 @@ function Invoke-WPFSelectedCheckboxesUpdate{ elseif ($appKey.StartsWith("WPFTweaks")) { "Tweaks" } elseif ($appKey.StartsWith("WPFToggle")) { "Toggle" } elseif ($appKey.StartsWith("WPFFeature")) { "Feature" } + elseif ($appKey.StartsWith("WPFAppx")) { "Appx" } else { "na" } switch ($group) { @@ -81,6 +82,16 @@ function Invoke-WPFSelectedCheckboxesUpdate{ $sync.selectedFeatures.Remove($appKey) } } + "Appx" { + if ($type -eq "Add") { + if (!$sync.selectedAppx.Contains($appKey)) { + $sync.selectedAppx.Add($appKey) + } + } + else{ + $sync.selectedAppx.Remove($appKey) + } + } default { Write-Host "Unknown group for checkbox: $($appKey)" } diff --git a/scripts/main.ps1 b/scripts/main.ps1 index a5e1a1bf..f3c6b1ed 100644 --- a/scripts/main.ps1 +++ b/scripts/main.ps1 @@ -86,6 +86,11 @@ $sync.configs.applications.PSObject.Properties | ForEach-Object { $sync.configs.applicationsHashtable[$_.Name] = $_.Value } +$sync.configs.appxHashtable = @{} +$sync.configs.appx.PSObject.Properties | ForEach-Object { + $sync.configs.appxHashtable[$_.Name] = $_.Value +} + Set-Preferences if ($Preset) { @@ -188,6 +193,8 @@ Invoke-WPFUIElements -configVariable $sync.configs.tweaks -targetGridName "tweak Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "featurespanel" -columncount 2 +Invoke-WPFUIElements -configVariable $sync.configs.appx -targetGridName "appxpanel" -columncount 2 + # Future implementation: Add Windows Version to updates panel #Invoke-WPFUIElements -configVariable $sync.configs.updates -targetGridName "updatespanel" -columncount 1 diff --git a/scripts/start.ps1 b/scripts/start.ps1 index e590a29a..6a8cb9ea 100644 --- a/scripts/start.ps1 +++ b/scripts/start.ps1 @@ -71,6 +71,7 @@ $sync.selectedApps = [System.Collections.Generic.List[string]]::new() $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() $sync.selectedFeatures = [System.Collections.Generic.List[string]]::new() +$sync.selectedAppx = [System.Collections.Generic.List[string]]::new() $sync.currentTab = "Install" $sync.selectedAppsStackPanel $sync.selectedAppsPopup diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index 8730fb0c..9ccc0123 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -1005,6 +1005,14 @@ + + + + AppX Removal + + + @@ -1690,6 +1698,51 @@ + + + + + + + + + + + + + + + + +