From 7c71a39f7a75e172d49cd0282a687b10e67a4bad Mon Sep 17 00:00:00 2001 From: Gabi <218829269+GabiNun2@users.noreply.github.com> Date: Wed, 1 Jul 2026 20:13:32 +0300 Subject: [PATCH] Feature/appx removal tab (#4729) * 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 * yep * yep * yep * yep * Update inputXML.xaml * Update Invoke-WPFButton.ps1 * Update Invoke-WPFButton.ps1 * Update Invoke-WPFSelectedCheckboxesUpdate.ps1 * Update appx.json * Update appx.json * Update appx.json * Update tweaks.json * Update appx.json * Update appx.json * Update appx.json * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFButton.ps1 * Delete functions/public/Invoke-WPFAppxRemoval.ps1 * Revert "Update Invoke-WPFButton.ps1" This reverts commit d8705cc08e1c29119f6bc983012c71c9676b8c10. * Revert "Delete functions/public/Invoke-WPFAppxRemoval.ps1" This reverts commit 9e45d1ad99e1a580c621b31ef55ee36dc48a435b. * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFButton.ps1 * yep * Update appx.json * Update appx.json * Update tweaks.json * Update start.ps1 * Update preset.json * Update tweaks.json * yep * yep * yep * yep * yep * yep * Update Invoke-WPFAppxRemoval.ps1 * Update Update-WinUtilSelections.ps1 * Update Update-WinUtilSelections.ps1 * yep * Update Invoke-WPFAppxRemoval.ps1 * yep * yep * Update Invoke-WPFAppxRemoval.ps1 * Update appx.json * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update appx.json * Update Invoke-WPFGetInstalled.ps1 * Update Invoke-WPFAppxRemoval.ps1 * yep * yep * Update Invoke-WPFSelectedCheckboxesUpdate.ps1 * yep * yep * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * yep * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update appx.json * Update Invoke-WPFImpex.ps1 * Update Invoke-WPFImpex.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update preset.json * Update preset.json * Update Invoke-WPFSelectedCheckboxesUpdate.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update tweaks.json * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * Update Invoke-WPFAppxRemoval.ps1 * yep * yep * Update Invoke-WPFAppxRemoval.ps1 * yep * Delete functions/private/Find-AppxByNameOrDescription.ps1 * yep * Update Invoke-WPFButton.ps1 * Update main.ps1 * Update Invoke-WPFTab.ps1 * yep * yep * Update themes.json --- config/appx.json | 233 ++++++++++++++++++ config/preset.json | 23 +- config/themes.json | 4 + config/tweaks.json | 64 ----- .../Find-TweaksByNameOrDescription.ps1 | 9 +- functions/private/Reset-WPFCheckBoxes.ps1 | 2 +- .../private/Update-WinUtilSelections.ps1 | 58 +---- functions/public/Invoke-WPFAppxRemoval.ps1 | 44 ++++ functions/public/Invoke-WPFButton.ps1 | 16 ++ functions/public/Invoke-WPFImpex.ps1 | 5 +- functions/public/Invoke-WPFPresets.ps1 | 1 + .../Invoke-WPFSelectedCheckboxesUpdate.ps1 | 95 +------ functions/public/Invoke-WPFTab.ps1 | 7 +- functions/public/Invoke-WinUtilAutoRun.ps1 | 6 + scripts/main.ps1 | 10 + scripts/start.ps1 | 1 + xaml/inputXML.xaml | 54 ++++ 17 files changed, 427 insertions(+), 205 deletions(-) create mode 100644 config/appx.json create mode 100644 functions/public/Invoke-WPFAppxRemoval.ps1 diff --git a/config/appx.json b/config/appx.json new file mode 100644 index 00000000..dffd9377 --- /dev/null +++ b/config/appx.json @@ -0,0 +1,233 @@ +{ + "WPFAppxMicrosoft_WindowsFeedbackHub": { + "Category": "Microsoft Apps", + "Content": "Feedback Hub", + "Description": "Allows users to submit bug reports, feature suggestions, and diagnostic data directly to Microsoft.", + "Panel": "0", + "PackageId": "Microsoft.WindowsFeedbackHub" + }, + "WPFAppxMicrosoft_GetHelp": { + "Category": "Microsoft Apps", + "Content": "Get Help", + "Description": "Provides access to automated troubleshooting guides, support documentation, and direct Microsoft customer assistance.", + "Panel": "0", + "PackageId": "Microsoft.GetHelp" + }, + "WPFAppxMicrosoft_OutlookForWindows": { + "Category": "Microsoft Apps", + "Content": "Outlook for Windows", + "Description": "Provides modern email management, calendar scheduling, and contact organization features.", + "Panel": "0", + "PackageId": "Microsoft.OutlookForWindows" + }, + "WPFAppxMSTeams": { + "Category": "Microsoft Apps", + "Content": "Microsoft Teams", + "Description": "Facilitates instant messaging, video conferencing, file sharing, and workspace collaboration.", + "Panel": "0", + "PackageId": "MSTeams" + }, + "WPFAppxClipchamp_Clipchamp": { + "Category": "Utilities & Productivity", + "Content": "Clipchamp", + "Description": "Provides a user-friendly video editor with built-in templates, effects, and timeline editing tools.", + "Panel": "0", + "PackageId": "Clipchamp.Clipchamp" + }, + "WPFAppxMicrosoft_MicrosoftOfficeHub": { + "Category": "Microsoft Apps", + "Content": "Microsoft 365", + "Description": "Serves as a centralized launcher and dashboard for accessing cloud-based Microsoft 365 apps and recent documents.", + "Panel": "0", + "PackageId": "Microsoft.MicrosoftOfficeHub" + }, + "WPFAppxMicrosoft_ZuneMusic": { + "Category": "Utilities & Productivity", + "Content": "Media Player", + "Description": "Plays local audio and video files with modern playlist management and casting capabilities.", + "Panel": "0", + "PackageId": "Microsoft.ZuneMusic" + }, + "WPFAppxMicrosoft_BingSearch": { + "Category": "Bing & Web Services", + "Content": "Bing Search", + "Description": "Integrates Microsoft Bing search capabilities and web services directly into the operating system.", + "Panel": "1", + "PackageId": "Microsoft.BingSearch" + }, + "WPFAppxMicrosoftCorporationII_QuickAssist": { + "Category": "Utilities & Productivity", + "Content": "Quick Assist", + "Description": "Enables secure remote technical support and screen sharing over an internet connection.", + "Panel": "0", + "PackageId": "MicrosoftCorporationII.QuickAssist" + }, + "WPFAppxMicrosoft_WindowsDevHome": { + "Category": "Developer Tools", + "Content": "Dev Home", + "Description": "Provides a specialized dashboard for software developer environment setups, repository syncing, and hardware widgets.", + "Panel": "1", + "PackageId": "Microsoft.Windows.DevHome" + }, + "WPFAppxMicrosoft_WindowsCrossDevice": { + "Category": "Microsoft Ecosystem", + "Content": "Mobile Devices", + "Description": "Manages system-level background connectivity with paired mobile devices. Removing this may disable cross-device features such as phone screen mirroring, file transfer, and mobile hotspot handoff integrated into Windows Settings.", + "Panel": "0", + "PackageId": "MicrosoftWindows.CrossDevice" + }, + "WPFAppxMicrosoft_Todos": { + "Category": "Utilities & Productivity", + "Content": "To Do", + "Description": "Creates, tracks, and synchronizes personal tasks, smart lists, and daily reminders.", + "Panel": "0", + "PackageId": "Microsoft.Todos" + }, + "WPFAppxMicrosoft_PowerAutomateDesktop": { + "Category": "Developer Tools", + "Content": "Power Automate", + "Description": "Automates repetitive workflows and desktop tasks using low-code visual scripting.", + "Panel": "1", + "PackageId": "Microsoft.PowerAutomateDesktop" + }, + "WPFAppxMicrosoft_YourPhone": { + "Category": "Microsoft Ecosystem", + "Content": "Phone Link", + "Description": "Synchronizes text messages, phone notifications, photos, and calls from a mobile device to the desktop.", + "Panel": "0", + "PackageId": "Microsoft.YourPhone" + }, + "WPFAppxMicrosoft_MicrosoftStickyNotes": { + "Category": "Utilities & Productivity", + "Content": "Sticky Notes", + "Description": "Creates quick, floating text notes on the desktop that automatically sync across devices.", + "Panel": "0", + "PackageId": "Microsoft.MicrosoftStickyNotes" + }, + "WPFAppxMicrosoft_WindowsSoundRecorder": { + "Category": "Utilities & Productivity", + "Content": "Sound Recorder", + "Description": "Records and trims live audio inputs with simple microphone adjustment controls.", + "Panel": "0", + "PackageId": "Microsoft.WindowsSoundRecorder" + }, + "WPFAppxMicrosoft_WindowsAlarms": { + "Category": "Utilities & Productivity", + "Content": "Clock", + "Description": "Features world clocks, alarms, countdown timers, stopwatches, and dedicated focus session tracking.", + "Panel": "0", + "PackageId": "Microsoft.WindowsAlarms" + }, + "WPFAppxMicrosoft_Paint": { + "Category": "Utilities & Productivity", + "Content": "Paint", + "Description": "Provides built-in digital sketching, basic image editing, and pixel-level graphic manipulation tools.", + "Panel": "0", + "PackageId": "Microsoft.Paint" + }, + "WPFAppxMicrosoft_WindowsNotepad": { + "Category": "Utilities & Productivity", + "Content": "Notepad", + "Description": "Provides a lightweight text editor with multi-tab support for plain text files and code snippets.", + "Panel": "0", + "PackageId": "Microsoft.WindowsNotepad" + }, + "WPFAppxMicrosoft_ScreenSketch": { + "Category": "Utilities & Productivity", + "Content": "Snipping Tool", + "Description": "Captures screenshots or screen recordings with built-in markup, image cropping, and optical character recognition (OCR).", + "Panel": "0", + "PackageId": "Microsoft.ScreenSketch" + }, + "WPFAppxMicrosoft_Copilot": { + "Category": "Bing & Web Services", + "Content": "Copilot", + "Description": "Launches the Microsoft AI companion for contextual answers, creative writing assistance, and intelligent web search.", + "Panel": "1", + "PackageId": "Microsoft.Copilot" + }, + "WPFAppxMicrosoft_WindowsCalculator": { + "Category": "Utilities & Productivity", + "Content": "Calculator", + "Description": "Performs standard arithmetic, scientific operations, programming calculations, and unit conversions.", + "Panel": "0", + "PackageId": "Microsoft.WindowsCalculator" + }, + "WPFAppxMicrosoft_WindowsCamera": { + "Category": "Utilities & Productivity", + "Content": "Camera", + "Description": "Captures photographs and records video files via connected webcams or imaging hardware.", + "Panel": "0", + "PackageId": "Microsoft.WindowsCamera" + }, + "WPFAppxMicrosoft_WindowsPhotos": { + "Category": "Utilities & Productivity", + "Content": "Photos", + "Description": "Organizes, views, and crops local images with basic color adjustment and album creation tools.", + "Panel": "0", + "PackageId": "Microsoft.Windows.Photos" + }, + "WPFAppxMicrosoft_BingNews": { + "Category": "Bing & Web Services", + "Content": "News", + "Description": "Aggregates breaking news headlines, personalized article feeds, and world current events.", + "Panel": "1", + "PackageId": "Microsoft.BingNews" + }, + "WPFAppxMicrosoft_BingWeather": { + "Category": "Bing & Web Services", + "Content": "Weather", + "Description": "Displays local real-time weather tracking, radar maps, and historical meteorological forecasts.", + "Panel": "1", + "PackageId": "Microsoft.BingWeather" + }, + "WPFAppxMicrosoft_GamingApp": { + "Category": "Xbox & Gaming", + "Content": "Xbox App", + "Description": "Serves as the primary gaming library manager, social community interface, and PC Game Pass dashboard.", + "Panel": "1", + "PackageId": "Microsoft.GamingApp" + }, + "WPFAppxMicrosoft_XboxGamingOverlay": { + "Category": "Xbox & Gaming", + "Content": "Xbox Game Bar", + "Description": "Provides customizable in-game status widgets, audio balancing sliders, system monitoring tools, and gameplay recording.", + "Panel": "1", + "PackageId": "Microsoft.XboxGamingOverlay" + }, + "WPFAppxMicrosoft_XboxIdentityProvider": { + "Category": "Xbox & Gaming", + "Content": "Xbox Identity Provider", + "Description": "Manages Xbox network user authentication and background account validation for connected titles. Warning: removing this may break Microsoft account sign-in for non-Xbox games and apps that rely on this authentication pipeline.", + "Panel": "1", + "PackageId": "Microsoft.XboxIdentityProvider" + }, + "WPFAppxMicrosoft_XboxSpeechToTextOverlay": { + "Category": "Xbox & Gaming", + "Content": "Xbox Speech To Text Overlay", + "Description": "Provides system-level live accessibility captions and voice-to-text translation for gaming chat networks.", + "Panel": "1", + "PackageId": "Microsoft.XboxSpeechToTextOverlay" + }, + "WPFAppxMicrosoft_Xbox_TCUI": { + "Category": "Xbox & Gaming", + "Content": "Xbox TCUI", + "Description": "Provides core account connection UI modules for single sign-on flows within game titles. Warning: removing this may break Microsoft account authentication in games and apps that do not otherwise require the Xbox app.", + "Panel": "1", + "PackageId": "Microsoft.Xbox.TCUI" + }, + "WPFAppxMicrosoft_StartExperiencesApp": { + "Category": "Bing & Web Services", + "Content": "Start Experiences App", + "Description": "Powers the Windows Widgets board, delivering a personalized feed of news, weather, sports, and finance content.", + "Panel": "1", + "PackageId": "Microsoft.StartExperiencesApp" + }, + "WPFAppxMicrosoft_MicrosoftSolitaireCollection": { + "Category": "Xbox & Gaming", + "Content": "Solitaire Collection", + "Description": "Bundles built-in card game modes including Klondike, Spider, FreeCell, Pyramid, and TriPeaks alongside daily challenges.", + "Panel": "1", + "PackageId": "Microsoft.MicrosoftSolitaireCollection" + } +} diff --git a/config/preset.json b/config/preset.json index 4842114e..88aaf489 100644 --- a/config/preset.json +++ b/config/preset.json @@ -4,7 +4,6 @@ "WPFTweaksConsumerFeatures", "WPFTweaksDisableExplorerAutoDiscovery", "WPFTweaksWPBT", - "WPFTweaksDeBloat", "WPFTweaksLocation", "WPFTweaksServices", "WPFTweaksTelemetry", @@ -16,7 +15,6 @@ ], "Minimal": [ "WPFTweaksConsumerFeatures", - "WPFTweaksDeBloat", "WPFTweaksWPBT", "WPFTweaksServices", "WPFTweaksTelemetry" @@ -26,7 +24,6 @@ "WPFTweaksConsumerFeatures", "WPFTweaksDisableExplorerAutoDiscovery", "WPFTweaksWPBT", - "WPFTweaksDeBloat", "WPFTweaksLocation", "WPFTweaksServices", "WPFTweaksTelemetry", @@ -39,5 +36,25 @@ "WPFTweaksRemoveOneDrive", "WPFTweaksWindowsAI", "WPFTweaksRightClickMenu" + ], + "AppxDefault": [ + "WPFAppxMicrosoft_WindowsFeedbackHub", + "WPFAppxMicrosoft_GetHelp", + "WPFAppxMicrosoft_MicrosoftOfficeHub", + "WPFAppxMicrosoft_WindowsCalculator", + "WPFAppxClipchamp_Clipchamp", + "WPFAppxMicrosoft_WindowsAlarms", + "WPFAppxMicrosoftCorporationII_QuickAssist", + "WPFAppxMicrosoft_WindowsSoundRecorder", + "WPFAppxMicrosoft_MicrosoftStickyNotes", + "WPFAppxMicrosoft_Todos", + "WPFAppxMicrosoft_MicrosoftSolitaireCollection", + "WPFAppxMicrosoft_PowerAutomateDesktop", + "WPFAppxMicrosoft_WindowsDevHome", + "WPFAppxMicrosoft_BingWeather", + "WPFAppxMicrosoft_StartExperiencesApp", + "WPFAppxMicrosoft_BingNews", + "WPFAppxMicrosoft_Copilot", + "WPFAppxMicrosoft_BingSearch" ] } 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/config/tweaks.json b/config/tweaks.json index b71ac304..2cf0677a 100644 --- a/config/tweaks.json +++ b/config/tweaks.json @@ -812,70 +812,6 @@ ], "link": "https://winutil.christitus.com/dev/tweaks/z--advanced-tweaks---caution/display" }, - "WPFTweaksXboxRemoval": { - "Content": "Xbox & Gaming Components - Remove", - "Description": "Removes Xbox services, the Xbox app, Game Bar, and related authentication components.", - "category": "z__Advanced Tweaks - CAUTION", - "panel": "1", - "registry": [ - { - "Path": "HKCU:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\GameDVR", - "Name": "AppCaptureEnabled", - "Value": "0", - "Type": "DWord", - "OriginalValue": "1" - } - ], - "appx": [ - "Microsoft.XboxIdentityProvider", - "Microsoft.XboxSpeechToTextOverlay", - "Microsoft.GamingApp", - "Microsoft.Xbox.TCUI", - "Microsoft.XboxGamingOverlay" - ], - "link": "https://winutil.christitus.com/dev/tweaks/z--advanced-tweaks---caution/xboxremoval" - }, - "WPFTweaksDeBloat": { - "Content": "Unwanted Pre-Installed Apps - Remove", - "Description": "This will remove a bunch of Windows pre-installed applications which most people dont want on their system.", - "category": "Essential Tweaks", - "panel": "1", - "appx": [ - "Microsoft.WindowsFeedbackHub", - "Microsoft.BingNews", - "Microsoft.BingSearch", - "Microsoft.BingWeather", - "Clipchamp.Clipchamp", - "Microsoft.Todos", - "Microsoft.PowerAutomateDesktop", - "Microsoft.MicrosoftSolitaireCollection", - "Microsoft.WindowsSoundRecorder", - "Microsoft.MicrosoftStickyNotes", - "Microsoft.Windows.DevHome", - "Microsoft.Paint", - "Microsoft.OutlookForWindows", - "Microsoft.WindowsAlarms", - "Microsoft.StartExperiencesApp", - "Microsoft.GetHelp", - "Microsoft.ZuneMusic", - "MicrosoftCorporationII.QuickAssist", - "MSTeams" - ], - "InvokeScript": [ - " - $TeamsPath = \"$Env:LocalAppData\\Microsoft\\Teams\\Update.exe\" - - if (Test-Path $TeamsPath) { - Write-Host \"Uninstalling Teams\" - Start-Process $TeamsPath -ArgumentList -uninstall -wait - - Write-Host \"Deleting Teams directory\" - Remove-Item $TeamsPath -Recurse -Force - } - " - ], - "link": "https://winutil.christitus.com/dev/tweaks/essential-tweaks/debloat" - }, "WPFTweaksReservedStorage": { "Content": "Disable Reserved Storage", "Description": "Disables Windows Reserved Storage (7-10 GB held for updates/temp files). Recommended only on small drives. Re-enable before major Windows feature updates to avoid installation failures.", diff --git a/functions/private/Find-TweaksByNameOrDescription.ps1 b/functions/private/Find-TweaksByNameOrDescription.ps1 index 06d60148..66af5753 100644 --- a/functions/private/Find-TweaksByNameOrDescription.ps1 +++ b/functions/private/Find-TweaksByNameOrDescription.ps1 @@ -46,12 +46,17 @@ function Find-TweaksByNameOrDescription { } # ------------------------------------------------------------------------------ - # 2. GET REFERENCE TO TWEAKS PANEL + # 2. GET REFERENCE TO TWEAKS OR APPX PANEL # ------------------------------------------------------------------------------ + $panelName = "tweakspanel" + if ($null -ne $Sync.currentTab -and $Sync.currentTab -eq "AppX") { + $panelName = "appxpanel" + } + $tweaksPanel = $null try { - $tweaksPanel = $Sync.Form.FindName("tweakspanel") + $tweaksPanel = $Sync.Form.FindName($panelName) } catch { # Silent return - panel not found or disposed diff --git a/functions/private/Reset-WPFCheckBoxes.ps1 b/functions/private/Reset-WPFCheckBoxes.ps1 index 5069d446..0f49f4d9 100644 --- a/functions/private/Reset-WPFCheckBoxes.ps1 +++ b/functions/private/Reset-WPFCheckBoxes.ps1 @@ -21,7 +21,7 @@ function Reset-WPFCheckBoxes { [string]$checkboxfilterpattern = "**" ) - $CheckBoxesToCheck = $sync.selectedApps + $sync.selectedTweaks + $sync.selectedFeatures + $CheckBoxesToCheck = $sync.selectedApps + $sync.selectedTweaks + $sync.selectedFeatures + $sync.selectedAppx $CheckBoxes = ($sync.GetEnumerator()).where{ $_.Value -is [System.Windows.Controls.CheckBox] -and $_.Name -notlike "WPFToggle*" -and $_.Name -like "$checkboxfilterpattern"} foreach ($CheckBox in $CheckBoxes) { diff --git a/functions/private/Update-WinUtilSelections.ps1 b/functions/private/Update-WinUtilSelections.ps1 index e1c5e99a..e5efe319 100644 --- a/functions/private/Update-WinUtilSelections.ps1 +++ b/functions/private/Update-WinUtilSelections.ps1 @@ -1,52 +1,14 @@ -function Update-WinUtilSelections { - <# +function Update-WinUtilSelections ($flatJson) { + foreach ($cbkey in $flatJson) { - .SYNOPSIS - Updates the $sync.selected variables with a given preset. - - .PARAMETER flatJson - The flattened json list of $sync values to select. - #> - - param ( - $flatJson - ) - - foreach ($item in $flatJson) { - # Ensure each item is treated as a string to handle PSCustomObject from JSON deserialization - $cbkey = [string]$item - $group = if ($cbkey.StartsWith("WPFInstall")) { "Install" } - elseif ($cbkey.StartsWith("WPFTweaks")) { "Tweaks" } - elseif ($cbkey.StartsWith("WPFToggle")) { "Toggle" } - elseif ($cbkey.StartsWith("WPFFeature")) { "Feature" } - else { "na" } - - switch ($group) { - "Install" { - if (!$sync.selectedApps.Contains($cbkey)) { - $sync.selectedApps.Add($cbkey) - # The List type needs to be specified again, because otherwise Sort-Object will convert the list to a string if there is only a single entry - [System.Collections.Generic.List[string]]$sync.selectedApps = $sync.SelectedApps | Sort-Object - } - } - "Tweaks" { - if (!$sync.selectedTweaks.Contains($cbkey)) { - $sync.selectedTweaks.Add($cbkey) - } - } - "Toggle" { - if (!$sync.selectedToggles.Contains($cbkey)) { - $sync.selectedToggles.Add($cbkey) - } - } - "Feature" { - if (!$sync.selectedFeatures.Contains($cbkey)) { - $sync.selectedFeatures.Add($cbkey) - } - } - default { - Write-Host "Unknown group for checkbox: $($cbkey)" - } + $listName = switch -Regex ($cbkey) { + '^WPFInstall' { 'selectedApps' } + '^WPFTweaks' { 'selectedTweaks' } + '^WPFToggle' { 'selectedToggles' } + '^WPFFeature' { 'selectedFeatures' } + '^WPFAppx' { 'selectedAppx' } } + + $sync.$listName.Add($cbkey) } } diff --git a/functions/public/Invoke-WPFAppxRemoval.ps1 b/functions/public/Invoke-WPFAppxRemoval.ps1 new file mode 100644 index 00000000..d192c375 --- /dev/null +++ b/functions/public/Invoke-WPFAppxRemoval.ps1 @@ -0,0 +1,44 @@ +function Invoke-WPFAppxRemoval { + if (-not ($sync.selectedAppx)) { + [System.Windows.Forms.MessageBox]::Show("No AppX Package selected","Error","OK","Error") + return + } + + $selected = $sync.selectedAppx + $apps = $sync.configs.appxHashtable + + $handle = Invoke-WPFRunspace -ParameterList @(("selected", $selected), ("apps", $apps)) -ScriptBlock { + param($selected, $apps) + + $sync.ProcessRunning = $true + + foreach ($key in $selected) { + if ($key -eq "WPFAppxMicrosoft_XboxGamingOverlay") { + # Making sure Game Bar isn't running + Stop-Process -Name GameBarFTServer + + # This stops annoying ms-gamebar popup when launching games. + Set-ItemProperty -Path HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\GameDVR -Name AppCaptureEnabled -Value 0 + } + + if ($key -eq "WPFAppxMicrosoft_WindowsNotepad") { + # i hope your having fun reading this + Stop-Process -Name dllhost + } + + Write-Host "Removing $($apps[$key].Content)" + Get-AppxPackage -Name $apps[$key].PackageId -AllUsers | Remove-AppxPackage -AllUsers + + if ($key -eq "WPFAppxMSTeams") { + # Uninstalls Microsoft Teams Meeting Add-in for Microsoft Office + Get-Package -Name "Microsoft Teams*" -ErrorAction SilentlyContinue | Uninstall-Package -Force + } + } + + Write-Host "=================================" + Write-Host "-- AppX Removal Finished ---" + Write-Host "=================================" + + $sync.ProcessRunning = $false + } +} diff --git a/functions/public/Invoke-WPFButton.ps1 b/functions/public/Invoke-WPFButton.ps1 index 2c51624d..454cce28 100644 --- a/functions/public/Invoke-WPFButton.ps1 +++ b/functions/public/Invoke-WPFButton.ps1 @@ -65,6 +65,22 @@ function Invoke-WPFButton { "WPFUpdatessecurity" {Invoke-WPFUpdatessecurity} "WPFGetInstalled" {Invoke-WPFGetInstalled -CheckBox "winget"} "WPFGetInstalledTweaks" {Invoke-WPFGetInstalled -CheckBox "tweaks"} + "WPFRemoveSelectedAppx" {Invoke-WPFAppxRemoval} + "WPFDefaultAppxSelection" {Invoke-WPFPresets "AppxDefault" -checkboxfilterpattern "WPFAppx*"} + "WPFSelectAllAppx" { + $sync.configs.appxHashtable.Keys | ForEach-Object {$sync.$_.IsChecked = $true} + } + "WPFClearAppxSelection" { + $sync.configs.appxHashtable.Keys | ForEach-Object {$sync.$_.IsChecked = $false} + } + "WPFGetInstalledAppx" { + $installedAppxPackages = Get-AppxPackage -AllUsers | Select-Object -ExpandProperty Name + foreach ($appx in $sync.configs.appxHashtable.GetEnumerator()) { + if ($appx.Value.PackageId -in $installedAppxPackages) { + $sync.$($appx.Key).IsChecked = $true + } + } + } "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-WPFImpex.ps1 b/functions/public/Invoke-WPFImpex.ps1 index 9142d6ec..18218ef7 100644 --- a/functions/public/Invoke-WPFImpex.ps1 +++ b/functions/public/Invoke-WPFImpex.ps1 @@ -44,10 +44,10 @@ function Invoke-WPFImpex { try { $Config = ConfigDialog if ($Config) { - $allConfs = ($sync.selectedApps + $sync.selectedTweaks + $sync.selectedToggles + $sync.selectedFeatures) | ForEach-Object { [string]$_ } + $allConfs = ($sync.selectedApps + $sync.selectedTweaks + $sync.selectedToggles + $sync.selectedFeatures + $sync.selectedAppx) | ForEach-Object { [string]$_ } if (-not $allConfs) { [System.Windows.MessageBox]::Show( - "No settings are selected to export. Please select at least one app, tweak, toggle, or feature before exporting.", + "No settings are selected to export. Please select at least one app, tweak, toggle, feature, or AppX package before exporting.", "Nothing to Export", "OK", "Warning") return } @@ -86,6 +86,7 @@ function Invoke-WPFImpex { # Clear all existing selections before importing so the import replaces # the current state rather than merging with it + $sync.selectedAppx = [System.Collections.Generic.List[string]]::new() $sync.selectedApps = [System.Collections.Generic.List[string]]::new() $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() diff --git a/functions/public/Invoke-WPFPresets.ps1 b/functions/public/Invoke-WPFPresets.ps1 index 2139c47e..01e9cd40 100644 --- a/functions/public/Invoke-WPFPresets.ps1 +++ b/functions/public/Invoke-WPFPresets.ps1 @@ -37,6 +37,7 @@ function Invoke-WPFPresets { switch ($checkboxfilterpattern) { "WPFTweak*" { $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() } "WPFInstall*" { $sync.selectedApps = [System.Collections.Generic.List[string]]::new() } + "WPFAppx*" { $sync.selectedAppx = [System.Collections.Generic.List[string]]::new() } "WPFeatures" { $sync.selectedFeatures = [System.Collections.Generic.List[string]]::new() } "WPFToggle" { $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() } default {} diff --git a/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 b/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 index 653efad6..b4ca3fb6 100644 --- a/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 +++ b/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 @@ -1,88 +1,17 @@ -function Invoke-WPFSelectedCheckboxesUpdate{ - <# - .SYNOPSIS - This is a helper function that is called by the Checked and Unchecked events of the Checkboxes. - It also Updates the "Selected Apps" selectedAppLabel on the Install Tab to represent the current collection - .PARAMETER type - Either: Add | Remove - .PARAMETER checkboxName - should contain the name of the current instance of the checkbox that triggered the Event. - Most of the time will be the automatic variable $this.Parent.Tag - .EXAMPLE - $checkbox.Add_Unchecked({Invoke-WPFSelectedCheckboxesUpdate -type "Remove" -checkboxName $this.Parent.Tag}) - OR - Invoke-WPFSelectedCheckboxesUpdate -type "Add" -checkboxName $specificCheckbox.Parent.Tag - #> - param ( - $type, - $checkboxName - ) - - if (($type -ne "Add") -and ($type -ne "Remove")) - { - Write-Error "Type: $type not implemented" - return +function Invoke-WPFSelectedCheckboxesUpdate ($type, $checkboxName) { + $listName = switch -Regex ($checkboxName) { + '^WPFInstall' { 'selectedApps' } + '^WPFTweaks' { 'selectedTweaks' } + '^WPFToggle' { 'selectedToggles' } + '^WPFFeature' { 'selectedFeatures' } + '^WPFAppx' { 'selectedAppx' } } - # Get the actual Name from the selectedAppLabel inside the Checkbox - $appKey = $checkboxName - $group = if ($appKey.StartsWith("WPFInstall")) { "Install" } - elseif ($appKey.StartsWith("WPFTweaks")) { "Tweaks" } - elseif ($appKey.StartsWith("WPFToggle")) { "Toggle" } - elseif ($appKey.StartsWith("WPFFeature")) { "Feature" } - else { "na" } - - switch ($group) { - "Install" { - if ($type -eq "Add") { - if (!$sync.selectedApps.Contains($appKey)) { - $sync.selectedApps.Add($appKey) - # The List type needs to be specified again, because otherwise Sort-Object will convert the list to a string if there is only a single entry - [System.Collections.Generic.List[string]]$sync.selectedApps = $sync.SelectedApps | Sort-Object - } - } - else{ - $sync.selectedApps.Remove($appKey) - } - - $count = $sync.SelectedApps.Count - $sync.WPFselectedAppsButton.Content = "Selected Apps: $count" - # On every change, remove all entries inside the Popup Menu. This is done, so we can keep the alphabetical order even if elements are selected in a random way - $sync.selectedAppsstackPanel.Children.Clear() - $sync.selectedApps | Foreach-Object { Add-SelectedAppsMenuItem -name $($sync.configs.applicationsHashtable.$_.Content) -key $_ } - } - "Tweaks" { - if ($type -eq "Add") { - if (!$sync.selectedTweaks.Contains($appKey)) { - $sync.selectedTweaks.Add($appKey) - } - } - else{ - $sync.selectedTweaks.Remove($appKey) - } - } - "Toggle" { - if ($type -eq "Add") { - if (!$sync.selectedToggles.Contains($appKey)) { - $sync.selectedToggles.Add($appKey) - } - } - else{ - $sync.selectedToggles.Remove($appKey) - } - } - "Feature" { - if ($type -eq "Add") { - if (!$sync.selectedFeatures.Contains($appKey)) { - $sync.selectedFeatures.Add($appKey) - } - } - else{ - $sync.selectedFeatures.Remove($appKey) - } - } - default { - Write-Host "Unknown group for checkbox: $($appKey)" + if ($type -eq "Add") { + if (-not $sync.$listName.Contains($checkboxName)) { + $sync.$listName.Add($checkboxName) } + } else { + $sync.$listName.Remove($checkboxName) } } diff --git a/functions/public/Invoke-WPFTab.ps1 b/functions/public/Invoke-WPFTab.ps1 index 530a7dc2..735b38a7 100644 --- a/functions/public/Invoke-WPFTab.ps1 +++ b/functions/public/Invoke-WPFTab.ps1 @@ -37,10 +37,13 @@ function Invoke-WPFTab { } elseif ($sync.currentTab -eq "Tweaks") { # Reset Tweaks tab filter Find-TweaksByNameOrDescription -SearchString "" + } elseif ($sync.currentTab -eq "AppX") { + # Reset AppX tab filter + Find-TweaksByNameOrDescription -SearchString "" } - # Show search bar in Install and Tweaks tabs - if ($tabNumber -eq 0 -or $tabNumber -eq 1) { + # Show search bar in Install, Tweaks, and AppX tabs + if ($tabNumber -eq 0 -or $tabNumber -eq 1 -or $tabNumber -eq 5) { $sync.SearchBar.Visibility = "Visible" $searchIcon = ($sync.Form.FindName("SearchBar").Parent.Children | Where-Object { $_ -is [System.Windows.Controls.TextBlock] -and $_.Text -eq [char]0xE721 })[0] if ($searchIcon) { diff --git a/functions/public/Invoke-WinUtilAutoRun.ps1 b/functions/public/Invoke-WinUtilAutoRun.ps1 index f9170522..c4b094db 100644 --- a/functions/public/Invoke-WinUtilAutoRun.ps1 +++ b/functions/public/Invoke-WinUtilAutoRun.ps1 @@ -30,5 +30,11 @@ function Invoke-WinUtilAutoRun { BusyWait } + if ($sync.selectedAppx.Count -gt 0) { + Write-Host "Removing AppX packages..." + Invoke-WPFAppxRemoval + BusyWait + } + Write-Host "Done." } diff --git a/scripts/main.ps1 b/scripts/main.ps1 index 5fb60838..4719d90d 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 @@ -387,6 +394,9 @@ $searchBarTimer.add_Tick({ "Tweaks" { Find-TweaksByNameOrDescription -SearchString $sync.SearchBar.Text } + "AppX" { + Find-TweaksByNameOrDescription -SearchString $sync.SearchBar.Text + } } }) $sync["SearchBar"].Add_TextChanged({ diff --git a/scripts/start.ps1 b/scripts/start.ps1 index e590a29a..e689b493 100644 --- a/scripts/start.ps1 +++ b/scripts/start.ps1 @@ -67,6 +67,7 @@ $sync.configs = @{} $sync.Buttons = [System.Collections.Generic.List[PSObject]]::new() $sync.preferences = @{} $sync.ProcessRunning = $false +$sync.selectedAppx = [System.Collections.Generic.List[string]]::new() $sync.selectedApps = [System.Collections.Generic.List[string]]::new() $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index 8730fb0c..1b6f860d 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -1005,6 +1005,14 @@ + + + + AppX Removal + + + @@ -1690,6 +1698,52 @@ + + + + + + + + + + + + + + + + +