Refactor code structure for improved readability and maintainability (#473)

* Add ToolTips to Tweaks
This commit is contained in:
Jeffrey
2026-02-15 23:08:54 +01:00
committed by GitHub
parent 95dc490b6e
commit 65aabbc050
31 changed files with 2877 additions and 2813 deletions

1
.gitignore vendored
View File

@@ -2,4 +2,5 @@ LastSettings
SavedSettings
LastUsedSettings.json
CustomAppsList
Logs/*
Win11Debloat.log

View File

@@ -50,6 +50,7 @@
{
"GroupId": "SearchIcon",
"Label": "Taskbar search style",
"ToolTip": "This setting allows you to customize the appearance of the search box on the taskbar.",
"Category": "Taskbar",
"Priority": 2,
"Values": [
@@ -82,6 +83,7 @@
{
"GroupId": "MultiMon",
"Label": "Show taskbar apps on",
"ToolTip": "This setting allows you to choose where taskbar app buttons are shown when using multiple monitors.",
"Category": "Taskbar",
"Values": [
{
@@ -107,6 +109,7 @@
{
"GroupId": "CombineButtons",
"Label": "Combine taskbar buttons on the main display",
"ToolTip": "This setting allows you to choose how taskbar buttons are combined on the main display.",
"Category": "Taskbar",
"Values": [
{
@@ -132,6 +135,7 @@
{
"GroupId": "CombineMMButtons",
"Label": "Combine taskbar buttons on secondary displays",
"ToolTip": "This setting allows you to choose how taskbar buttons are combined on secondary displays.",
"Category": "Taskbar",
"Values": [
{
@@ -157,6 +161,7 @@
{
"GroupId": "ClearStart",
"Label": "Remove pinned apps from the start menu",
"ToolTip": "This setting allows you to quickly remove all pinned apps from the start menu.",
"Category": "Start Menu",
"Values": [
{
@@ -176,6 +181,7 @@
{
"GroupId": "ExplorerLocation",
"Label": "Open File Explorer to",
"ToolTip": "This setting allows you to choose the default location that File Explorer opens to.",
"Category": "File Explorer",
"Values": [
{
@@ -207,6 +213,7 @@
{
"GroupId": "ShowTabsInAltTab",
"Label": "Show tabs from apps when snapping or pressing Alt+Tab",
"ToolTip": "This setting allows you to choose whether to show tabs from apps (such as Edge browser tabs) when snapping windows or pressing Alt+Tab.",
"Category": "Multi-tasking",
"Priority": 10,
"Values": [
@@ -337,6 +344,7 @@
{
"FeatureId": "DisableTelemetry",
"Label": "telemetry, tracking & targeted ads",
"ToolTip": "This settings disables telemetry, diagnostic data collection, activity history, app-launch tracking and targeted ads. This limits the data that is sent to Microsoft about your device and usage.",
"Category": "Privacy & Suggested Content",
"Action": "Disable",
"RegistryKey": "Disable_Telemetry.reg",
@@ -349,6 +357,7 @@
{
"FeatureId": "DisableSuggestions",
"Label": "tips, tricks & suggested content throughout Windows",
"ToolTip": "Disabling this will disable various tips, tricks, suggestions and ads throughout Windows.",
"Category": "Privacy & Suggested Content",
"Action": "Disable",
"RegistryKey": "Disable_Windows_Suggestions.reg",
@@ -361,6 +370,7 @@
{
"FeatureId": "DisableLockscreenTips",
"Label": "tips & tricks on the lock screen",
"ToolTip": "Disabling this will turn off the tips, tricks and fun facts that appear on the lock screen.",
"Category": "Privacy & Suggested Content",
"Action": "Disable",
"RegistryKey": "Disable_Lockscreen_Tips.reg",
@@ -373,6 +383,7 @@
{
"FeatureId": "DisableDesktopSpotlight",
"Label": "Windows Spotlight for desktop",
"ToolTip": "Disabling this will turn off the 'Windows Spotlight' feature for the desktop background, which shows different background images and occasionally tips and fun facts on the desktop.",
"Category": "Privacy & Suggested Content",
"Action": "Disable",
"RegistryKey": "Disable_Desktop_Spotlight.reg",
@@ -385,6 +396,7 @@
{
"FeatureId": "DisableEdgeAds",
"Label": "ads, suggestions and newsfeed in Edge",
"ToolTip": "Disabling this will turn off various distractions from Microsoft Edge such as ads, suggestions and the MSN news feed. This setting uses policies, which means some settings will be locked.",
"Category": "Privacy & Suggested Content",
"Action": "Disable",
"RegistryKey": "Disable_Edge_Ads_And_Suggestions.reg",
@@ -397,6 +409,7 @@
{
"FeatureId": "DisableCopilot",
"Label": "Microsoft Copilot",
"ToolTip": "Disabling this will turn off and uninstall Microsoft Copilot, the AI assistant integrated throughout Windows.",
"Category": "AI",
"Action": "Disable",
"RegistryKey": "Disable_Copilot.reg",
@@ -409,6 +422,7 @@
{
"FeatureId": "DisableRecall",
"Label": "Windows Recall",
"ToolTip": "Disabling this will turn off Windows Recall, an AI-powered feature that provides quick access to recently used files, apps and activities.",
"Category": "AI",
"Action": "Disable",
"RegistryKey": "Disable_AI_Recall.reg",
@@ -421,6 +435,7 @@
{
"FeatureId": "DisableClickToDo",
"Label": "Click To Do, AI text & image analysis",
"ToolTip": "Disabling this will turn off Click To Do, which provides AI-powered text and image analysis features in Windows.",
"Category": "AI",
"Action": "Disable",
"RegistryKey": "Disable_Click_to_Do.reg",
@@ -433,6 +448,7 @@
{
"FeatureId": "DisableDVR",
"Label": "Xbox game/screen recording",
"ToolTip": "Disabling this will turn off the Xbox game/screen recording features included with the Game Bar app.",
"Category": "Gaming",
"Action": "Disable",
"RegistryKey": "Disable_DVR.reg",
@@ -445,6 +461,7 @@
{
"FeatureId": "DisableGameBarIntegration",
"Label": "Game Bar integration",
"ToolTip": "Disabling this will turn off the Game Bar integration features such as the Game Bar overlay that appears when pressing Win+G.",
"Category": "Gaming",
"Action": "Disable",
"RegistryKey": "Disable_Game_Bar_Integration.reg",
@@ -505,6 +522,7 @@
{
"FeatureId": "DisableStartRecommended",
"Label": "recommended section in the start menu",
"ToolTip": "Disabling this will hide the recommended section in the start menu, which shows recently added apps, recently opened files and app recommendations.",
"Category": "Start Menu",
"Action": "Hide",
"RegistryKey": "Disable_Start_Recommended.reg",
@@ -517,6 +535,7 @@
{
"FeatureId": "DisableBing",
"Label": "Bing web search & Copilot integration",
"ToolTip": "Disabling this will turn off Bing web search results and Copilot integration in the Windows search experience.",
"Category": "Start Menu",
"Action": "Disable",
"RegistryKey": "Disable_Bing_Cortana_In_Search.reg",
@@ -529,6 +548,7 @@
{
"FeatureId": "DisableStartPhoneLink",
"Label": "Phone Link integration in the start menu",
"ToolTip": "Disabling this will remove the Phone Link integration that appears in the start menu when you have a mobile device linked to your PC.",
"Category": "Start Menu",
"Action": "Disable",
"RegistryKey": "Disable_Phone_Link_In_Start.reg",
@@ -540,11 +560,12 @@
},
{
"FeatureId": "DisableSettings365Ads",
"Label": "Microsoft 365 ads in Settings Home",
"Label": "Microsoft 365 Copilot ads in Settings Home",
"ToolTip": "Disabling this will turn off the Microsoft 365 Copilot ads that appear in the Settings Home page.",
"Category": "Privacy & Suggested Content",
"Action": "Hide",
"RegistryKey": "Disable_Settings_365_Ads.reg",
"ApplyText": "> Disabling Microsoft 365 ads in Settings Home...",
"ApplyText": "> Disabling Microsoft 365 Copilot ads in Settings Home...",
"UndoAction": "Show",
"RegistryUndoKey": "Enable_Settings_365_Ads.reg",
"MinVersion": null,
@@ -553,7 +574,8 @@
{
"FeatureId": "DisableSettingsHome",
"Label": "Settings 'Home' page",
"Category": "Privacy & Suggested Content",
"ToolTip": "Removes the 'Home' page from the Settings app.",
"Category": "Other",
"Action": "Hide",
"RegistryKey": "Disable_Settings_Home.reg",
"ApplyText": "> Disabling the Settings Home page...",
@@ -565,6 +587,7 @@
{
"FeatureId": "DisableEdgeAI",
"Label": "AI features in Microsoft Edge",
"ToolTip": "Disabling this will turn off AI features in Microsoft Edge, such as the AI-powered sidebar and Copilot features. This setting uses policies, which means some settings will be locked.",
"Category": "AI",
"Action": "Disable",
"RegistryKey": "Disable_Edge_AI_Features.reg",
@@ -577,6 +600,7 @@
{
"FeatureId": "DisablePaintAI",
"Label": "AI features in Paint",
"ToolTip": "Disabling this will turn off AI features in Paint, such as the AI-powered image generation and editing tools.",
"Category": "AI",
"Action": "Disable",
"RegistryKey": "Disable_Paint_AI_Features.reg",
@@ -589,6 +613,7 @@
{
"FeatureId": "DisableNotepadAI",
"Label": "AI features in Notepad",
"ToolTip": "Disabling this will turn off AI features in Notepad, such as the AI-powered writing suggestions.",
"Category": "AI",
"Action": "Disable",
"RegistryKey": "Disable_Notepad_AI_Features.reg",
@@ -601,6 +626,7 @@
{
"FeatureId": "EnableDarkMode",
"Label": "theme for system and apps",
"ToolTip": "Enabling this will set the default app mode and system theme to dark mode, which changes the appearance of Windows and supported apps.",
"Category": "Appearance",
"Action": "Enable dark",
"RegistryKey": "Enable_Dark_Mode.reg",
@@ -613,6 +639,7 @@
{
"FeatureId": "DisableDragTray",
"Label": "'Drag Tray' for sharing & moving files",
"ToolTip": "The Drag Tray is a new feature for sharing & moving files in Windows 11, it appears at the top of the screen when dragging files.",
"Category": "System",
"Action": "Disable",
"RegistryKey": "Disable_Share_Drag_Tray.reg",
@@ -625,6 +652,7 @@
{
"FeatureId": "RevertContextMenu",
"Label": "context menu style",
"ToolTip": "This will restore the classic Windows 10 style context menu instead of the modern Windows 11 style menu.",
"Category": "System",
"Action": "Use classic Windows 10",
"RegistryKey": "Disable_Show_More_Options_Context_Menu.reg",
@@ -637,6 +665,7 @@
{
"FeatureId": "DisableMouseAcceleration",
"Label": "Enhance Pointer Precision (mouse acceleration)",
"ToolTip": "By default, Windows has a mouse acceleration enabled, which can make the mouse movement less predictable, especially for gaming. Disabling this will make the mouse movement more consistent.",
"Category": "System",
"Action": "Disable",
"RegistryKey": "Disable_Enhance_Pointer_Precision.reg",
@@ -649,6 +678,7 @@
{
"FeatureId": "DisableStickyKeys",
"Label": "Sticky Keys keyboard shortcut (5x shift)",
"ToolTip": "Disabling this will prevent the Sticky Keys dialog from appearing when you press the Shift key 5 times in a row.",
"Category": "System",
"Action": "Disable",
"RegistryKey": "Disable_Sticky_Keys_Shortcut.reg",
@@ -661,6 +691,7 @@
{
"FeatureId": "DisableWindowSnapping",
"Label": "window snapping",
"ToolTip": "Disabling this will turn off the ability to snap windows to the sides or corners of the screen.",
"Category": "Multi-tasking",
"Priority": 1,
"Action": "Disable",
@@ -674,6 +705,7 @@
{
"FeatureId": "DisableSnapAssist",
"Label": "showing app suggestions when snapping windows",
"ToolTip": "Disabling this will turn off app suggestions when you snap windows to the sides or corners of the screen.",
"Category": "Multi-tasking",
"Priority": 2,
"Action": "Disable",
@@ -687,6 +719,7 @@
{
"FeatureId": "DisableSnapLayouts",
"Label": "snap layout flyout at top of screen and on maximize button",
"ToolTip": "Disabling this will turn off the snap layout flyout that appears when you hover over the maximize button or drag windows to the top of the screen.",
"Category": "Multi-tasking",
"Priority": 3,
"Action": "Hide",
@@ -748,6 +781,7 @@
{
"FeatureId": "TaskbarAlignLeft",
"Label": "taskbar alignment",
"ToolTip": "By default, Windows 11 has the taskbar buttons centered. Enabling this will align the taskbar buttons to the left, similar to previous versions of Windows.",
"Category": "Taskbar",
"Priority": 1,
"Action": "Left",
@@ -809,6 +843,7 @@
{
"FeatureId": "HideTaskview",
"Label": "'Task view' button on the taskbar",
"ToolTip": "Disabling this will turn off the 'Task view' button on the taskbar, which allows you to see all your open windows and virtual desktops.",
"Category": "Taskbar",
"Priority": 3,
"Action": "Hide",
@@ -822,6 +857,7 @@
{
"FeatureId": "DisableWidgets",
"Label": "widgets on the taskbar & lock screen",
"ToolTip": "Disabling this will turn off the widgets features in Windows, including the widgets button on the taskbar and the widgets that can appear on the lock screen.",
"Category": "Taskbar",
"Priority": 4,
"Action": "Disable",
@@ -835,6 +871,7 @@
{
"FeatureId": "HideChat",
"Label": "Chat (meet now) icon on the taskbar",
"ToolTip": "Disabling this will turn off the Chat (meet now) icon on the taskbar.",
"Category": "Taskbar",
"Priority": 5,
"Action": "Hide",
@@ -848,6 +885,7 @@
{
"FeatureId": "DisableFastStartup",
"Label": "fast start-up",
"ToolTip": "Fast Start-up helps your PC start faster after shutdown by saving a system image to disk. Disabling Fast Start-up can help with certain issues, but may result in slightly longer boot times.",
"Category": "System",
"Action": "Disable",
"RegistryKey": "Disable_Fast_Startup.reg",
@@ -860,6 +898,7 @@
{
"FeatureId": "DisableBitlockerAutoEncryption",
"Label": "BitLocker automatic device encryption",
"ToolTip": "For devices that support it, Windows 11 automatically enables BitLocker device encryption. Disabling this will turn off automatic encryption of the device, but you can still manually enable BitLocker encryption if desired.",
"Category": "System",
"Action": "Disable",
"RegistryKey": "Disable_Bitlocker_Auto_Encryption.reg",
@@ -872,6 +911,7 @@
{
"FeatureId": "DisableModernStandbyNetworking",
"Label": "Modern Standby network connectivity",
"ToolTip": "By default, devices that support Modern Standby maintain network connectivity while in sleep mode to allow for features like receiving calls or messages while asleep. Disabling network connectivity during Modern Standby can help save battery life.",
"Category": "System",
"Action": "Disable",
"RegistryKey": "Disable_Modern_Standby_Networking.reg",
@@ -884,6 +924,7 @@
{
"FeatureId": "EnableEndTask",
"Label": "'End Task' option in taskbar context menu",
"ToolTip": "When enabled, adds an 'End Task' option to the right-click context menu for apps in the taskbar, allowing you to quickly force close apps without opening Task Manager.",
"Category": "Taskbar",
"Priority": 6,
"Action": "Show",
@@ -897,6 +938,7 @@
{
"FeatureId": "EnableLastActiveClick",
"Label": "'Last Active Click' behavior for taskbar apps",
"ToolTip": "When enabled, clicking on an app in the taskbar will switch to the last active window of that app, instead of showing the thumbnail preview.",
"Category": "Taskbar",
"Priority": 7,
"Action": "Enable",
@@ -1066,6 +1108,7 @@
{
"FeatureId": "ShowKnownFileExt",
"Label": "file extensions for known file types",
"ToolTip": "Enabling this will show file extensions for known file types. By default, Windows hides file extensions for known file types which can lead to confusion and security risks.",
"Category": "File Explorer",
"Action": "Show",
"RegistryKey": "Show_Extensions_For_Known_File_Types.reg",
@@ -1078,6 +1121,7 @@
{
"FeatureId": "ShowHiddenFolders",
"Label": "hidden files, folders and drives",
"ToolTip": "By default, Windows hides certain files, folders and drives to prevent accidental modification or deletion. Enabling this will show hidden files, folders and drives in File Explorer.",
"Category": "File Explorer",
"Action": "Show",
"RegistryKey": "Show_Hidden_Folders.reg",
@@ -1090,6 +1134,7 @@
{
"FeatureId": "HideHome",
"Label": "'Home' from navigation pane",
"ToolTip": "Hides the 'Home' section from the File Explorer navigation pane.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Hide_Home_from_Explorer.reg",
@@ -1102,6 +1147,7 @@
{
"FeatureId": "HideGallery",
"Label": "'Gallery' from navigation pane",
"ToolTip": "Hides the 'Gallery' section from the File Explorer navigation pane.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Hide_Gallery_from_Explorer.reg",
@@ -1114,6 +1160,7 @@
{
"FeatureId": "HideDupliDrive",
"Label": "duplicate removable drive entries",
"ToolTip": "When you connect a removable drive, Windows shows the drive both under 'This PC' and in the navigation pane with its own entry. Hiding duplicate removable drive entries will only show the drive under 'This PC' and remove it from the navigation pane.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Hide_duplicate_removable_drives_from_navigation_pane_of_File_Explorer.reg",
@@ -1126,6 +1173,7 @@
{
"FeatureId": "AddFoldersToThisPC",
"Label": "common folders back to 'This PC' page",
"ToolTip": "This setting will add common folders like Desktop, Documents, Downloads, Music, Pictures and Videos back to the 'This PC' page in File Explorer.",
"Category": "File Explorer",
"Action": "Add",
"RegistryKey": "Add_All_Folders_Under_This_PC.reg",
@@ -1138,6 +1186,7 @@
{
"FeatureId": "DisableTransparency",
"Label": "transparency effects",
"ToolTip": "Disabling this will turn off transparency effects on Windows and interfaces. Which can help improve performance on older hardware.",
"Category": "Appearance",
"Action": "Disable",
"RegistryKey": "Disable_Transparency.reg",
@@ -1150,6 +1199,7 @@
{
"FeatureId": "DisableAnimations",
"Label": "animations and visual effects",
"ToolTip": "Disabling this will turn off animations and some visual effects in Windows, which can make the interface feel snappier and more responsive, especially on older hardware.",
"Category": "Appearance",
"Action": "Disable",
"RegistryKey": "Disable_Animations.reg",
@@ -1162,6 +1212,7 @@
{
"FeatureId": "DisableUpdateASAP",
"Label": "updates as soon as they're available",
"ToolTip": "Disabling this will prevent your PC from being among the first to receive new non-security updates. Your PC will still receive these updates eventually.",
"Category": "Windows Update",
"Action": "Prevent getting",
"RegistryKey": "Disable_Update_ASAP.reg",
@@ -1174,6 +1225,7 @@
{
"FeatureId": "PreventUpdateAutoReboot",
"Label": "automatic restarts after updates while signed in",
"ToolTip": "Disabling this will prevent your PC from automatically restarting after updates while any user is signed in.",
"Category": "Windows Update",
"Action": "Prevent",
"RegistryKey": "Prevent_Auto_Reboot.reg",
@@ -1186,6 +1238,7 @@
{
"FeatureId": "DisableDeliveryOptimization",
"Label": "sharing downloaded updates with other PCs",
"ToolTip": "Disabling this will prevent your PC from sharing downloaded updates with other PCs on the local network or on the internet. This also prevents your PC from downloading updates from other PCs.",
"Category": "Windows Update",
"Action": "Disable",
"RegistryKey": "Disable_Delivery_Optimization.reg",
@@ -1210,6 +1263,7 @@
{
"FeatureId": "HideIncludeInLibrary",
"Label": "'Include in library' option in the context menu",
"ToolTip": "Hides the 'Include in library' option from the File Explorer context menu.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Disable_Include_in_library_from_context_menu.reg",
@@ -1222,6 +1276,7 @@
{
"FeatureId": "HideGiveAccessTo",
"Label": "'Give access to' option in the context menu",
"ToolTip": "Hides the 'Give access to' option from the File Explorer context menu.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Disable_Give_access_to_context_menu.reg",
@@ -1234,6 +1289,7 @@
{
"FeatureId": "HideShare",
"Label": "'Share' option in the context menu",
"ToolTip": "Hides the 'Share' option from the File Explorer context menu.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Disable_Share_from_context_menu.reg",
@@ -1246,6 +1302,7 @@
{
"FeatureId": "HideOnedrive",
"Label": "'OneDrive' folder from navigation pane",
"ToolTip": "Hides the 'OneDrive' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Hide_Onedrive_Folder.reg",
@@ -1258,6 +1315,7 @@
{
"FeatureId": "Hide3dObjects",
"Label": "'3D objects' folder under 'This PC'",
"ToolTip": "Hides the '3D objects' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Hide_3D_Objects_Folder.reg",
@@ -1270,6 +1328,7 @@
{
"FeatureId": "HideMusic",
"Label": "'Music' folder under 'This PC'",
"ToolTip": "Hides the 'Music' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
"Action": "Hide",
"RegistryKey": "Hide_Music_Folder.reg",
@@ -1282,6 +1341,7 @@
{
"FeatureId": "DisableBraveBloat",
"Label": "bloat in Brave browser (AI, Crypto, etc.)",
"ToolTip": "Disabling this will turn off Brave's built-in AI features, Crypto wallet, News, Rewards, Talk and VPN.",
"Category": "Other",
"Action": "Disable",
"RegistryKey": "Disable_Brave_Bloat.reg",

View File

@@ -4,7 +4,10 @@ setlocal EnableDelayedExpansion
:: Set Windows Terminal installation paths. (Default and Scoop installation)
set "wtDefaultPath=%LOCALAPPDATA%\Microsoft\WindowsApps\wt.exe"
set "wtScoopPath=%USERPROFILE%\scoop\apps\windows-terminal\current\wt.exe"
set "logFile=%~dp0Win11Debloat.log"
set "logFile=%~dp0Logs\Win11Debloat-Run.log"
:: Ensure Logs folder exists
if not exist "%~dp0Logs" mkdir "%~dp0Logs"
:: Determine which terminal exists
if exist "%wtDefaultPath%" (

View File

@@ -13,11 +13,11 @@
<Window.Resources>
<Style x:Key="HyperlinkStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="#0078D4"/>
<Setter Property="Foreground" Value="{DynamicResource ButtonBg}"/>
<Setter Property="Cursor" Value="Hand"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="#106EBE"/>
<Setter Property="Foreground" Value="{DynamicResource ButtonHover}"/>
</Trigger>
</Style.Triggers>
</Style>
@@ -196,7 +196,7 @@
<!-- Content -->
<StackPanel Grid.Row="2" Margin="24,20">
<!-- Donation Message -->
<TextBlock Text="If you found this tool helpful, please consider making a small donation to help keep it going."
<TextBlock Text="Win11Debloat is a passion project that I maintain in my free time. If you've found this tool useful, please consider making a small donation to support its development. I really appreciate it!"
FontSize="14"
Foreground="{DynamicResource FgColor}"
TextWrapping="Wrap"
@@ -211,7 +211,7 @@
<TextBlock x:Name="KofiLinkIcon"
Grid.Column="0"
FontSize="14"
FontSize="16"
Style="{StaticResource HyperlinkStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -223,12 +223,12 @@
<TextBlock x:Name="KofiLink"
Grid.Column="1"
FontSize="14"
FontSize="16"
Style="{StaticResource HyperlinkStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="SemiBold"
Text="Support on Ko-fi"/>
Text="Support me on Ko-fi"/>
</Grid>
</StackPanel>
</Grid>

View File

@@ -0,0 +1,20 @@
# Prints the header for the script
function PrintHeader {
param (
$title
)
$fullTitle = " Win11Debloat Script - $title"
if ($script:Params.ContainsKey("Sysprep")) {
$fullTitle = "$fullTitle (Sysprep mode)"
}
else {
$fullTitle = "$fullTitle (User: $(GetUserName))"
}
Clear-Host
Write-Host "-------------------------------------------------------------------------------------------"
Write-Host $fullTitle
Write-Host "-------------------------------------------------------------------------------------------"
}

View File

@@ -0,0 +1,66 @@
# Prints all pending changes that will be made by the script
function PrintPendingChanges {
Write-Output "Win11Debloat will make the following changes:"
if ($script:Params['CreateRestorePoint']) {
Write-Output "- $($script:Features['CreateRestorePoint'].Label)"
}
foreach ($parameterName in $script:Params.Keys) {
if ($script:ControlParams -contains $parameterName) {
continue
}
# Print parameter description
switch ($parameterName) {
'Apps' {
continue
}
'CreateRestorePoint' {
continue
}
'RemoveApps' {
$appsList = GenerateAppsList
if ($appsList.Count -eq 0) {
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
Write-Output ""
continue
}
Write-Output "- Remove $($appsList.Count) apps:"
Write-Host $appsList -ForegroundColor DarkGray
continue
}
'RemoveAppsCustom' {
$appsList = LoadAppsFromFile $script:CustomAppsListFilePath
if ($appsList.Count -eq 0) {
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
Write-Output ""
continue
}
Write-Output "- Remove $($appsList.Count) apps:"
Write-Host $appsList -ForegroundColor DarkGray
continue
}
default {
if ($script:Features -and $script:Features.ContainsKey($parameterName)) {
$action = $script:Features[$parameterName].Action
$message = $script:Features[$parameterName].Label
Write-Output "- $action $message"
}
else {
# Fallback: show the parameter name if no feature description is available
Write-Output "- $parameterName"
}
continue
}
}
}
Write-Output ""
Write-Output ""
Write-Output "Press enter to execute the script or press CTRL+C to quit..."
Read-Host | Out-Null
}

View File

@@ -0,0 +1,28 @@
# Shows the CLI app removal menu and prompts the user to select which apps to remove.
function ShowCLIAppRemoval {
PrintHeader "App Removal"
Write-Output "> Opening app selection form..."
$result = Show-AppSelectionWindow
if ($result -eq $true) {
Write-Output "You have selected $($script:SelectedApps.Count) apps for removal"
AddParameter 'RemoveAppsCustom'
SaveSettings
# Suppress prompt if Silent parameter was passed
if (-not $Silent) {
Write-Output ""
Write-Output ""
Write-Output "Press enter to remove the selected apps or press CTRL+C to quit..."
Read-Host | Out-Null
PrintHeader "App Removal"
}
}
else {
Write-Host "Selection was cancelled, no apps have been removed" -ForegroundColor Red
Write-Output ""
}
}

View File

@@ -0,0 +1,33 @@
# Shows the CLI default mode app removal options. Loops until a valid option is selected.
function ShowCLIDefaultModeAppRemovalOptions {
PrintHeader 'Default Mode'
Write-Host "Please note: The default selection of apps includes Microsoft Teams, Spotify, Sticky Notes and more. Select option 2 to verify and change what apps are removed by the script" -ForegroundColor DarkGray
Write-Host ""
Do {
Write-Host "Options:" -ForegroundColor Yellow
Write-Host " (n) Don't remove any apps" -ForegroundColor Yellow
Write-Host " (1) Only remove the default selection of apps" -ForegroundColor Yellow
Write-Host " (2) Manually select which apps to remove" -ForegroundColor Yellow
$RemoveAppsInput = Read-Host "Do you want to remove any apps? Apps will be removed for all users (n/1/2)"
# Show app selection form if user entered option 3
if ($RemoveAppsInput -eq '2') {
$result = Show-AppSelectionWindow
if ($result -ne $true) {
# User cancelled or closed app selection, change RemoveAppsInput so the menu will be shown again
Write-Host ""
Write-Host "Cancelled application selection, please try again" -ForegroundColor Red
$RemoveAppsInput = 'c'
}
Write-Host ""
}
}
while ($RemoveAppsInput -ne 'n' -and $RemoveAppsInput -ne '0' -and $RemoveAppsInput -ne '1' -and $RemoveAppsInput -ne '2')
return $RemoveAppsInput
}

View File

@@ -0,0 +1,55 @@
# Show CLI default mode options for removing apps, or set selection if RunDefaults or RunDefaultsLite parameter was passed
function ShowCLIDefaultModeOptions {
if ($RunDefaults) {
$RemoveAppsInput = '1'
}
elseif ($RunDefaultsLite) {
$RemoveAppsInput = '0'
}
else {
$RemoveAppsInput = ShowCLIDefaultModeAppRemovalOptions
if ($RemoveAppsInput -eq '2' -and ($script:SelectedApps.contains('Microsoft.XboxGameOverlay') -or $script:SelectedApps.contains('Microsoft.XboxGamingOverlay')) -and
$( Read-Host -Prompt "Disable Game Bar integration and game/screen recording? This also stops ms-gamingoverlay and ms-gamebar popups (y/n)" ) -eq 'y') {
$DisableGameBarIntegrationInput = $true;
}
}
PrintHeader 'Default Mode'
# Add default settings based on user input
try {
# Select app removal options based on user input
switch ($RemoveAppsInput) {
'1' {
AddParameter 'RemoveApps'
AddParameter 'Apps' 'Default'
}
'2' {
AddParameter 'RemoveAppsCustom'
if ($DisableGameBarIntegrationInput) {
AddParameter 'DisableDVR'
AddParameter 'DisableGameBarIntegration'
}
}
}
# Load settings from DefaultSettings.json and add to params
LoadSettings -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
}
catch {
Write-Error "Failed to load settings from DefaultSettings.json file: $_"
AwaitKeyToExit
}
SaveSettings
# Skip change summary if Silent parameter was passed
if ($Silent) {
return
}
PrintPendingChanges
PrintHeader 'Default Mode'
}

View File

@@ -0,0 +1,16 @@
# Shows the CLI last used settings from LastUsedSettings.json file, displays pending changes and prompts the user to apply them.
function ShowCLILastUsedSettings {
PrintHeader 'Custom Mode'
try {
# Load settings from LastUsedSettings.json and add to params
LoadSettings -filePath $script:SavedSettingsFilePath -expectedVersion "1.0"
}
catch {
Write-Error "Failed to load settings from LastUsedSettings.json file: $_"
AwaitKeyToExit
}
PrintPendingChanges
PrintHeader 'Custom Mode'
}

View File

@@ -0,0 +1,30 @@
# Shows the CLI menu options and prompts the user to select one. Loops until a valid option is selected.
function ShowCLIMenuOptions {
Do {
$ModeSelectionMessage = "Please select an option (1/2)"
PrintHeader 'Menu'
Write-Host "(1) Default mode: Quickly apply the recommended changes"
Write-Host "(2) App removal mode: Select & remove apps, without making other changes"
# Only show this option if SavedSettings file exists
if (Test-Path $script:SavedSettingsFilePath) {
Write-Host "(3) Quickly apply your last used settings"
$ModeSelectionMessage = "Please select an option (1/2/3)"
}
Write-Host ""
Write-Host ""
$Mode = Read-Host $ModeSelectionMessage
if (($Mode -eq '3') -and -not (Test-Path $script:SavedSettingsFilePath)) {
$Mode = $null
}
}
while ($Mode -ne '1' -and $Mode -ne '2' -and $Mode -ne '3')
return $Mode
}

View File

@@ -0,0 +1,44 @@
# Read Apps.json and return list of app objects with optional filtering
function LoadAppsDetailsFromJson {
param (
[switch]$OnlyInstalled,
[string]$InstalledList = "",
[switch]$InitialCheckedFromJson
)
$apps = @()
try {
$jsonContent = Get-Content -Path $script:AppsListFilePath -Raw | ConvertFrom-Json
}
catch {
Write-Error "Failed to read Apps.json: $_"
return $apps
}
foreach ($appData in $jsonContent.Apps) {
$appId = $appData.AppId.Trim()
if ($appId.length -eq 0) { continue }
if ($OnlyInstalled) {
if (-not ($InstalledList -like ("*$appId*")) -and -not (Get-AppxPackage -Name $appId)) {
continue
}
if (($appId -eq "Microsoft.Edge") -and -not ($InstalledList -like "* Microsoft.Edge *")) {
continue
}
}
$displayName = if ($appData.FriendlyName) { "$($appData.FriendlyName) ($appId)" } else { $appId }
$isChecked = if ($InitialCheckedFromJson) { $appData.SelectedByDefault } else { $false }
$apps += [PSCustomObject]@{
AppId = $appId
DisplayName = $displayName
IsChecked = $isChecked
Description = $appData.Description
SelectedByDefault = $appData.SelectedByDefault
}
}
return $apps
}

View File

@@ -0,0 +1,45 @@
# Returns list of apps from the specified file, it trims the app names and removes any comments
function LoadAppsFromFile {
param (
$appsFilePath
)
$appsList = @()
if (-not (Test-Path $appsFilePath)) {
return $appsList
}
try {
# Check if file is JSON or text format
if ($appsFilePath -like "*.json") {
# JSON file format
$jsonContent = Get-Content -Path $appsFilePath -Raw | ConvertFrom-Json
Foreach ($appData in $jsonContent.Apps) {
$appId = $appData.AppId.Trim()
$selectedByDefault = $appData.SelectedByDefault
if ($selectedByDefault -and $appId.length -gt 0) {
$appsList += $appId
}
}
}
else {
# Legacy text file format
Foreach ($app in (Get-Content -Path $appsFilePath | Where-Object { $_ -notmatch '^#.*' -and $_ -notmatch '^\s*$' } )) {
if (-not ($app.IndexOf('#') -eq -1)) {
$app = $app.Substring(0, $app.IndexOf('#'))
}
$app = $app.Trim()
$appString = $app.Trim('*')
$appsList += $appString
}
}
return $appsList
}
catch {
Write-Error "Unable to read apps list from file: $appsFilePath"
AwaitKeyToExit
}
}

View File

@@ -0,0 +1,32 @@
# Loads a JSON file from the specified path and returns the parsed object
# Returns $null if the file doesn't exist or if parsing fails
function LoadJsonFile {
param (
[string]$filePath,
[string]$expectedVersion = $null,
[switch]$optionalFile
)
if (-not (Test-Path $filePath)) {
if (-not $optionalFile) {
Write-Error "File not found: $filePath"
}
return $null
}
try {
$jsonContent = Get-Content -Path $filePath -Raw | ConvertFrom-Json
# Validate version if specified
if ($expectedVersion -and $jsonContent.Version -and $jsonContent.Version -ne $expectedVersion) {
Write-Error "$(Split-Path $filePath -Leaf) version mismatch (expected $expectedVersion, found $($jsonContent.Version))"
return $null
}
return $jsonContent
}
catch {
Write-Error "Failed to parse JSON file: $filePath"
return $null
}
}

View File

@@ -0,0 +1,31 @@
# Loads settings from a JSON file and adds them to script params
function LoadSettings {
param (
[string]$filePath,
[string]$expectedVersion = "1.0"
)
$settingsJson = LoadJsonFile -filePath $filePath -expectedVersion $expectedVersion
if (-not $settingsJson -or -not $settingsJson.Settings) {
throw "Failed to load settings from $(Split-Path $filePath -Leaf)"
}
# Get current Windows build version
$WinVersion = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' CurrentBuild
foreach ($setting in $settingsJson.Settings) {
if ($setting.Value -eq $false) {
continue
}
$feature = $script:Features[$setting.Name]
# Check version and feature compatibility using Features.json
if (($feature.MinVersion -and $WinVersion -lt $feature.MinVersion) -or ($feature.MaxVersion -and $WinVersion -gt $feature.MaxVersion) -or ($feature.FeatureId -eq 'DisableModernStandbyNetworking' -and (-not $script:ModernStandbySupported))) {
continue
}
AddParameter $setting.Name $setting.Value
}
}

View File

@@ -0,0 +1,15 @@
# Saves the provided appsList to the CustomAppsList file
function SaveCustomAppsListToFile {
param (
$appsList
)
$script:SelectedApps = $appsList
# Create file that stores selected apps if it doesn't exist
if (-not (Test-Path $script:CustomAppsListFilePath)) {
$null = New-Item $script:CustomAppsListFilePath -ItemType File
}
Set-Content -Path $script:CustomAppsListFilePath -Value $script:SelectedApps
}

View File

@@ -0,0 +1,26 @@
# Saves the current settings, excluding control parameters, to 'LastUsedSettings.json' file
function SaveSettings {
$settings = @{
"Version" = "1.0"
"Settings" = @()
}
foreach ($param in $script:Params.Keys) {
if ($script:ControlParams -notcontains $param) {
$value = $script:Params[$param]
$settings.Settings += @{
"Name" = $param
"Value" = $value
}
}
}
try {
$settings | ConvertTo-Json -Depth 10 | Set-Content $script:SavedSettingsFilePath
}
catch {
Write-Output ""
Write-Host "Error: Failed to save settings to LastUsedSettings.json file" -ForegroundColor Red
}
}

View File

@@ -0,0 +1,24 @@
# Returns a validated list of apps based on the provided appsList and the supported apps from Apps.json
function ValidateAppslist {
param (
$appsList
)
$supportedAppsList = (LoadAppsDetailsFromJson | ForEach-Object { $_.AppId })
$validatedAppsList = @()
# Validate provided appsList against supportedAppsList
Foreach ($app in $appsList) {
$app = $app.Trim()
$appString = $app.Trim('*')
if ($supportedAppsList -notcontains $appString) {
Write-Host "Removal of app '$appString' is not supported and will be skipped" -ForegroundColor Yellow
continue
}
$validatedAppsList += $appString
}
return $validatedAppsList
}

View File

@@ -0,0 +1,80 @@
# Applies settings from a JSON object to UI controls (checkboxes and comboboxes)
# Used by LoadDefaultsBtn and LoadLastUsedBtn in the UI
function ApplySettingsToUiControls {
param (
$window,
$settingsJson,
$uiControlMappings
)
if (-not $settingsJson -or -not $settingsJson.Settings) {
return $false
}
# First, reset all tweaks to "No Change" (index 0) or unchecked
if ($uiControlMappings) {
foreach ($comboName in $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
}
}
}
# Also uncheck RestorePointCheckBox
$restorePointCheckBox = $window.FindName('RestorePointCheckBox')
if ($restorePointCheckBox) {
$restorePointCheckBox.IsChecked = $false
}
# Apply settings from JSON
foreach ($setting in $settingsJson.Settings) {
if ($setting.Value -ne $true) { continue }
$paramName = $setting.Name
# Handle RestorePointCheckBox separately
if ($paramName -eq 'CreateRestorePoint') {
if ($restorePointCheckBox) { $restorePointCheckBox.IsChecked = $true }
continue
}
if ($uiControlMappings) {
foreach ($comboName in $uiControlMappings.Keys) {
$mapping = $uiControlMappings[$comboName]
if ($mapping.Type -eq 'group') {
$i = 1
foreach ($val in $mapping.Values) {
if ($val.FeatureIds -contains $paramName) {
$control = $window.FindName($comboName)
if ($control -and $control.Visibility -eq 'Visible') {
if ($control -is [System.Windows.Controls.ComboBox]) {
$control.SelectedIndex = $i
}
}
break
}
$i++
}
}
elseif ($mapping.Type -eq 'feature') {
if ($mapping.FeatureId -eq $paramName) {
$control = $window.FindName($comboName)
if ($control -and $control.Visibility -eq 'Visible') {
if ($control -is [System.Windows.Controls.CheckBox]) {
$control.IsChecked = $true
}
elseif ($control -is [System.Windows.Controls.ComboBox]) {
$control.SelectedIndex = 1
}
}
}
}
}
}
}
return $true
}

View File

@@ -0,0 +1,71 @@
# Attaches shift-click selection behavior to a checkbox in an apps panel
# Parameters:
# - $checkbox: The checkbox to attach the behavior to
# - $appsPanel: The StackPanel containing checkbox items
# - $lastSelectedCheckboxRef: A reference to a variable storing the last clicked checkbox
# - $updateStatusCallback: Optional callback to update selection status
function AttachShiftClickBehavior {
param (
[System.Windows.Controls.CheckBox]$checkbox,
[System.Windows.Controls.StackPanel]$appsPanel,
[ref]$lastSelectedCheckboxRef,
[scriptblock]$updateStatusCallback = $null
)
# Use a closure to capture the parameters
$checkbox.Add_PreviewMouseLeftButtonDown({
param(
$sender,
$e
)
$isShiftPressed = [System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::LeftShift) -or
[System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::RightShift)
if ($isShiftPressed -and $null -ne $lastSelectedCheckboxRef.Value) {
# Get all visible checkboxes in the panel
$visibleCheckboxes = @()
foreach ($child in $appsPanel.Children) {
if ($child -is [System.Windows.Controls.CheckBox] -and $child.Visibility -eq 'Visible') {
$visibleCheckboxes += $child
}
}
# Find indices of the last selected and current checkbox
$lastIndex = -1
$currentIndex = -1
for ($i = 0; $i -lt $visibleCheckboxes.Count; $i++) {
if ($visibleCheckboxes[$i] -eq $lastSelectedCheckboxRef.Value) {
$lastIndex = $i
}
if ($visibleCheckboxes[$i] -eq $sender) {
$currentIndex = $i
}
}
if ($lastIndex -ge 0 -and $currentIndex -ge 0 -and $lastIndex -ne $currentIndex) {
$startIndex = [Math]::Min($lastIndex, $currentIndex)
$endIndex = [Math]::Max($lastIndex, $currentIndex)
$shouldDeselect = $sender.IsChecked
# Set all checkboxes in the range to the appropriate state
for ($i = $startIndex; $i -le $endIndex; $i++) {
$visibleCheckboxes[$i].IsChecked = -not $shouldDeselect
}
if ($updateStatusCallback) {
& $updateStatusCallback
}
# Mark the event as handled to prevent the default toggle behavior
$e.Handled = $true
return
}
}
# Update the last selected checkbox reference for next time
$lastSelectedCheckboxRef.Value = $sender
}.GetNewClosure())
}

View File

@@ -0,0 +1,9 @@
# Checks if the system is set to use dark mode for apps
function GetSystemUsesDarkMode {
try {
return (Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' -Name 'AppsUseLightTheme').AppsUseLightTheme -eq 0
}
catch {
return $false
}
}

View File

@@ -0,0 +1,69 @@
# Sets resource colors for a WPF window based on dark mode preference
function SetWindowThemeResources {
param (
$window,
[bool]$usesDarkMode
)
if ($usesDarkMode) {
$window.Resources.Add("BgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#202020")))
$window.Resources.Add("FgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFFFFF")))
$window.Resources.Add("CardBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#2b2b2b")))
$window.Resources.Add("BorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#404040")))
$window.Resources.Add("ButtonBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#404040")))
$window.Resources.Add("CheckBoxBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#272727")))
$window.Resources.Add("CheckBoxBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#808080")))
$window.Resources.Add("CheckBoxHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#343434")))
$window.Resources.Add("ComboBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#373737")))
$window.Resources.Add("ComboHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#434343")))
$window.Resources.Add("ComboItemBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#2c2c2c")))
$window.Resources.Add("ComboItemHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#383838")))
$window.Resources.Add("ComboItemSelectedColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#343434")))
$window.Resources.Add("AccentColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFD700")))
$window.Resources.Add("ButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#434343")))
$window.Resources.Add("ButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#989898")))
$window.Resources.Add("SecondaryButtonBg", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#393939")))
$window.Resources.Add("SecondaryButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#2a2a2a")))
$window.Resources.Add("SecondaryButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#1e1e1e")))
$window.Resources.Add("SecondaryButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#3b3b3b")))
$window.Resources.Add("SecondaryButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#787878")))
$window.Resources.Add("InputFocusColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#1f1f1f")))
$window.Resources.Add("ScrollBarThumbColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#3d3d3d")))
$window.Resources.Add("ScrollBarThumbHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#4b4b4b")))
}
else {
$window.Resources.Add("BgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f3f3f3")))
$window.Resources.Add("FgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#000000")))
$window.Resources.Add("CardBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#fbfbfb")))
$window.Resources.Add("BorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ededed")))
$window.Resources.Add("ButtonBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#d3d3d3")))
$window.Resources.Add("CheckBoxBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f5f5f5")))
$window.Resources.Add("CheckBoxBorderColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#898989")))
$window.Resources.Add("CheckBoxHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ececec")))
$window.Resources.Add("ComboBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFFFFF")))
$window.Resources.Add("ComboHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f8f8f8")))
$window.Resources.Add("ComboItemBgColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f9f9f9")))
$window.Resources.Add("ComboItemHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f0f0f0")))
$window.Resources.Add("ComboItemSelectedColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f3f3f3")))
$window.Resources.Add("AccentColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ffae00")))
$window.Resources.Add("ButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#bfbfbf")))
$window.Resources.Add("ButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#ffffff")))
$window.Resources.Add("SecondaryButtonBg", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#fbfbfb")))
$window.Resources.Add("SecondaryButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f6f6f6")))
$window.Resources.Add("SecondaryButtonPressed", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f0f0f0")))
$window.Resources.Add("SecondaryButtonDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#f7f7f7")))
$window.Resources.Add("SecondaryButtonTextDisabled", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#b7b7b7")))
$window.Resources.Add("InputFocusColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#fbfbfb")))
$window.Resources.Add("ScrollBarThumbColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#b9b9b9")))
$window.Resources.Add("ScrollBarThumbHoverColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#8b8b8b")))
}
$window.Resources.Add("ButtonBg", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#0067c0")))
$window.Resources.Add("ButtonHover", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#1E88E5")))
$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("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")))
}

View File

@@ -0,0 +1,95 @@
function Show-AboutDialog {
param (
[Parameter(Mandatory=$false)]
[System.Windows.Window]$Owner = $null
)
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
$usesDarkMode = GetSystemUsesDarkMode
# Determine owner window
$ownerWindow = if ($Owner) { $Owner } else { $script:GuiWindow }
# Show overlay if owner window exists
$overlay = $null
if ($ownerWindow) {
try {
$overlay = $ownerWindow.FindName('ModalOverlay')
if ($overlay) {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
}
}
catch { }
}
# Load XAML from file
$xaml = Get-Content -Path $script:AboutWindowSchema -Raw
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
try {
$aboutWindow = [System.Windows.Markup.XamlReader]::Load($reader)
}
finally {
$reader.Close()
}
# Set owner to owner window if it exists
if ($ownerWindow) {
try {
$aboutWindow.Owner = $ownerWindow
}
catch { }
}
# Apply theme resources
SetWindowThemeResources -window $aboutWindow -usesDarkMode $usesDarkMode
# Get UI elements
$titleBar = $aboutWindow.FindName('TitleBar')
$versionText = $aboutWindow.FindName('VersionText')
$projectLink = $aboutWindow.FindName('ProjectLink')
$kofiLink = $aboutWindow.FindName('KofiLink')
$closeButton = $aboutWindow.FindName('CloseButton')
# Set version
$versionText.Text = $script:Version
# Title bar drag to move window
$titleBar.Add_MouseLeftButtonDown({
$aboutWindow.DragMove()
})
# Project link click handler
$projectLink.Add_MouseLeftButtonDown({
Start-Process "https://github.com/Raphire/Win11Debloat"
})
# Ko-fi link click handler
$kofiLink.Add_MouseLeftButtonDown({
Start-Process "https://ko-fi.com/raphire"
})
# Close button handler
$closeButton.Add_Click({
$aboutWindow.Close()
})
# Handle Escape key to close
$aboutWindow.Add_KeyDown({
param($sender, $e)
if ($e.Key -eq 'Escape') {
$aboutWindow.Close()
}
})
# Show dialog
$aboutWindow.ShowDialog() | Out-Null
# Hide overlay after dialog closes
if ($overlay) {
try {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
}
catch { }
}
}

View File

@@ -0,0 +1,161 @@
# Shows application selection window that allows the user to select what apps they want to remove or keep
function Show-AppSelectionWindow {
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
$usesDarkMode = GetSystemUsesDarkMode
# Show overlay if main window exists
$overlay = $null
if ($script:GuiWindow) {
try {
$overlay = $script:GuiWindow.FindName('ModalOverlay')
if ($overlay) {
$script:GuiWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
}
}
catch { }
}
# Load XAML from file
$xaml = Get-Content -Path $script:AppSelectionSchema -Raw
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
try {
$window = [System.Windows.Markup.XamlReader]::Load($reader)
}
finally {
$reader.Close()
}
# Set owner to main window if it exists
if ($script:GuiWindow) {
try {
$window.Owner = $script:GuiWindow
}
catch { }
}
SetWindowThemeResources -window $window -usesDarkMode $usesDarkMode
$appsPanel = $window.FindName('AppsPanel')
$checkAllBox = $window.FindName('CheckAllBox')
$onlyInstalledBox = $window.FindName('OnlyInstalledBox')
$confirmBtn = $window.FindName('ConfirmBtn')
$loadingIndicator = $window.FindName('LoadingAppsIndicator')
$titleBar = $window.FindName('TitleBar')
# Track the last selected checkbox for shift-click range selection
$script:AppSelectionWindowLastSelectedCheckbox = $null
# Loads apps into the apps UI
function LoadApps {
# Show loading indicator
$loadingIndicator.Visibility = 'Visible'
$window.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{})
$appsPanel.Children.Clear()
$listOfApps = ""
if ($onlyInstalledBox.IsChecked -and ($script:WingetInstalled -eq $true)) {
# Attempt to get a list of installed apps via WinGet, times out after 10 seconds
$listOfApps = GetInstalledAppsViaWinget -TimeOut 10
if (-not $listOfApps) {
# Show error that the script was unable to get list of apps from WinGet
Show-MessageBox -Message 'Unable to load list of installed apps via WinGet.' -Title 'Error' -Button 'OK' -Icon 'Error' -Owner $window | Out-Null
$onlyInstalledBox.IsChecked = $false
}
}
$appsToAdd = LoadAppsDetailsFromJson -OnlyInstalled:$onlyInstalledBox.IsChecked -InstalledList $listOfApps -InitialCheckedFromJson:$true
# Reset the last selected checkbox when loading a new list
$script:AppSelectionWindowLastSelectedCheckbox = $null
# Sort apps alphabetically and add to panel
$appsToAdd | Sort-Object -Property DisplayName | ForEach-Object {
$checkbox = New-Object System.Windows.Controls.CheckBox
$checkbox.Content = $_.DisplayName
$checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $_.DisplayName)
$checkbox.Tag = $_.AppId
$checkbox.IsChecked = $_.IsChecked
$checkbox.ToolTip = $_.Description
$checkbox.Style = $window.Resources["AppsPanelCheckBoxStyle"]
# Attach shift-click behavior for range selection
AttachShiftClickBehavior -checkbox $checkbox -appsPanel $appsPanel -lastSelectedCheckboxRef ([ref]$script:AppSelectionWindowLastSelectedCheckbox)
$appsPanel.Children.Add($checkbox) | Out-Null
}
# Hide loading indicator
$loadingIndicator.Visibility = 'Collapsed'
}
# Event handlers
$titleBar.Add_MouseLeftButtonDown({
$window.DragMove()
})
$checkAllBox.Add_Checked({
foreach ($child in $appsPanel.Children) {
if ($child -is [System.Windows.Controls.CheckBox]) {
$child.IsChecked = $true
}
}
})
$checkAllBox.Add_Unchecked({
foreach ($child in $appsPanel.Children) {
if ($child -is [System.Windows.Controls.CheckBox]) {
$child.IsChecked = $false
}
}
})
$onlyInstalledBox.Add_Checked({ LoadApps })
$onlyInstalledBox.Add_Unchecked({ LoadApps })
$confirmBtn.Add_Click({
$selectedApps = @()
foreach ($child in $appsPanel.Children) {
if ($child -is [System.Windows.Controls.CheckBox] -and $child.IsChecked) {
$selectedApps += $child.Tag
}
}
# Close form without saving if no apps were selected
if ($selectedApps.Count -eq 0) {
$window.Close()
return
}
if ($selectedApps -contains "Microsoft.WindowsStore" -and -not $Silent) {
$result = Show-MessageBox -Message 'Are you sure you wish to uninstall the Microsoft Store? This app cannot easily be reinstalled.' -Title 'Are you sure?' -Button 'YesNo' -Icon 'Warning' -Owner $window
if ($result -eq 'No') {
return
}
}
SaveCustomAppsListToFile -appsList $selectedApps
$window.DialogResult = $true
})
# Load apps after window is shown (allows UI to render first)
$window.Add_ContentRendered({
$window.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ LoadApps })
})
# Show the window and return dialog result
$result = $window.ShowDialog()
# Hide overlay after dialog closes
if ($overlay) {
try {
$script:GuiWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
}
catch { }
}
return $result
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,154 @@
# Shows a Windows 11 styled custom message box
function Show-MessageBox {
param (
[Parameter(Mandatory=$true)]
[string]$Message,
[Parameter(Mandatory=$false)]
[string]$Title = "Win11Debloat",
[Parameter(Mandatory=$false)]
[ValidateSet('OK', 'OKCancel', 'YesNo')]
[string]$Button = 'OK',
[Parameter(Mandatory=$false)]
[ValidateSet('None', 'Information', 'Warning', 'Error', 'Question')]
[string]$Icon = 'None',
[Parameter(Mandatory=$false)]
[System.Windows.Window]$Owner = $null
)
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
$usesDarkMode = GetSystemUsesDarkMode
# Determine owner window - use provided Owner, or fall back to main GUI window
$ownerWindow = if ($Owner) { $Owner } else { $script:GuiWindow }
# Show overlay if owner window exists
$overlay = $null
if ($ownerWindow) {
try {
$overlay = $ownerWindow.FindName('ModalOverlay')
if ($overlay) {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
}
}
catch { }
}
# Load XAML from file
$xaml = Get-Content -Path $script:MessageBoxSchema -Raw
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
try {
$msgWindow = [System.Windows.Markup.XamlReader]::Load($reader)
}
finally {
$reader.Close()
}
# Set owner to owner window if it exists
if ($ownerWindow) {
try {
$msgWindow.Owner = $ownerWindow
}
catch { }
}
# Apply theme resources
SetWindowThemeResources -window $msgWindow -usesDarkMode $usesDarkMode
# Get UI elements
$titleText = $msgWindow.FindName('TitleText')
$messageText = $msgWindow.FindName('MessageText')
$iconText = $msgWindow.FindName('IconText')
$button1 = $msgWindow.FindName('Button1')
$button2 = $msgWindow.FindName('Button2')
$titleBar = $msgWindow.FindName('TitleBar')
# Set title and message
$titleText.Text = $Title
$messageText.Text = $Message
# Configure icon
switch ($Icon) {
'Information' {
$iconText.Text = [char]0xE946
$iconText.Foreground = $msgWindow.FindResource('InformationIconColor')
$iconText.Visibility = 'Visible'
}
'Warning' {
$iconText.Text = [char]0xE7BA
$iconText.Foreground = $msgWindow.FindResource('WarningIconColor')
$iconText.Visibility = 'Visible'
}
'Error' {
$iconText.Text = [char]0xEA39
$iconText.Foreground = $msgWindow.FindResource('ErrorIconColor')
$iconText.Visibility = 'Visible'
}
'Question' {
$iconText.Text = [char]0xE897
$iconText.Foreground = $msgWindow.FindResource('QuestionIconColor')
$iconText.Visibility = 'Visible'
}
default {
$iconText.Visibility = 'Collapsed'
}
}
# Configure buttons - store result in window's Tag property
switch ($Button) {
'OK' {
$button1.Content = 'OK'
$button1.Add_Click({ $msgWindow.Tag = 'OK'; $msgWindow.Close() })
$button2.Visibility = 'Collapsed'
}
'OKCancel' {
$button1.Content = 'OK'
$button2.Content = 'Cancel'
$button1.Add_Click({ $msgWindow.Tag = 'OK'; $msgWindow.Close() })
$button2.Add_Click({ $msgWindow.Tag = 'Cancel'; $msgWindow.Close() })
$button2.Visibility = 'Visible'
}
'YesNo' {
$button1.Content = 'Yes'
$button2.Content = 'No'
$button1.Add_Click({ $msgWindow.Tag = 'Yes'; $msgWindow.Close() })
$button2.Add_Click({ $msgWindow.Tag = 'No'; $msgWindow.Close() })
$button2.Visibility = 'Visible'
}
}
# Title bar drag to move window
$titleBar.Add_MouseLeftButtonDown({
$msgWindow.DragMove()
})
# Handle Escape key to close
$msgWindow.Add_KeyDown({
param($sender, $e)
if ($e.Key -eq 'Escape') {
if ($Button -eq 'OK') {
$msgWindow.Tag = 'OK'
} else {
$msgWindow.Tag = 'Cancel'
}
$msgWindow.Close()
}
})
# Show dialog and return result from Tag
$msgWindow.ShowDialog() | Out-Null
# Hide overlay after dialog closes
if ($overlay) {
try {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
}
catch { }
}
return $msgWindow.Tag
}

View File

@@ -121,7 +121,7 @@ catch {
if (Test-Path "$env:TEMP/Win11Debloat") {
Write-Output ""
Write-Output "> Cleaning up old Win11Debloat folder..."
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log | Remove-Item -Recurse -Force
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log,Logs | Remove-Item -Recurse -Force
}
Write-Output ""
@@ -171,7 +171,7 @@ if (Test-Path "$env:TEMP/Win11Debloat") {
Write-Output "> Cleaning up..."
# Cleanup, remove Win11Debloat directory
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log | Remove-Item -Recurse -Force
Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log,Logs | Remove-Item -Recurse -Force
}
Write-Output ""

File diff suppressed because it is too large Load Diff