mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2026-08-09 17:41:14 +10:00
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
This commit is contained in:
+11
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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 "================================="
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
|
||||
@@ -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)"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1005,6 +1005,14 @@
|
||||
</TextBlock>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<ToggleButton Margin="0,0,5,0" Height="{DynamicResource TabButtonHeight}" Width="Auto" MinWidth="{DynamicResource TabButtonWidth}"
|
||||
Background="{DynamicResource ButtonAppxBackgroundColor}" Foreground="{DynamicResource ButtonAppxForegroundColor}" FontWeight="Bold" Name="WPFTab6BT">
|
||||
<ToggleButton.Content>
|
||||
<TextBlock FontSize="{DynamicResource TabButtonFontSize}" Background="Transparent" Foreground="{DynamicResource ButtonAppxForegroundColor}">
|
||||
<Underline>A</Underline>ppX Removal
|
||||
</TextBlock>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Search Bar and Action Buttons -->
|
||||
@@ -1690,6 +1698,51 @@
|
||||
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="AppX" Visibility="Collapsed" Name="WPFTab6">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Grid.Row="0" Margin="{DynamicResource TabContentMargin}">
|
||||
<Grid Background="Transparent">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Background="{DynamicResource MainBackgroundColor}" Orientation="Vertical" Grid.Row="0" Grid.Column="0" Margin="5">
|
||||
<Label Content="Selections:" FontSize="{DynamicResource FontSize}" VerticalAlignment="Center" Margin="2"/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,2,0,0">
|
||||
<Button Name="WPFSelectAllAppx" Content=" Select All " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||
<Button Name="WPFClearAppxSelection" Content=" Clear Selection " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Name="appxpanel" Grid.Row="1">
|
||||
<!-- Dynamic AppX package checkboxes -->
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="2" Style="{StaticResource BorderStyle}" Margin="5,15,5,5">
|
||||
<StackPanel Background="{DynamicResource MainBackgroundColor}" Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Padding="10" TextWrapping="Wrap" Foreground="{DynamicResource MainForegroundColor}">
|
||||
Note: Select the pre-installed Windows AppX packages you wish to remove and click 'Remove Selected'.
|
||||
<LineBreak/>These packages are removed for the current user and all new user profiles.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
<Border Grid.Row="1" Background="{DynamicResource MainBackgroundColor}" BorderBrush="{DynamicResource BorderColor}" BorderThickness="1" CornerRadius="5" HorizontalAlignment="Stretch" Padding="10">
|
||||
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<Button Name="WPFRemoveSelectedAppx" Content="Remove Selected" Margin="5" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
|
||||
</WrapPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
Reference in New Issue
Block a user