diff --git a/Config/Apps.json b/Config/Apps.json
index bfd5f98..65e579f 100644
--- a/Config/Apps.json
+++ b/Config/Apps.json
@@ -841,6 +841,20 @@
"SelectedByDefault": false,
"Recommendation": "optional"
},
+ {
+ "FriendlyName": "Windows Web Experience Pack",
+ "AppId": "MicrosoftWindows.Client.WebExperience",
+ "Description": "Helps deliver and update certain features, like Widgets, through the Microsoft Store",
+ "SelectedByDefault": false,
+ "Recommendation": "optional"
+ },
+ {
+ "FriendlyName": "Widgets Platform Runtime",
+ "AppId": "Microsoft.WidgetsPlatformRuntime",
+ "Description": "Runtime required for Windows Widgets to function",
+ "SelectedByDefault": false,
+ "Recommendation": "optional"
+ },
{
"FriendlyName": "HP AI Experience Center",
"AppId": "AD2F1837.HPAIExperienceCenter",
diff --git a/Config/DefaultSettings.json b/Config/DefaultSettings.json
index 2d7c8a1..815b492 100644
--- a/Config/DefaultSettings.json
+++ b/Config/DefaultSettings.json
@@ -29,10 +29,6 @@
"Name": "DisableStoreSearchSuggestions",
"Value": true
},
- {
- "Name": "DisableSearchHighlights",
- "Value": true
- },
{
"Name": "DisableCopilot",
"Value": true
@@ -65,10 +61,6 @@
"Name": "DisableDragTray",
"Value": true
},
- {
- "Name": "DisableFastStartup",
- "Value": true
- },
{
"Name": "Hide3dObjects",
"Value": true
diff --git a/Config/Features.json b/Config/Features.json
index ff19d79..9f8d2cd 100644
--- a/Config/Features.json
+++ b/Config/Features.json
@@ -187,6 +187,7 @@
"Label": "Open File Explorer to",
"ToolTip": "This setting allows you to choose the default location that File Explorer opens to.",
"Category": "File Explorer",
+ "Priority": 1,
"Values": [
{
"Label": "Home",
@@ -214,6 +215,39 @@
}
]
},
+ {
+ "GroupId": "DriveLetterPosition",
+ "Label": "Drive letter position",
+ "ToolTip": "This setting allows you to choose where drive letters are shown in File Explorer.",
+ "Category": "File Explorer",
+ "Priority": 20,
+ "Values": [
+ {
+ "Label": "Show drive letters after drive label (Default)",
+ "FeatureIds": [
+ "ShowDriveLettersLast"
+ ]
+ },
+ {
+ "Label": "Show drive letters before drive label",
+ "FeatureIds": [
+ "ShowDriveLettersFirst"
+ ]
+ },
+ {
+ "Label": "Show network drive letters before drive label",
+ "FeatureIds": [
+ "ShowNetworkDriveLettersFirst"
+ ]
+ },
+ {
+ "Label": "Hide all drive letters",
+ "FeatureIds": [
+ "HideDriveLetters"
+ ]
+ }
+ ]
+ },
{
"GroupId": "ShowTabsInAltTab",
"Label": "Show tabs from apps when snapping or pressing Alt+Tab",
@@ -1007,7 +1041,7 @@
},
{
"FeatureId": "DisableBitlockerAutoEncryption",
- "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.",
+ "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. Drives that are already encrypted with BitLocker will remain encrypted when this setting is applied.",
"Category": "System",
"Action": "Disable BitLocker automatic device encryption",
"ApplyText": "Disabling BitLocker automatic device encryption...",
@@ -1219,6 +1253,7 @@
"FeatureId": "ShowKnownFileExt",
"ToolTip": "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",
+ "Priority": 2,
"Action": "Show file extensions for known file types",
"ApplyText": "Showing file extensions for known file types...",
"UndoAction": "Hide file extensions for known file types",
@@ -1232,6 +1267,7 @@
"FeatureId": "ShowHiddenFolders",
"ToolTip": "By default, Windows hides certain files, folders and drives to prevent accidental modification or deletion. Turn this on to show all files in File Explorer.",
"Category": "File Explorer",
+ "Priority": 3,
"Action": "Show hidden files, folders and drives",
"ApplyText": "Showing hidden files, folders and drives...",
"UndoAction": "Hide hidden files, folders and drives",
@@ -1241,10 +1277,25 @@
"MinVersion": null,
"MaxVersion": null
},
+ {
+ "FeatureId": "HideDupliDrive",
+ "ToolTip": "By default, Windows shows removable drives both under 'This PC' and in the navigation pane with its own entry. Enable this setting to only show removable drives under 'This PC'.",
+ "Category": "File Explorer",
+ "Priority": 4,
+ "Action": "Hide duplicate removable drive entries",
+ "ApplyText": "Hiding duplicate removable drive entries from the File Explorer navigation pane...",
+ "UndoAction": "Show duplicate removable drive entries",
+ "UndoText": "Showing duplicate removable drive entries...",
+ "RegistryKey": "Hide_duplicate_removable_drives_from_navigation_pane_of_File_Explorer.reg",
+ "RegistryUndoKey": "Show_duplicate_removable_drives_in_navigation_pane_of_File_Explorer.reg",
+ "MinVersion": null,
+ "MaxVersion": null
+ },
{
"FeatureId": "HideHome",
"ToolTip": "Hides the 'Home' section from the File Explorer navigation pane.",
"Category": "File Explorer",
+ "Priority": 5,
"Action": "Hide 'Home' from navigation pane",
"ApplyText": "Hiding 'Home' from the File Explorer navigation pane...",
"UndoAction": "Show 'Home' from navigation pane",
@@ -1258,6 +1309,7 @@
"FeatureId": "HideGallery",
"ToolTip": "Hides the 'Gallery' section from the File Explorer navigation pane.",
"Category": "File Explorer",
+ "Priority": 6,
"Action": "Hide 'Gallery' from navigation pane",
"ApplyText": "Hiding 'Gallery' from the File Explorer navigation pane...",
"UndoAction": "Show 'Gallery' from navigation pane",
@@ -1267,32 +1319,6 @@
"MinVersion": 22000,
"MaxVersion": null
},
- {
- "FeatureId": "HideDupliDrive",
- "ToolTip": "By default, Windows shows removable drives both under 'This PC' and in the navigation pane with its own entry. Enable this setting to only show removable drives under 'This PC'.",
- "Category": "File Explorer",
- "Action": "Hide duplicate removable drive entries",
- "ApplyText": "Hiding duplicate removable drive entries from the File Explorer navigation pane...",
- "UndoAction": "Show duplicate removable drive entries",
- "UndoText": "Showing duplicate removable drive entries...",
- "RegistryKey": "Hide_duplicate_removable_drives_from_navigation_pane_of_File_Explorer.reg",
- "RegistryUndoKey": "Show_duplicate_removable_drives_in_navigation_pane_of_File_Explorer.reg",
- "MinVersion": null,
- "MaxVersion": null
- },
- {
- "FeatureId": "AddFoldersToThisPC",
- "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 common folders back to 'This PC' page",
- "ApplyText": "Adding all common folders (Desktop, Downloads, etc.) back to 'This PC' in File Explorer...",
- "UndoAction": "Remove common folders from 'This PC' page",
- "UndoText": "Removing common folders from 'This PC' page...",
- "RegistryKey": "Add_All_Folders_Under_This_PC.reg",
- "RegistryUndoKey": "Remove_All_Folders_Under_This_PC.reg",
- "MinVersion": 22000,
- "MaxVersion": null
- },
{
"FeatureId": "DisableTransparency",
"ToolTip": "This will disable transparency effects on Windows and interfaces. Which can help improve performance on older hardware.",
@@ -1371,49 +1397,11 @@
"MinVersion": null,
"MaxVersion": null
},
- {
- "FeatureId": "HideIncludeInLibrary",
- "ToolTip": "Hides the 'Include in library' option from the File Explorer context menu.",
- "Category": "File Explorer",
- "Action": "Hide 'Include in library' option in the context menu",
- "ApplyText": "Hiding 'Include in library' in the context menu...",
- "UndoAction": "Show 'Include in library' option in the context menu",
- "UndoText": "Showing 'Include in library' option in the context menu...",
- "RegistryKey": "Disable_Include_in_library_from_context_menu.reg",
- "RegistryUndoKey": "Enable_Include_in_library_in_context_menu.reg",
- "MinVersion": null,
- "MaxVersion": 21999
- },
- {
- "FeatureId": "HideGiveAccessTo",
- "ToolTip": "Hides the 'Give access to' option from the File Explorer context menu.",
- "Category": "File Explorer",
- "Action": "Hide 'Give access to' option in the context menu",
- "ApplyText": "Hiding 'Give access to' in the context menu...",
- "UndoAction": "Show 'Give access to' option in the context menu",
- "UndoText": "Showing 'Give access to' option in the context menu...",
- "RegistryKey": "Disable_Give_access_to_context_menu.reg",
- "RegistryUndoKey": "Enable_Give_access_to_context_menu.reg",
- "MinVersion": null,
- "MaxVersion": 21999
- },
- {
- "FeatureId": "HideShare",
- "ToolTip": "Hides the 'Share' option from the File Explorer context menu.",
- "Category": "File Explorer",
- "Action": "Hide 'Share' option in the context menu",
- "ApplyText": "Hiding 'Share' in the context menu...",
- "UndoAction": "Show 'Share' option in the context menu",
- "UndoText": "Showing 'Share' option in the context menu...",
- "RegistryKey": "Disable_Share_from_context_menu.reg",
- "RegistryUndoKey": "Enable_Share_in_context_menu.reg",
- "MinVersion": null,
- "MaxVersion": 21999
- },
{
"FeatureId": "HideOnedrive",
"ToolTip": "Hides the 'OneDrive' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
+ "Priority": 7,
"Action": "Hide 'OneDrive' folder from navigation pane",
"ApplyText": "Hiding the 'OneDrive' folder from the File Explorer navigation pane...",
"UndoAction": "Show 'OneDrive' folder from navigation pane",
@@ -1421,12 +1409,13 @@
"RegistryKey": "Hide_Onedrive_Folder.reg",
"RegistryUndoKey": "Show_Onedrive_Folder.reg",
"MinVersion": null,
- "MaxVersion": 21999
+ "MaxVersion": null
},
{
"FeatureId": "Hide3dObjects",
"ToolTip": "Hides the '3D objects' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
+ "Priority": 8,
"Action": "Hide '3D objects' folder from navigation pane",
"ApplyText": "Hiding the '3D objects' folder from the File Explorer navigation pane...",
"UndoAction": "Show '3D objects' folder in the File Explorer navigation pane",
@@ -1440,6 +1429,7 @@
"FeatureId": "HideMusic",
"ToolTip": "Hides the 'Music' folder from the File Explorer navigation pane.",
"Category": "File Explorer",
+ "Priority": 9,
"Action": "Hide 'Music' folder from navigation pane",
"ApplyText": "Hiding the 'Music' folder from the File Explorer navigation pane...",
"UndoAction": "Show 'Music' folder in the File Explorer navigation pane",
@@ -1449,6 +1439,62 @@
"MinVersion": null,
"MaxVersion": 21999
},
+ {
+ "FeatureId": "AddFoldersToThisPC",
+ "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",
+ "Priority": 10,
+ "Action": "Add common folders back to 'This PC' page",
+ "ApplyText": "Adding all common folders (Desktop, Downloads, etc.) back to 'This PC' in File Explorer...",
+ "UndoAction": "Remove common folders from 'This PC' page",
+ "UndoText": "Removing common folders from 'This PC' page...",
+ "RegistryKey": "Add_All_Folders_Under_This_PC.reg",
+ "RegistryUndoKey": "Remove_All_Folders_Under_This_PC.reg",
+ "MinVersion": 22000,
+ "MaxVersion": null
+ },
+ {
+ "FeatureId": "HideIncludeInLibrary",
+ "ToolTip": "Hides the 'Include in library' option from the File Explorer context menu.",
+ "Category": "File Explorer",
+ "Priority": 11,
+ "Action": "Hide 'Include in library' option in the context menu",
+ "ApplyText": "Hiding 'Include in library' in the context menu...",
+ "UndoAction": "Show 'Include in library' option in the context menu",
+ "UndoText": "Showing 'Include in library' option in the context menu...",
+ "RegistryKey": "Disable_Include_in_library_from_context_menu.reg",
+ "RegistryUndoKey": "Enable_Include_in_library_in_context_menu.reg",
+ "MinVersion": null,
+ "MaxVersion": 21999
+ },
+ {
+ "FeatureId": "HideGiveAccessTo",
+ "ToolTip": "Hides the 'Give access to' option from the File Explorer context menu.",
+ "Category": "File Explorer",
+ "Priority": 12,
+ "Action": "Hide 'Give access to' option in the context menu",
+ "ApplyText": "Hiding 'Give access to' in the context menu...",
+ "UndoAction": "Show 'Give access to' option in the context menu",
+ "UndoText": "Showing 'Give access to' option in the context menu...",
+ "RegistryKey": "Disable_Give_access_to_context_menu.reg",
+ "RegistryUndoKey": "Enable_Give_access_to_context_menu.reg",
+ "MinVersion": null,
+ "MaxVersion": 21999
+ },
+ {
+ "FeatureId": "HideShare",
+ "ToolTip": "Hides the 'Share' option from the File Explorer context menu.",
+ "Category": "File Explorer",
+ "Priority": 13,
+ "Action": "Hide 'Share' option in the context menu",
+ "ApplyText": "Hiding 'Share' in the context menu...",
+ "UndoAction": "Show 'Share' option in the context menu",
+ "UndoText": "Showing 'Share' option in the context menu...",
+ "RegistryKey": "Disable_Share_from_context_menu.reg",
+ "RegistryUndoKey": "Enable_Share_in_context_menu.reg",
+ "MinVersion": null,
+ "MaxVersion": 21999
+ },
{
"FeatureId": "DisableBraveBloat",
"ToolTip": "This will disable Brave's built-in AI features, Crypto wallet, News, Rewards, Talk and VPN. This feature uses policies, which will lock down certain settings.",
@@ -1489,6 +1535,58 @@
"RequiresReboot": true,
"MinVersion": 22000,
"MaxVersion": null
+ },
+ {
+ "FeatureId": "ShowDriveLettersFirst",
+ "ToolTip": "This setting will show drive letters before the drive label in File Explorer.",
+ "Category": "File Explorer",
+ "Action": "Show all drive letters before drive label",
+ "ApplyText": "Showing drive letters before drive label...",
+ "UndoAction": "Show all drive letters after drive label",
+ "UndoText": "Showing drive letters after drive label...",
+ "RegistryKey": "Show_Drive_Letters_First.reg",
+ "RegistryUndoKey": "Undo/Show_Drive_Letters_Last.reg",
+ "MinVersion": null,
+ "MaxVersion": null
+ },
+ {
+ "FeatureId": "ShowDriveLettersLast",
+ "ToolTip": "This setting will show drive letters after the drive label in File Explorer (Default Windows behavior).",
+ "Category": "File Explorer",
+ "Action": "Show all drive letters after drive label",
+ "ApplyText": "Showing drive letters after drive label...",
+ "UndoAction": null,
+ "UndoText": null,
+ "RegistryKey": "Show_Drive_Letters_Last.reg",
+ "RegistryUndoKey": null,
+ "MinVersion": null,
+ "MaxVersion": null
+ },
+ {
+ "FeatureId": "ShowNetworkDriveLettersFirst",
+ "ToolTip": "This setting will show only network drive letters before the drive label in File Explorer.",
+ "Category": "File Explorer",
+ "Action": "Show network drive letters before drive label",
+ "ApplyText": "Showing network drive letters before drive label...",
+ "UndoAction": "Show all drive letters after drive label",
+ "UndoText": "Showing drive letters after drive label...",
+ "RegistryKey": "Show_Network_Drive_Letters_First.reg",
+ "RegistryUndoKey": "Undo/Show_Drive_Letters_Last.reg",
+ "MinVersion": null,
+ "MaxVersion": null
+ },
+ {
+ "FeatureId": "HideDriveLetters",
+ "ToolTip": "This setting will hide all drive letters from the File Explorer navigation pane and 'This PC'.",
+ "Category": "File Explorer",
+ "Action": "Hide all drive letters",
+ "ApplyText": "Hiding all drive letters...",
+ "UndoAction": "Show all drive letters after drive label",
+ "UndoText": "Showing drive letters after drive label...",
+ "RegistryKey": "Hide_Drive_Letters.reg",
+ "RegistryUndoKey": "Undo/Show_Drive_Letters_Last.reg",
+ "MinVersion": null,
+ "MaxVersion": null
}
]
}
diff --git a/README.md b/README.md
index 93ba13e..b93ac70 100755
--- a/README.md
+++ b/README.md
@@ -160,6 +160,7 @@ Below is an overview of the key features and functionality offered by Win11Deblo
- Add all common folders (Desktop, Downloads, etc.) back to 'This PC' in File Explorer.
- Hide the 3D objects, music or OneDrive folder from the File Explorer navigation pane.
- Hide the 'Include in library', 'Give access to' and 'Share' options from the context menu.
+- Change drive letter position or visibility in File Explorer.
#### Multi-tasking
diff --git a/Regfiles/Hide_Drive_Letters.reg b/Regfiles/Hide_Drive_Letters.reg
new file mode 100644
index 0000000..ecd2576
--- /dev/null
+++ b/Regfiles/Hide_Drive_Letters.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000002
diff --git a/Regfiles/Hide_Onedrive_Folder.reg b/Regfiles/Hide_Onedrive_Folder.reg
index d8e037c..c500982 100644
Binary files a/Regfiles/Hide_Onedrive_Folder.reg and b/Regfiles/Hide_Onedrive_Folder.reg differ
diff --git a/Regfiles/Show_Drive_Letters_First.reg b/Regfiles/Show_Drive_Letters_First.reg
new file mode 100644
index 0000000..7403a2e
--- /dev/null
+++ b/Regfiles/Show_Drive_Letters_First.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000004
diff --git a/Regfiles/Show_Drive_Letters_Last.reg b/Regfiles/Show_Drive_Letters_Last.reg
new file mode 100644
index 0000000..5362089
--- /dev/null
+++ b/Regfiles/Show_Drive_Letters_Last.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000000
diff --git a/Regfiles/Show_Network_Drive_Letters_First.reg b/Regfiles/Show_Network_Drive_Letters_First.reg
new file mode 100644
index 0000000..e8dad3e
--- /dev/null
+++ b/Regfiles/Show_Network_Drive_Letters_First.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000001
diff --git a/Regfiles/Sysprep/Hide_Drive_Letters.reg b/Regfiles/Sysprep/Hide_Drive_Letters.reg
new file mode 100644
index 0000000..b0c6820
--- /dev/null
+++ b/Regfiles/Sysprep/Hide_Drive_Letters.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000002
diff --git a/Regfiles/Sysprep/Hide_Onedrive_Folder.reg b/Regfiles/Sysprep/Hide_Onedrive_Folder.reg
index d8e037c..6a2caba 100644
Binary files a/Regfiles/Sysprep/Hide_Onedrive_Folder.reg and b/Regfiles/Sysprep/Hide_Onedrive_Folder.reg differ
diff --git a/Regfiles/Sysprep/Show_Drive_Letters_First.reg b/Regfiles/Sysprep/Show_Drive_Letters_First.reg
new file mode 100644
index 0000000..be8192f
--- /dev/null
+++ b/Regfiles/Sysprep/Show_Drive_Letters_First.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000004
diff --git a/Regfiles/Sysprep/Show_Drive_Letters_Last.reg b/Regfiles/Sysprep/Show_Drive_Letters_Last.reg
new file mode 100644
index 0000000..b44b896
--- /dev/null
+++ b/Regfiles/Sysprep/Show_Drive_Letters_Last.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000000
diff --git a/Regfiles/Sysprep/Show_Network_Drive_Letters_First.reg b/Regfiles/Sysprep/Show_Network_Drive_Letters_First.reg
new file mode 100644
index 0000000..d1ac10d
--- /dev/null
+++ b/Regfiles/Sysprep/Show_Network_Drive_Letters_First.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[hkey_users\default\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000001
diff --git a/Regfiles/Undo/Show_Drive_Letters_Last.reg b/Regfiles/Undo/Show_Drive_Letters_Last.reg
new file mode 100644
index 0000000..5362089
--- /dev/null
+++ b/Regfiles/Undo/Show_Drive_Letters_Last.reg
@@ -0,0 +1,4 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
+"ShowDriveLettersFirst"=dword:00000000
diff --git a/Regfiles/Undo/Show_Onedrive_folder.reg b/Regfiles/Undo/Show_Onedrive_folder.reg
index 10c77da..c4ec51f 100644
Binary files a/Regfiles/Undo/Show_Onedrive_folder.reg and b/Regfiles/Undo/Show_Onedrive_folder.reg differ
diff --git a/Schemas/ImportExportConfigWindow.xaml b/Schemas/ImportExportConfigWindow.xaml
index 17617c7..c76bbdc 100644
--- a/Schemas/ImportExportConfigWindow.xaml
+++ b/Schemas/ImportExportConfigWindow.xaml
@@ -43,16 +43,18 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+ Margin="0">
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
@@ -557,8 +556,8 @@
Margin="12,0,0,0"
FontSize="12"/>
-
-
-
+
+
+
+
+
+
+
+
@@ -756,15 +762,20 @@
-
+
+
+
+
+
+
-
-
+
+
@@ -895,9 +906,67 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1093,10 +1162,10 @@
-
+
-
-
+
+
@@ -1126,11 +1195,12 @@
+
-
+
false before Click handlers fire; restore desired mixed -> checked behavior.
+ $checkBox.WasIndeterminateBeforeClick = $false
+ $checkBox.IsChecked = $true
+ return $true
+ }
+
+ return ($checkBox.IsChecked -eq $true)
+ }
+
+ function SetTriStatePresetCheckBoxState {
+ param(
+ [System.Windows.Controls.CheckBox]$CheckBox,
+ [int]$Total,
+ [int]$Selected
+ )
+
+ if (-not $CheckBox) { return }
+
+ if ($Total -eq 0) {
+ $CheckBox.IsEnabled = $false
+ $CheckBox.IsChecked = $false
+ return
+ }
+
+ $CheckBox.IsEnabled = $true
+ if ($Selected -eq 0) {
+ $CheckBox.IsChecked = $false
+ }
+ elseif ($Selected -eq $Total) {
+ $CheckBox.IsChecked = $true
+ }
+ else {
+ $CheckBox.IsChecked = [System.Nullable[bool]]$null
+ }
+ }
+
+ function AnimateDropdownArrow {
+ param(
+ [System.Windows.Controls.TextBlock]$arrow,
+ [double]$angle
+ )
+
+ if (-not $arrow) { return }
+
+ $animation = New-Object System.Windows.Media.Animation.DoubleAnimation
+ $animation.To = $angle
+ $animation.Duration = [System.Windows.Duration]::new([System.TimeSpan]::FromMilliseconds(200))
+
+ $ease = New-Object System.Windows.Media.Animation.CubicEase
+ $ease.EasingMode = 'EaseOut'
+ $animation.EasingFunction = $ease
+
+ $arrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
+ }
# Load JSON-defined presets and build dynamic preset checkboxes
$script:JsonPresetCheckboxes = @()
@@ -249,16 +375,17 @@ function Show-MainWindow {
$checkbox.Content = $preset.Name
$checkbox.IsThreeState = $true
$checkbox.Style = $window.Resources['PresetCheckBoxStyle']
+ $checkbox.ToolTip = "Select $($preset.Name)"
$checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $preset.Name)
+ AttachTriStateClickBehavior -checkBox $checkbox
Add-Member -InputObject $checkbox -MemberType NoteProperty -Name 'PresetAppIds' -Value $preset.AppIds
$jsonPresetsPanel.Children.Add($checkbox) | Out-Null
$script:JsonPresetCheckboxes += $checkbox
$checkbox.Add_Click({
if ($script:UpdatingPresets) { return }
- $check = ($this.IsChecked -eq $true)
- if ($this.IsChecked -eq $null) { $this.IsChecked = $false; $check = $false }
$presetIds = $this.PresetAppIds
+ $check = NormalizeCheckboxState -checkBox $this
ApplyPresetToApps -MatchFilter { param($c) (@($c.AppIds) | Where-Object { $presetIds -contains $_ }).Count -gt 0 }.GetNewClosure() -Check $check
})
}
@@ -283,6 +410,7 @@ function Show-MainWindow {
# Guard flag to prevent preset handlers from firing when we update their state programmatically
$script:UpdatingPresets = $false
+ $script:UpdatingTweakPresets = $false
# Sort state for the app table
$script:SortColumn = 'Name'
@@ -413,19 +541,7 @@ function Show-MainWindow {
}
}
}
- if ($total -eq 0) {
- $checkbox.IsChecked = $false
- $checkbox.IsEnabled = $false
- } else {
- $checkbox.IsEnabled = $true
- if ($checked -eq 0) {
- $checkbox.IsChecked = $false
- } elseif ($checked -eq $total) {
- $checkbox.IsChecked = $true
- } else {
- $checkbox.IsChecked = [System.Nullable[bool]]$null
- }
- }
+ SetTriStatePresetCheckBoxState -CheckBox $checkbox -Total $total -Selected $checked
}
SetPresetState $presetDefaultApps { param($c) $c.SelectedByDefault -eq $true }
@@ -590,8 +706,8 @@ function Show-MainWindow {
$helpBtn.Tag = (GetWikiUrlForCategory -category $categoryName)
$helpBtn.Style = $window.Resources['CategoryHelpLinkButtonStyle']
$helpBtn.Add_Click({
- param($sender, $e)
- if ($sender.Tag) { Start-Process $sender.Tag }
+ param($button, $e)
+ if ($button.Tag) { Start-Process $button.Tag }
})
$headerRow.Children.Add($helpBtn) | Out-Null
@@ -701,7 +817,7 @@ function Show-MainWindow {
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
}
- $script:UiControlMappings[$comboName] = @{ Type='group'; Values = $group.Values; Label = $group.Label }
+ $script:UiControlMappings[$comboName] = @{ Type='group'; Values = $group.Values; Label = $group.Label; Category = $categoryName }
}
elseif ($item.Type -eq 'feature') {
$feature = $item.Data
@@ -721,7 +837,7 @@ function Show-MainWindow {
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
}
- $script:UiControlMappings[$comboName] = @{ Type='feature'; FeatureId = $feature.FeatureId; Action = $feature.Action }
+ $script:UiControlMappings[$comboName] = @{ Type='feature'; FeatureId = $feature.FeatureId; Action = $feature.Action; Category = $categoryName }
}
}
}
@@ -918,37 +1034,45 @@ function Show-MainWindow {
# Animate arrow when popup opens/closes, and lazily update preset states
$presetsPopup.Add_Opened({
UpdatePresetStates
- $animation = New-Object System.Windows.Media.Animation.DoubleAnimation
- $animation.To = 180
- $animation.Duration = [System.Windows.Duration]::new([System.TimeSpan]::FromMilliseconds(200))
- $animation.EasingFunction = New-Object System.Windows.Media.Animation.CubicEase
- $animation.EasingFunction.EasingMode = 'EaseOut'
- $presetsArrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
+ AnimateDropdownArrow -arrow $presetsArrow -angle 180
})
$presetsPopup.Add_Closed({
- $animation = New-Object System.Windows.Media.Animation.DoubleAnimation
- $animation.To = 0
- $animation.Duration = [System.Windows.Duration]::new([System.TimeSpan]::FromMilliseconds(200))
- $animation.EasingFunction = New-Object System.Windows.Media.Animation.CubicEase
- $animation.EasingFunction.EasingMode = 'EaseOut'
- $presetsArrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
+ AnimateDropdownArrow -arrow $presetsArrow -angle 0
$presetsBtn.IsChecked = $false
})
+ $tweaksPresetsPopup.Add_Opened({
+ UpdateTweakPresetStates
+ AnimateDropdownArrow -arrow $tweaksPresetsArrow -angle 180
+ })
+ $tweaksPresetsPopup.Add_Closed({
+ AnimateDropdownArrow -arrow $tweaksPresetsArrow -angle 0
+ $tweaksPresetsBtn.IsChecked = $false
+ })
+
# Close popup when clicking anywhere outside the popup or the presets button.
$window.Add_PreviewMouseDown({
- if (-not $presetsPopup.IsOpen) { return }
- if ($presetsPopup.Child -ne $null -and $presetsPopup.Child.IsMouseOver) { return }
+ $isAppPopupOpen = $presetsPopup.IsOpen
+ $isTweaksPopupOpen = $tweaksPresetsPopup.IsOpen
+ if (-not $isAppPopupOpen -and -not $isTweaksPopupOpen) { return }
+
+ if ($isAppPopupOpen -and $null -ne $presetsPopup.Child -and $presetsPopup.Child.IsMouseOver) { return }
+ if ($isTweaksPopupOpen -and $null -ne $tweaksPresetsPopup.Child -and $tweaksPresetsPopup.Child.IsMouseOver) { return }
+
$src = $_.OriginalSource -as [System.Windows.DependencyObject]
- if ($src -ne $null) {
- $inBtn = $presetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($presetsBtn, $src)
- if (-not $inBtn) { $presetsPopup.IsOpen = $false }
+ if ($null -ne $src) {
+ $inAppBtn = $presetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($presetsBtn, $src)
+ $inTweaksBtn = $tweaksPresetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($tweaksPresetsBtn, $src)
+
+ if ($isAppPopupOpen -and -not $inAppBtn) { $presetsPopup.IsOpen = $false }
+ if ($isTweaksPopupOpen -and -not $inTweaksBtn) { $tweaksPresetsPopup.IsOpen = $false }
}
})
# Close the preset menu when the main window loses focus (e.g., user switches to another app).
$window.Add_Deactivated({
if ($presetsPopup.IsOpen) { $presetsPopup.IsOpen = $false }
+ if ($tweaksPresetsPopup.IsOpen) { $tweaksPresetsPopup.IsOpen = $false }
})
# Toggle popup on button click
@@ -957,11 +1081,26 @@ function Show-MainWindow {
$presetsBtn.IsChecked = $presetsPopup.IsOpen
})
+ $tweaksPresetsBtn.Add_Click({
+ $tweaksPresetsPopup.IsOpen = -not $tweaksPresetsPopup.IsOpen
+ $tweaksPresetsBtn.IsChecked = $tweaksPresetsPopup.IsOpen
+ })
+
+ foreach ($presetCheckBox in @(
+ $presetDefaultApps,
+ $presetLastUsed,
+ $presetDefaultTweaksBtn,
+ $presetLastUsedTweaksBtn,
+ $presetPrivacyTweaksBtn,
+ $presetAITweaksBtn
+ )) {
+ AttachTriStateClickBehavior -checkBox $presetCheckBox
+ }
+
# Preset: Default selection
$presetDefaultApps.Add_Click({
if ($script:UpdatingPresets) { return }
- $check = ($this.IsChecked -eq $true)
- if ($this.IsChecked -eq $null) { $this.IsChecked = $false; $check = $false }
+ $check = NormalizeCheckboxState -checkBox $this
ApplyPresetToApps -MatchFilter { param($c) $c.SelectedByDefault -eq $true } -Check $check
})
@@ -1078,7 +1217,7 @@ function Show-MainWindow {
})
$appSearchBox.Add_KeyDown({
- param($sender, $e)
+ param($sourceControl, $e)
if ($e.Key -eq [System.Windows.Input.Key]::Enter -and $script:AppSearchMatches.Count -gt 0) {
# Reset background of current active match
$script:AppSearchMatches[$script:AppSearchMatchIndex].Background = $window.Resources["SearchHighlightColor"]
@@ -1201,7 +1340,7 @@ function Show-MainWindow {
# Add Ctrl+F keyboard shortcut to focus search box on current tab
$window.Add_KeyDown({
- param($sender, $e)
+ param($sourceControl, $e)
# Check if Ctrl+F was pressed
if ($e.Key -eq [System.Windows.Input.Key]::F -and
@@ -1728,6 +1867,9 @@ function Show-MainWindow {
# Initialize UI elements on window load
$window.Add_Loaded({
BuildDynamicTweaks
+ RefreshTweakPresetSources -defaultSettingsJson $defaultsJson -lastUsedSettingsJson $lastUsedSettingsJson
+ RegisterTweakPresetControlStateHandlers
+ UpdateTweakPresetStates
LoadAppsIntoMainUI
@@ -1770,61 +1912,279 @@ function Show-MainWindow {
UpdateNavigationButtons
})
- # Handle Load Defaults button
- $loadDefaultsBtn = $window.FindName('LoadDefaultsBtn')
- $loadDefaultsBtn.Add_Click({
- $defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
+ function BuildTweakPresetControlMap {
+ param($settingsJson)
- if (-not $defaultsJson) {
- Show-MessageBox -Message "Failed to load default settings file" -Title "Error" -Button 'OK' -Icon 'Error'
- return
+ $presetMap = @{}
+ if (-not $settingsJson -or -not $settingsJson.Settings -or -not $script:UiControlMappings) {
+ return $presetMap
}
-
- ApplySettingsToUiControls -window $window -settingsJson $defaultsJson -uiControlMappings $script:UiControlMappings
- })
- # Handle Load Last Used settings and Load Last Used apps
- $loadLastUsedBtn = $window.FindName('LoadLastUsedBtn')
+ # FeatureId -> control metadata, similar to ApplySettingsToUiControls lookup.
+ $featureIdIndex = @{}
+ foreach ($controlName in $script:UiControlMappings.Keys) {
+ $control = $window.FindName($controlName)
+ if (-not $control -or $control.Visibility -ne 'Visible') { continue }
+
+ $mapping = $script:UiControlMappings[$controlName]
+ if ($mapping.Type -eq 'group') {
+ $i = 1
+ foreach ($val in $mapping.Values) {
+ foreach ($fid in $val.FeatureIds) {
+ $featureIdIndex[$fid] = @{ ControlName = $controlName; Control = $control; MappingType = 'group'; Index = $i }
+ }
+ $i++
+ }
+ }
+ elseif ($mapping.Type -eq 'feature') {
+ $featureIdIndex[$mapping.FeatureId] = @{ ControlName = $controlName; Control = $control; MappingType = 'feature' }
+ }
+ }
+
+ foreach ($setting in $settingsJson.Settings) {
+ if ($setting.Value -ne $true) { continue }
+ if ($setting.Name -eq 'CreateRestorePoint') { continue }
+
+ $entry = $featureIdIndex[$setting.Name]
+ if (-not $entry) { continue }
+ if ($presetMap.ContainsKey($entry.ControlName)) { continue }
+
+ $controlType = if ($entry.Control -is [System.Windows.Controls.CheckBox]) { 'CheckBox' } else { 'ComboBox' }
+ $desiredValue = switch ($entry.MappingType) {
+ 'group' { $entry.Index }
+ default { if ($controlType -eq 'CheckBox') { $true } else { 1 } }
+ }
+
+ $presetMap[$entry.ControlName] = @{ Control = $entry.Control; ControlType = $controlType; DesiredValue = $desiredValue }
+ }
+
+ return $presetMap
+ }
+
+ function BuildCategoryTweakPresetMap {
+ param([string]$Category)
+
+ $presetMap = @{}
+ if (-not $script:UiControlMappings) { return $presetMap }
+
+ foreach ($controlName in $script:UiControlMappings.Keys) {
+ $mapping = $script:UiControlMappings[$controlName]
+ if ($mapping.Category -ne $Category) { continue }
+
+ $control = $window.FindName($controlName)
+ if (-not $control -or $control.Visibility -ne 'Visible') { continue }
+
+ $controlType = if ($control -is [System.Windows.Controls.CheckBox]) { 'CheckBox' } else { 'ComboBox' }
+ $desiredValue = if ($controlType -eq 'CheckBox') { $true } else { 1 }
+ $presetMap[$controlName] = @{ Control = $control; ControlType = $controlType; DesiredValue = $desiredValue }
+ }
+
+ return $presetMap
+ }
+
+ function GetSavedAppIdsFromSettingsJson {
+ param($settingsJson)
+
+ if (-not $settingsJson -or -not $settingsJson.Settings) {
+ return $null
+ }
+
+ $appsValue = $null
+ foreach ($setting in $settingsJson.Settings) {
+ if ($setting.Name -eq 'Apps' -and $setting.Value) {
+ $appsValue = $setting.Value
+ break
+ }
+ }
+
+ if (-not $appsValue) {
+ return $null
+ }
+
+ $savedAppIds = @()
+ if ($appsValue -is [string]) {
+ $savedAppIds = $appsValue.Split(',')
+ }
+ elseif ($appsValue -is [array]) {
+ $savedAppIds = $appsValue
+ }
+
+ $savedAppIds = $savedAppIds | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
+ if ($savedAppIds.Count -eq 0) {
+ return $null
+ }
+
+ return $savedAppIds
+ }
+
+ function ApplyTweakPresetMap {
+ param(
+ [hashtable]$PresetMap,
+ [bool]$Check
+ )
+
+ if (-not $PresetMap) {
+ $PresetMap = @{}
+ }
+
+ $wasUpdatingTweakPresets = [bool]$script:UpdatingTweakPresets
+ $script:UpdatingTweakPresets = $true
+ try {
+ foreach ($target in $PresetMap.Values) {
+ $control = $target.Control
+ if (-not $control) { continue }
+
+ if ($target.ControlType -eq 'CheckBox') {
+ $control.IsChecked = $Check
+ }
+ elseif ($target.ControlType -eq 'ComboBox') {
+ $desiredIndex = [int]$target.DesiredValue
+ if ($Check) {
+ $control.SelectedIndex = $desiredIndex
+ }
+ elseif ($control.SelectedIndex -eq $desiredIndex) {
+ $control.SelectedIndex = 0
+ }
+ }
+ }
+ }
+ finally {
+ $script:UpdatingTweakPresets = $wasUpdatingTweakPresets
+ }
+
+ if (-not $wasUpdatingTweakPresets) {
+ UpdateTweakPresetStates
+ }
+ }
+
+ function SetTweakPresetState {
+ param(
+ [System.Windows.Controls.CheckBox]$PresetCheckBox,
+ [hashtable]$PresetMap
+ )
+
+ if (-not $PresetCheckBox) { return }
+ if (-not $PresetMap) {
+ $PresetMap = @{}
+ }
+
+ $total = $PresetMap.Count
+ $selected = 0
+
+ foreach ($target in $PresetMap.Values) {
+ $control = $target.Control
+ if (-not $control) { continue }
+
+ if ($target.ControlType -eq 'CheckBox' -and $control.IsChecked -eq $true) {
+ $selected++
+ }
+ elseif ($target.ControlType -eq 'ComboBox' -and $control.SelectedIndex -eq [int]$target.DesiredValue) {
+ $selected++
+ }
+ }
+
+ SetTriStatePresetCheckBoxState -CheckBox $PresetCheckBox -Total $total -Selected $selected
+ }
+
+ function UpdateTweakPresetStates {
+ $script:UpdatingTweakPresets = $true
+ try {
+ SetTweakPresetState -PresetCheckBox $presetDefaultTweaksBtn -PresetMap $script:DefaultTweakPresetMap
+ if ($presetLastUsedTweaksBtn -and $presetLastUsedTweaksBtn.Visibility -ne 'Collapsed') {
+ SetTweakPresetState -PresetCheckBox $presetLastUsedTweaksBtn -PresetMap $script:LastUsedTweakPresetMap
+ }
+ SetTweakPresetState -PresetCheckBox $presetPrivacyTweaksBtn -PresetMap $script:PrivacyTweakPresetMap
+ SetTweakPresetState -PresetCheckBox $presetAITweaksBtn -PresetMap $script:AITweakPresetMap
+ }
+ finally {
+ $script:UpdatingTweakPresets = $false
+ }
+ }
+
+ function RegisterTweakPresetControlStateHandlers {
+ if (-not $script:UiControlMappings) { return }
+
+ foreach ($controlName in $script:UiControlMappings.Keys) {
+ $control = $window.FindName($controlName)
+ if (-not $control) { continue }
+
+ if ($control -is [System.Windows.Controls.CheckBox]) {
+ $control.Add_Checked({ if (-not $script:UpdatingTweakPresets) { UpdateTweakPresetStates } })
+ $control.Add_Unchecked({ if (-not $script:UpdatingTweakPresets) { UpdateTweakPresetStates } })
+ }
+ elseif ($control -is [System.Windows.Controls.ComboBox]) {
+ $control.Add_SelectionChanged({ if (-not $script:UpdatingTweakPresets) { UpdateTweakPresetStates } })
+ }
+ }
+ }
+
+ function RefreshTweakPresetSources {
+ param(
+ $defaultSettingsJson,
+ $lastUsedSettingsJson
+ )
+
+ $script:DefaultTweakPresetMap = BuildTweakPresetControlMap -settingsJson $defaultSettingsJson
+ $script:LastUsedTweakPresetMap = BuildTweakPresetControlMap -settingsJson $lastUsedSettingsJson
+ $script:PrivacyTweakPresetMap = BuildCategoryTweakPresetMap -Category 'Privacy & Suggested Content'
+ $script:AITweakPresetMap = BuildCategoryTweakPresetMap -Category 'AI'
+
+ if ($presetLastUsedTweaksBtn) {
+ $presetLastUsedTweaksBtn.Visibility = if ($script:LastUsedTweakPresetMap.Count -gt 0) { 'Visible' } else { 'Collapsed' }
+ }
+ }
$lastUsedSettingsJson = LoadJsonFile -filePath $script:SavedSettingsFilePath -expectedVersion "1.0" -optionalFile
- $hasSettings = $false
- $appsSetting = $null
- if ($lastUsedSettingsJson -and $lastUsedSettingsJson.Settings) {
- foreach ($s in $lastUsedSettingsJson.Settings) {
- # Only count as hasSettings if a setting other than RemoveApps/Apps is present and true
- if ($s.Value -eq $true -and $s.Name -ne 'RemoveApps' -and $s.Name -ne 'Apps') { $hasSettings = $true }
- if ($s.Name -eq 'Apps' -and $s.Value) { $appsSetting = $s.Value }
- }
- }
+ $defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
+ $script:DefaultTweakPresetMap = @{}
+ $script:LastUsedTweakPresetMap = @{}
+ $script:PrivacyTweakPresetMap = @{}
+ $script:AITweakPresetMap = @{}
+ $script:SavedAppIds = GetSavedAppIdsFromSettingsJson -settingsJson $lastUsedSettingsJson
- # Show option to load last used settings if they exist
- if ($hasSettings) {
- $loadLastUsedBtn.Add_Click({
- try {
- ApplySettingsToUiControls -window $window -settingsJson $lastUsedSettingsJson -uiControlMappings $script:UiControlMappings
- }
- catch {
- Show-MessageBox -Message "Failed to load last used settings: $_" -Title "Error" -Button 'OK' -Icon 'Error'
- }
+ if ($presetDefaultTweaksBtn) {
+ $presetDefaultTweaksBtn.Add_Click({
+ if ($script:UpdatingTweakPresets) { return }
+ $check = NormalizeCheckboxState -checkBox $this
+ ApplyTweakPresetMap -PresetMap $script:DefaultTweakPresetMap -Check $check
})
}
- else {
- $loadLastUsedBtn.Visibility = 'Collapsed'
+
+ if ($presetLastUsedTweaksBtn) {
+ $presetLastUsedTweaksBtn.Add_Click({
+ if ($script:UpdatingTweakPresets) { return }
+ $check = NormalizeCheckboxState -checkBox $this
+ ApplyTweakPresetMap -PresetMap $script:LastUsedTweakPresetMap -Check $check
+ })
+ }
+
+ if ($presetPrivacyTweaksBtn) {
+ $presetPrivacyTweaksBtn.Add_Click({
+ if ($script:UpdatingTweakPresets) { return }
+ $check = NormalizeCheckboxState -checkBox $this
+ ApplyTweakPresetMap -PresetMap $script:PrivacyTweakPresetMap -Check $check
+ })
+ }
+
+ if ($presetAITweaksBtn) {
+ $presetAITweaksBtn.Add_Click({
+ if ($script:UpdatingTweakPresets) { return }
+ $check = NormalizeCheckboxState -checkBox $this
+ ApplyTweakPresetMap -PresetMap $script:AITweakPresetMap -Check $check
+ })
+ }
+
+ # Hide Last used tweak preset by default; it is shown after dynamic controls are built and mappings are resolved.
+ if ($presetLastUsedTweaksBtn) {
+ $presetLastUsedTweaksBtn.Visibility = 'Collapsed'
}
# Preset: Last used selection (wired to PresetLastUsed checkbox)
- if ($appsSetting -and $appsSetting.ToString().Trim().Length -gt 0) {
- # Parse and store saved app IDs for UpdatePresetStates
- $script:SavedAppIds = @()
- if ($appsSetting -is [string]) { $script:SavedAppIds = $appsSetting.Split(',') }
- elseif ($appsSetting -is [array]) { $script:SavedAppIds = $appsSetting }
- $script:SavedAppIds = $script:SavedAppIds | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
-
+ if ($script:SavedAppIds) {
$presetLastUsed.Add_Click({
if ($script:UpdatingPresets) { return }
- $check = ($this.IsChecked -eq $true)
- if ($this.IsChecked -eq $null) { $this.IsChecked = $false; $check = $false }
+ $check = NormalizeCheckboxState -checkBox $this
ApplyPresetToApps -MatchFilter { param($c) (@($c.AppIds) | Where-Object { $script:SavedAppIds -contains $_ }).Count -gt 0 } -Check $check
})
}
@@ -1848,6 +2208,7 @@ function Show-MainWindow {
}
}
}
+ UpdateTweakPresetStates
})
# Preload app data to speed up loading when user navigates to App Removal tab
@@ -1859,5 +2220,12 @@ function Show-MainWindow {
}
# Show the window
- return $window.ShowDialog()
+ $frame = [System.Windows.Threading.DispatcherFrame]::new()
+ $window.Add_Closed({
+ $frame.Continue = $false
+ })
+
+ $window.Show() | Out-Null
+ [System.Windows.Threading.Dispatcher]::PushFrame($frame)
+ return $null
}
diff --git a/Scripts/Get-Dev.ps1 b/Scripts/Get-Dev.ps1
new file mode 100644
index 0000000..f39495d
--- /dev/null
+++ b/Scripts/Get-Dev.ps1
@@ -0,0 +1,225 @@
+param (
+ [switch]$CLI,
+ [switch]$Silent,
+ [switch]$Verbose,
+ [switch]$Sysprep,
+ [string]$LogPath,
+ [string]$User,
+ [switch]$NoRestartExplorer,
+ [switch]$CreateRestorePoint,
+ [switch]$RunAppsListGenerator,
+ [switch]$RunDefaults,
+ [switch]$RunDefaultsLite,
+ [switch]$RunSavedSettings,
+ [string]$Config,
+ [string]$Apps,
+ [string]$AppRemovalTarget,
+ [switch]$RemoveApps,
+ [switch]$RemoveAppsCustom,
+ [switch]$RemoveGamingApps,
+ [switch]$RemoveCommApps,
+ [switch]$RemoveHPApps,
+ [switch]$RemoveW11Outlook,
+ [switch]$ForceRemoveEdge,
+ [switch]$DisableDVR,
+ [switch]$DisableGameBarIntegration,
+ [switch]$EnableWindowsSandbox,
+ [switch]$EnableWindowsSubsystemForLinux,
+ [switch]$DisableTelemetry,
+ [switch]$DisableSearchHistory,
+ [switch]$DisableFastStartup,
+ [switch]$DisableBitlockerAutoEncryption,
+ [switch]$DisableModernStandbyNetworking,
+ [switch]$DisableStorageSense,
+ [switch]$DisableUpdateASAP,
+ [switch]$PreventUpdateAutoReboot,
+ [switch]$DisableDeliveryOptimization,
+ [switch]$DisableBing,
+ [switch]$DisableStoreSearchSuggestions,
+ [switch]$DisableDesktopSpotlight,
+ [switch]$DisableLockscreenTips,
+ [switch]$DisableSuggestions,
+ [switch]$DisableLocationServices,
+ [switch]$DisableFindMyDevice,
+ [switch]$DisableEdgeAds,
+ [switch]$DisableBraveBloat,
+ [switch]$DisableSettings365Ads,
+ [switch]$DisableSettingsHome,
+ [switch]$ShowHiddenFolders,
+ [switch]$ShowKnownFileExt,
+ [switch]$HideDupliDrive,
+ [switch]$EnableDarkMode,
+ [switch]$DisableTransparency,
+ [switch]$DisableAnimations,
+ [switch]$TaskbarAlignLeft,
+ [switch]$CombineTaskbarAlways, [switch]$CombineTaskbarWhenFull, [switch]$CombineTaskbarNever,
+ [switch]$CombineMMTaskbarAlways, [switch]$CombineMMTaskbarWhenFull, [switch]$CombineMMTaskbarNever,
+ [switch]$MMTaskbarModeAll, [switch]$MMTaskbarModeMainActive, [switch]$MMTaskbarModeActive,
+ [switch]$HideSearchTb, [switch]$ShowSearchIconTb, [switch]$ShowSearchLabelTb, [switch]$ShowSearchBoxTb,
+ [switch]$HideTaskview,
+ [switch]$DisableStartRecommended,
+ [switch]$DisableStartAllApps,
+ [switch]$DisableStartPhoneLink,
+ [switch]$DisableCopilot,
+ [switch]$DisableRecall,
+ [switch]$DisableClickToDo,
+ [switch]$DisableAISvcAutoStart,
+ [switch]$DisablePaintAI,
+ [switch]$DisableNotepadAI,
+ [switch]$DisableEdgeAI,
+ [switch]$DisableSearchHighlights,
+ [switch]$DisableWidgets,
+ [switch]$HideChat,
+ [switch]$EnableEndTask,
+ [switch]$EnableLastActiveClick,
+ [switch]$ClearStart,
+ [string]$ReplaceStart,
+ [switch]$ClearStartAllUsers,
+ [string]$ReplaceStartAllUsers,
+ [switch]$RevertContextMenu,
+ [switch]$DisableDragTray,
+ [switch]$DisableMouseAcceleration,
+ [switch]$DisableStickyKeys,
+ [switch]$DisableWindowSnapping,
+ [switch]$DisableSnapAssist,
+ [switch]$DisableSnapLayouts,
+ [switch]$HideTabsInAltTab, [switch]$Show3TabsInAltTab, [switch]$Show5TabsInAltTab, [switch]$Show20TabsInAltTab,
+ [switch]$HideHome,
+ [switch]$HideGallery,
+ [switch]$ExplorerToHome,
+ [switch]$ExplorerToThisPC,
+ [switch]$ExplorerToDownloads,
+ [switch]$ExplorerToOneDrive,
+ [switch]$AddFoldersToThisPC,
+ [switch]$HideOnedrive,
+ [switch]$Hide3dObjects,
+ [switch]$HideMusic,
+ [switch]$HideIncludeInLibrary,
+ [switch]$HideGiveAccessTo,
+ [switch]$HideShare,
+ [switch]$ShowDriveLettersFirst,
+ [switch]$ShowDriveLettersLast,
+ [switch]$ShowNetworkDriveLettersFirst,
+ [switch]$HideDriveLetters
+)
+
+# Show error if current powershell environment does not have LanguageMode set to FullLanguage
+if ($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") {
+ Write-Host "Error: Win11Debloat is unable to run on your system. PowerShell execution is restricted by security policies" -ForegroundColor Red
+ Write-Output ""
+ Write-Output "Press enter to exit..."
+ Read-Host | Out-Null
+ Exit
+}
+
+Clear-Host
+Write-Output "-------------------------------------------------------------------------------------------"
+Write-Output " Win11Debloat Script - Get Dev"
+Write-Output "-------------------------------------------------------------------------------------------"
+
+Write-Output "> Downloading Win11Debloat for development..."
+
+# Download latest version of Win11Debloat from GitHub master branch as zip archive
+try {
+ Invoke-RestMethod "https://github.com/Raphire/Win11Debloat/archive/refs/heads/master.zip" -OutFile "$env:TEMP/win11debloat.zip"
+}
+catch {
+ Write-Host "Error: Unable to fetch master branch from GitHub. Please check your internet connection and try again." -ForegroundColor Red
+ Write-Output ""
+ Write-Output "Press enter to exit..."
+ Read-Host | Out-Null
+ Exit
+}
+
+Write-Output ""
+Write-Output "> Cleaning up old Win11Debloat folder..."
+
+# Remove old script folder if it exists, but keep config and log files
+if (Test-Path "$env:TEMP/Win11Debloat") {
+ Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log,Config,Logs | Remove-Item -Recurse -Force
+}
+
+$configDir = "$env:TEMP/Win11Debloat/Config"
+$backupDir = "$env:TEMP/Win11Debloat/ConfigOld"
+
+# Temporarily move existing config files if they exist to prevent them from being overwritten by the new script files, will be moved back after the new script is unpacked
+if (Test-Path "$configDir") {
+ New-Item -ItemType Directory -Path "$backupDir" -Force | Out-Null
+
+ $filesToKeep = @(
+ 'CustomAppsList',
+ 'LastUsedSettings.json'
+ )
+
+ Get-ChildItem -Path "$configDir" -Recurse | Where-Object { $_.Name -in $filesToKeep } | Move-Item -Destination "$backupDir"
+
+ Remove-Item "$configDir" -Recurse -Force
+}
+
+Write-Output ""
+Write-Output "> Unpacking..."
+
+# Unzip archive to Win11Debloat folder
+Expand-Archive "$env:TEMP/win11debloat.zip" "$env:TEMP/Win11Debloat"
+
+# Remove archive
+Remove-Item "$env:TEMP/win11debloat.zip"
+
+# Move files
+Get-ChildItem -Path "$env:TEMP/Win11Debloat/*Win11Debloat-*" -Recurse | Move-Item -Destination "$env:TEMP/Win11Debloat"
+
+# Add existing config files back to Config folder
+if (Test-Path "$backupDir") {
+ if (-not (Test-Path "$configDir")) {
+ New-Item -ItemType Directory -Path "$configDir" -Force | Out-Null
+ }
+
+ Get-ChildItem -Path "$backupDir" -Recurse | Move-Item -Destination "$configDir"
+ Remove-Item "$backupDir" -Recurse -Force
+}
+
+# Make list of arguments to pass on to the script
+$arguments = $($PSBoundParameters.GetEnumerator() | ForEach-Object {
+ if ($_.Value -eq $true) {
+ "-$($_.Key)"
+ }
+ else {
+ "-$($_.Key) ""$($_.Value)"""
+ }
+})
+
+Write-Output ""
+Write-Output "> Launching Win11Debloat..."
+
+# Minimize the powershell window when no parameters are provided
+if ($arguments.Count -eq 0) {
+ $windowStyle = "Minimized"
+}
+else {
+ $windowStyle = "Normal"
+}
+
+# Remove Powershell 7 modules from path to prevent module loading issues in the script
+if ($PSVersionTable.PSVersion.Major -ge 7) {
+ $NewPSModulePath = $env:PSModulePath -split ';' | Where-Object -FilterScript { $_ -like '*WindowsPowerShell*' }
+ $env:PSModulePath = $NewPSModulePath -join ';'
+}
+
+# Run Win11Debloat script with the provided arguments
+$debloatProcess = Start-Process powershell.exe -WindowStyle $windowStyle -PassThru -ArgumentList "-executionpolicy bypass -File $env:TEMP\Win11Debloat\Win11Debloat.ps1 $arguments" -Verb RunAs
+
+# Wait for the process to finish before continuing
+if ($null -ne $debloatProcess) {
+ $debloatProcess.WaitForExit()
+}
+
+# Remove all remaining script files, except for CustomAppsList and LastUsedSettings.json files
+if (Test-Path "$env:TEMP/Win11Debloat") {
+ Write-Output ""
+ Write-Output "> Cleaning up..."
+
+ # Cleanup, remove Win11Debloat directory
+ Get-ChildItem -Path "$env:TEMP/Win11Debloat" -Exclude CustomAppsList,LastUsedSettings.json,Win11Debloat.log,Win11Debloat-Run.log,Config,Logs | Remove-Item -Recurse -Force
+}
+
+Write-Output ""
diff --git a/Scripts/Get.ps1 b/Scripts/Get.ps1
index e04e3f7..9f88e45 100644
--- a/Scripts/Get.ps1
+++ b/Scripts/Get.ps1
@@ -97,7 +97,11 @@ param (
[switch]$HideMusic,
[switch]$HideIncludeInLibrary,
[switch]$HideGiveAccessTo,
- [switch]$HideShare
+ [switch]$HideShare,
+ [switch]$ShowDriveLettersFirst,
+ [switch]$ShowDriveLettersLast,
+ [switch]$ShowNetworkDriveLettersFirst,
+ [switch]$HideDriveLetters
)
# Show error if current powershell environment does not have LanguageMode set to FullLanguage
@@ -187,7 +191,7 @@ $arguments = $($PSBoundParameters.GetEnumerator() | ForEach-Object {
})
Write-Output ""
-Write-Output "> Running Win11Debloat..."
+Write-Output "> Launching Win11Debloat..."
# Minimize the powershell window when no parameters are provided
if ($arguments.Count -eq 0) {
diff --git a/Win11Debloat.ps1 b/Win11Debloat.ps1
index ffe5d14..d49189b 100644
--- a/Win11Debloat.ps1
+++ b/Win11Debloat.ps1
@@ -1,5 +1,3 @@
-#Requires -RunAsAdministrator
-
[CmdletBinding(SupportsShouldProcess)]
param (
[switch]$CLI,
@@ -99,13 +97,52 @@ param (
[switch]$HideMusic,
[switch]$HideIncludeInLibrary,
[switch]$HideGiveAccessTo,
- [switch]$HideShare
+ [switch]$HideShare,
+ [switch]$ShowDriveLettersFirst,
+ [switch]$ShowDriveLettersLast,
+ [switch]$ShowNetworkDriveLettersFirst,
+ [switch]$HideDriveLetters
)
+# Check if script is running as administrator
+$isAdmin = ([Security.Principal.WindowsPrincipal] `
+ [Security.Principal.WindowsIdentity]::GetCurrent()
+).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
+# If script is not running as administrator ask user if they want to allow it
+if (-not $isAdmin) {
+ Write-Host "Win11Debloat must be run as Administrator." -ForegroundColor Red
+
+ $choice = Read-Host "Restart as Administrator? (y/n)"
+
+ if ($choice -match '^[Yy]$') {
+ $elevatedArgs = @("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $PSCommandPath)
+
+ foreach ($paramName in $PSBoundParameters.Keys) {
+ $paramValue = $PSBoundParameters[$paramName]
+
+ if ($paramValue -is [System.Management.Automation.SwitchParameter]) {
+ if ($paramValue.IsPresent) {
+ $elevatedArgs += "-$paramName"
+ }
+ }
+ else {
+ $elevatedArgs += "-$paramName"
+ $elevatedArgs += "$paramValue"
+ }
+ }
+
+ if ($MyInvocation.UnboundArguments.Count -gt 0) {
+ $elevatedArgs += $MyInvocation.UnboundArguments
+ }
+
+ Start-Process powershell -ArgumentList $elevatedArgs -Verb RunAs
+ }
+ exit
+}
# Define script-level variables & paths
-$script:Version = "2026.03.15"
+$script:Version = "2026.04.05"
$script:FeaturesConfigVersion = "2.0"
$script:AppsListFilePath = "$PSScriptRoot/Config/Apps.json"
$script:DefaultSettingsFilePath = "$PSScriptRoot/Config/DefaultSettings.json"
@@ -142,8 +179,16 @@ if ($ExecutionContext.SessionState.LanguageMode -ne "FullLanguage") {
Exit
}
-# Display ASCII art launch logo in CLI
Clear-Host
+
+# Ensure required Windows command paths are present in PATH for this session.
+$system32Path = "$env:SystemRoot\System32"
+if ($env:PATH -notmatch "(?i)(^|;)$([regex]::Escape($system32Path))(?=;|$)") {
+ $env:PATH = "$env:SystemRoot\System32;$env:SystemRoot;" + $env:PATH
+ Write-Warning "System32 path was missing from PATH environment variable, it has been added for this session."
+}
+
+# Display ASCII art launch logo in CLI
Write-Host ""
Write-Host ""
Write-Host " " -NoNewline; Write-Host " ^" -ForegroundColor Blue
@@ -158,8 +203,8 @@ Write-Host " " -NoNewline; Write-Host " | |" -Foregroun
Write-Host " " -NoNewline; Write-Host " /| |\" -ForegroundColor Blue
Write-Host " " -NoNewline; Write-Host "/ | | \" -ForegroundColor Blue
Write-Host " " -NoNewline; Write-Host " | " -ForegroundColor DarkGray -NoNewline; Write-Host "'''" -ForegroundColor Red -NoNewline; Write-Host " |" -ForegroundColor DarkGray -NoNewline; Write-Host " *" -ForegroundColor Yellow
-Write-Host " " -NoNewline; Write-Host " (" -ForegroundColor Yellow -NoNewline; Write-Host "'''" -ForegroundColor Red -NoNewline; Write-Host ") " -ForegroundColor Yellow -NoNewline; Write-Host " * *" -ForegroundColor DarkYellow
-Write-Host " " -NoNewline; Write-Host " ( " -ForegroundColor DarkYellow -NoNewline; Write-Host "'" -ForegroundColor Red -NoNewline; Write-Host " ) " -ForegroundColor DarkYellow -NoNewline; Write-Host "*" -ForegroundColor Yellow
+Write-Host " " -NoNewline; Write-Host " (" -ForegroundColor Yellow -NoNewline; Write-Host "'''" -ForegroundColor Red -NoNewline; Write-Host ") " -ForegroundColor Yellow -NoNewline; Write-Host " * *" -ForegroundColor DarkYellow
+Write-Host " " -NoNewline; Write-Host " ( " -ForegroundColor DarkYellow -NoNewline; Write-Host "'" -ForegroundColor Red -NoNewline; Write-Host " ) " -ForegroundColor DarkYellow -NoNewline; Write-Host "*" -ForegroundColor Yellow
Write-Host ""
Write-Host " Win11Debloat is launching..." -ForegroundColor White
Write-Host " Leave this window open" -ForegroundColor DarkGray