2020-11-07 02:57:38 +01:00
[ CmdletBinding ( SupportsShouldProcess )]
2024-01-31 22:19:50 +01:00
param (
2026-02-01 01:41:12 +01:00
[ switch ] $CLI ,
2024-03-11 23:38:19 +01:00
[ switch ] $Silent ,
2024-06-27 23:08:43 +02:00
[ switch ] $Sysprep ,
2025-05-10 13:02:48 +02:00
[ string ] $LogPath ,
2025-03-05 23:39:29 +01:00
[ string ] $User ,
2026-07-19 22:58:03 +02:00
[ Alias ( 'NoRestartExplorer' )]
[ switch ] $SkipExplorerRestart ,
2025-05-03 17:55:31 +02:00
[ switch ] $CreateRestorePoint ,
2026-07-25 20:05:49 +02:00
[ switch ] $SkipRegistryBackup ,
2025-09-13 23:36:38 +02:00
[ switch ] $RunDefaults ,
[ switch ] $RunDefaultsLite ,
2025-01-09 21:33:28 +01:00
[ switch ] $RunSavedSettings ,
2026-03-27 20:33:24 +01:00
[ string ] $Config ,
2025-12-26 20:36:51 +01:00
[ string ] $Apps ,
2026-02-12 22:50:22 +01:00
[ string ] $AppRemovalTarget ,
2025-12-26 20:36:51 +01:00
[ switch ] $RemoveApps ,
2024-03-11 23:38:19 +01:00
[ switch ] $RemoveGamingApps ,
2025-05-04 12:27:19 -04:00
[ switch ] $RemoveHPApps ,
2024-07-02 18:51:00 +02:00
[ switch ] $ForceRemoveEdge ,
2024-05-24 14:13:15 +02:00
[ switch ] $DisableDVR ,
2025-11-29 17:15:12 +01:00
[ switch ] $DisableGameBarIntegration ,
2026-02-18 19:00:49 +01:00
[ switch ] $EnableWindowsSandbox ,
[ switch ] $EnableWindowsSubsystemForLinux ,
2024-03-11 23:38:19 +01:00
[ switch ] $DisableTelemetry ,
2026-02-18 19:00:49 +01:00
[ switch ] $DisableSearchHistory ,
2025-05-01 22:32:41 +01:00
[ switch ] $DisableFastStartup ,
2026-02-04 13:59:10 +01:00
[ switch ] $DisableBitlockerAutoEncryption ,
2025-08-19 23:24:28 +05:30
[ switch ] $DisableModernStandbyNetworking ,
2026-03-07 20:29:08 +01:00
[ switch ] $DisableStorageSense ,
2026-02-04 14:01:04 +01:00
[ switch ] $DisableUpdateASAP ,
[ switch ] $PreventUpdateAutoReboot ,
[ switch ] $DisableDeliveryOptimization ,
2026-07-08 17:54:13 +02:00
[ switch ] $DisableDeviceAutoAppDownload ,
2026-02-01 01:41:12 +01:00
[ switch ] $DisableBing ,
2026-07-06 13:29:09 -04:00
[ switch ] $DisableNotifications ,
2026-03-07 20:28:48 +01:00
[ switch ] $DisableStoreSearchSuggestions ,
2026-03-07 18:32:06 +00:00
[ switch ] $DisableSearchHighlights ,
2024-12-26 19:06:49 +01:00
[ switch ] $DisableDesktopSpotlight ,
2026-02-01 01:41:12 +01:00
[ switch ] $DisableLockscreenTips ,
[ switch ] $DisableSuggestions ,
2026-02-18 20:53:53 +01:00
[ switch ] $DisableLocationServices ,
2026-03-07 18:32:06 +00:00
[ switch ] $DisableFindMyDevice ,
2025-08-16 01:36:00 +02:00
[ switch ] $DisableEdgeAds ,
2026-02-01 01:41:12 +01:00
[ switch ] $DisableBraveBloat ,
2025-05-20 21:55:38 +02:00
[ switch ] $DisableSettings365Ads ,
2025-05-20 21:56:04 +02:00
[ switch ] $DisableSettingsHome ,
2024-03-11 23:38:19 +01:00
[ switch ] $ShowHiddenFolders ,
[ switch ] $ShowKnownFileExt ,
[ switch ] $HideDupliDrive ,
2025-06-12 21:50:57 +02:00
[ switch ] $EnableDarkMode ,
[ switch ] $DisableTransparency ,
[ switch ] $DisableAnimations ,
2024-03-11 23:38:19 +01:00
[ switch ] $TaskbarAlignLeft ,
2025-09-27 14:34:01 +02:00
[ switch ] $CombineTaskbarAlways , [ switch ] $CombineTaskbarWhenFull , [ switch ] $CombineTaskbarNever ,
2025-10-06 23:33:04 +02:00
[ switch ] $CombineMMTaskbarAlways , [ switch ] $CombineMMTaskbarWhenFull , [ switch ] $CombineMMTaskbarNever ,
[ switch ] $MMTaskbarModeAll , [ switch ] $MMTaskbarModeMainActive , [ switch ] $MMTaskbarModeActive ,
2024-03-11 23:38:19 +01:00
[ switch ] $HideSearchTb , [ switch ] $ShowSearchIconTb , [ switch ] $ShowSearchLabelTb , [ switch ] $ShowSearchBoxTb ,
[ switch ] $HideTaskview ,
2025-02-03 21:27:46 +01:00
[ switch ] $DisableStartRecommended ,
2026-06-10 17:40:31 +02:00
[ switch ] $DisableStartAllApps , [ switch ] $StartAllAppsCategory , [ switch ] $StartAllAppsGrid , [ switch ] $StartAllAppsList ,
2025-06-11 22:04:17 +02:00
[ switch ] $DisableStartPhoneLink ,
2024-03-11 23:38:19 +01:00
[ switch ] $DisableCopilot ,
2024-06-05 09:17:24 +02:00
[ switch ] $DisableRecall ,
2025-09-17 23:33:52 +02:00
[ switch ] $DisableClickToDo ,
2026-03-07 20:28:58 +01:00
[ switch ] $DisableAISvcAutoStart ,
2025-08-01 21:21:38 +02:00
[ switch ] $DisablePaintAI ,
[ switch ] $DisableNotepadAI ,
2025-08-16 01:36:00 +02:00
[ switch ] $DisableEdgeAI ,
2026-02-01 01:41:12 +01:00
[ switch ] $DisableWidgets ,
[ switch ] $HideChat ,
2025-04-16 12:31:18 +02:00
[ switch ] $EnableEndTask ,
2025-07-30 15:30:51 -04:00
[ switch ] $EnableLastActiveClick ,
2024-03-11 23:38:19 +01:00
[ switch ] $ClearStart ,
2025-05-19 00:01:49 +02:00
[ string ] $ReplaceStart ,
2024-06-27 23:08:43 +02:00
[ switch ] $ClearStartAllUsers ,
2025-05-19 00:01:49 +02:00
[ string ] $ReplaceStartAllUsers ,
2024-03-11 23:38:19 +01:00
[ switch ] $RevertContextMenu ,
2026-02-01 01:41:12 +01:00
[ switch ] $DisableDragTray ,
2025-02-13 21:08:47 +01:00
[ switch ] $DisableMouseAcceleration ,
2025-04-16 12:56:37 +02:00
[ switch ] $DisableStickyKeys ,
2026-02-12 23:14:15 +01:00
[ switch ] $DisableWindowSnapping ,
[ switch ] $DisableSnapAssist ,
[ switch ] $DisableSnapLayouts ,
[ switch ] $HideTabsInAltTab , [ switch ] $Show3TabsInAltTab , [ switch ] $Show5TabsInAltTab , [ switch ] $Show20TabsInAltTab ,
2024-09-04 17:46:41 +02:00
[ switch ] $HideHome ,
2024-06-29 16:18:23 +02:00
[ switch ] $HideGallery ,
2024-10-27 19:28:43 +01:00
[ switch ] $ExplorerToHome ,
[ switch ] $ExplorerToThisPC ,
[ switch ] $ExplorerToDownloads ,
[ switch ] $ExplorerToOneDrive ,
2025-12-29 01:03:14 +01:00
[ switch ] $AddFoldersToThisPC ,
2026-02-01 01:41:12 +01:00
[ switch ] $HideOnedrive ,
[ switch ] $Hide3dObjects ,
[ switch ] $HideMusic ,
[ switch ] $HideIncludeInLibrary ,
[ switch ] $HideGiveAccessTo ,
2026-03-28 20:25:12 -03:00
[ switch ] $HideShare ,
[ switch ] $ShowDriveLettersFirst ,
[ switch ] $ShowDriveLettersLast ,
[ switch ] $ShowNetworkDriveLettersFirst ,
[ switch ] $HideDriveLetters
2020-11-07 02:57:38 +01:00
)
2020-10-27 23:26:39 +01:00
2026-07-08 20:22:36 +07:00
# Win11Debloat depends on Windows PowerShell 5.1 cmdlets (the Appx module's Get-AppxPackage /
# Remove-AppxPackage, and Get-ComputerRestorePoint) that do not load in PowerShell 7 (pwsh), where the
# Appx module fails with "Operation is not supported on this platform" (0x80131539). Without this guard
# the run continues and silently fails to remove any apps while still reporting success. See issue #675.
if ( $PSVersionTable . PSEdition -eq 'Core' ) {
Write-Host "Win11Debloat requires Windows PowerShell 5.1, but it is running under PowerShell $( $PSVersionTable . PSVersion ) (pwsh / Core edition)." -ForegroundColor Red
Write-Host "App removal and system restore points rely on modules that are not available in PowerShell 7, so the run cannot complete correctly here." -ForegroundColor Red
Write-Host "Please re-run this script with Windows PowerShell instead (powershell.exe)." -ForegroundColor Yellow
exit 1
}
2026-04-25 18:09:57 +02:00
# Check if script is running as administrator
$isAdmin = ([ Security.Principal.WindowsPrincipal ] `
[ Security.Principal.WindowsIdentity ]:: GetCurrent ()
). IsInRole ([ Security.Principal.WindowsBuiltInRole ]:: Administrator )
2023-08-03 22:24:27 +02:00
2026-04-25 18:09:57 +02:00
# 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]$' ) {
2026-07-04 22:35:24 +07:00
# Win32-safe escaping for arguments to pass to elevated process
function Format-ElevatedArg([string]$Value ) {
$escaped = $Value -replace '(\\*)"' , '$1$1\"'
$escaped = $escaped -replace '(\\+)$' , '$1$1'
return '"' + $escaped + '"'
}
$elevatedArgs = @ ( "-NoProfile" , "-ExecutionPolicy" , "Bypass" , "-File" , ( Format-ElevatedArg $PSCommandPath ))
2026-04-25 18:09:57 +02:00
foreach ( $paramName in $PSBoundParameters . Keys ) {
$paramValue = $PSBoundParameters [ $paramName ]
if ( $paramValue -is [ System.Management.Automation.SwitchParameter ]) {
if ( $paramValue . IsPresent ) {
$elevatedArgs += "- $paramName "
}
}
else {
$elevatedArgs += "- $paramName "
2026-07-04 22:35:24 +07:00
$elevatedArgs += ( Format-ElevatedArg $paramValue )
2026-04-25 18:09:57 +02:00
}
}
if ( $MyInvocation . UnboundArguments . Count -gt 0 ) {
2026-07-04 22:35:24 +07:00
foreach ( $unboundArg in $MyInvocation . UnboundArguments ) {
$elevatedArgs += ( Format-ElevatedArg " $unboundArg " )
}
2026-04-25 18:09:57 +02:00
}
2026-08-12 15:56:29 +02:00
try {
Start-Process powershell -ArgumentList $elevatedArgs -Verb RunAs -ErrorAction Stop
}
catch {
Write-Error "Failed to start Win11Debloat as Administrator: $_ "
Exit 1
}
Exit 0
2026-04-25 18:09:57 +02:00
}
2026-08-12 15:56:29 +02:00
Exit 1
2026-04-25 18:09:57 +02:00
}
2025-12-15 23:22:29 +01:00
2025-12-26 20:36:51 +01:00
# Define script-level variables & paths
2026-07-11 20:07:47 +02:00
$script:Version = "2026.07.11"
2026-05-08 21:19:52 +02:00
$configPath = Join-Path $PSScriptRoot 'Config'
$logsPath = Join-Path $PSScriptRoot 'Logs'
$schemasPath = Join-Path $PSScriptRoot 'Schemas'
$scriptsPath = Join-Path $PSScriptRoot 'Scripts'
$script:AppsListFilePath = Join-Path $configPath 'Apps.json'
$script:DefaultSettingsFilePath = Join-Path $configPath 'DefaultSettings.json'
$script:FeaturesFilePath = Join-Path $configPath 'Features.json'
$script:SavedSettingsFilePath = Join-Path $configPath 'LastUsedSettings.json'
$script:DefaultLogPath = Join-Path $logsPath 'Win11Debloat.log'
$script:RegfilesPath = Join-Path $PSScriptRoot 'Regfiles'
$script:RegistryBackupsPath = Join-Path $PSScriptRoot 'Backups'
$script:AssetsPath = Join-Path $PSScriptRoot 'Assets'
$script:AppSelectionSchema = Join-Path $schemasPath 'AppSelectionWindow.xaml'
$script:MainWindowSchema = Join-Path $schemasPath 'MainWindow.xaml'
2026-06-21 18:47:52 +02:00
$script:MessageBoxSchema = Join-Path $schemasPath 'MessageBox.xaml'
2026-05-08 21:19:52 +02:00
$script:AboutWindowSchema = Join-Path $schemasPath 'AboutWindow.xaml'
$script:ApplyChangesWindowSchema = Join-Path $schemasPath 'ApplyChangesWindow.xaml'
$script:SharedStylesSchema = Join-Path $schemasPath 'SharedStyles.xaml'
$script:BubbleHintSchema = Join-Path $schemasPath 'BubbleHint.xaml'
$script:ImportExportConfigSchema = Join-Path $schemasPath 'ImportExportConfigWindow.xaml'
$script:RestoreBackupWindowSchema = Join-Path $schemasPath 'RestoreBackupWindow.xaml'
2026-07-19 22:06:07 +02:00
$script:LoadAppsDetailsScriptPath = Join-Path ( Join-Path $scriptsPath 'FileIO' ) 'Import-AppDetailsFromJson.ps1'
2026-06-22 22:13:01 +02:00
$script:TestAppInWingetListScriptPath = Join-Path ( Join-Path $scriptsPath 'AppRemoval' ) 'Test-AppInWingetList.ps1'
2025-12-26 20:36:51 +01:00
2026-07-25 20:05:49 +02:00
$script:ControlParams = 'WhatIf' , 'Confirm' , 'Verbose' , 'Debug' , 'LogPath' , 'Silent' , 'Sysprep' , 'User' , 'SkipExplorerRestart' , 'SkipRegistryBackup' , 'RunDefaults' , 'RunDefaultsLite' , 'RunSavedSettings' , 'Config' , 'CLI' , 'AppRemovalTarget'
2026-02-01 01:41:12 +01:00
# Script-level variables for GUI elements
$script:GuiWindow = $null
2026-02-06 23:44:39 +01:00
$script:CancelRequested = $false
2026-03-07 14:49:29 +01:00
$script:ApplyProgressCallback = $null
$script:ApplySubStepCallback = $null
2026-08-12 15:56:29 +02:00
$script:RegistryImportFailures = 0
$script:AppRemovalFailures = 0
$script:AppRemovalVerificationUnavailable = $false
2025-12-26 20:36:51 +01:00
2026-08-12 15:56:29 +02:00
# Check if current PowerShell environment is limited by security policies
2024-06-26 20:27:25 +02:00
if ( $ExecutionContext . SessionState . LanguageMode -ne "FullLanguage" ) {
2026-08-12 15:56:29 +02:00
Write-Error "Win11Debloat is unable to run on your system, PowerShell execution is restricted by security policies"
2025-12-26 20:36:51 +01:00
Write-Output "Press any key to exit..."
$null = [ System.Console ]:: ReadKey ()
2026-08-12 15:56:29 +02:00
Exit 1
2025-12-26 20:36:51 +01:00
}
2026-02-01 01:41:12 +01:00
Clear-Host
2026-04-17 20:09:47 +02:00
# 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
2026-02-01 01:41:12 +01:00
Write-Host ""
Write-Host ""
Write-Host " " -NoNewline ; Write-Host " ^" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " / \" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " / \" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " / \" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " / ===== \" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " |" -ForegroundColor Blue -NoNewline ; Write-Host " --- " -ForegroundColor White -NoNewline ; Write-Host "|" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " |" -ForegroundColor Blue -NoNewline ; Write-Host " ( O ) " -ForegroundColor DarkCyan -NoNewline ; Write-Host "|" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " |" -ForegroundColor Blue -NoNewline ; Write-Host " --- " -ForegroundColor White -NoNewline ; Write-Host "|" -ForegroundColor Blue
Write-Host " " -NoNewline ; Write-Host " | |" -ForegroundColor Blue
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
2026-04-17 20:09:47 +02:00
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
2026-02-01 01:41:12 +01:00
Write-Host ""
Write-Host " Win11Debloat is launching..." -ForegroundColor White
2026-06-21 18:47:52 +02:00
Write-Host " Keep this window open" -ForegroundColor DarkGray
Write-Host ""
2026-02-01 01:41:12 +01:00
Write-Host ""
2024-06-26 20:27:25 +02:00
2025-05-10 13:02:48 +02:00
# Log script output to 'Win11Debloat.log' at the specified path
2025-05-25 20:25:06 +02:00
if ( $LogPath -and ( Test-Path $LogPath )) {
2026-05-08 21:19:52 +02:00
Start-Transcript -Path ( Join-Path $LogPath 'Win11Debloat.log' ) -Append -IncludeInvocationHeader -Force | Out-Null
2025-05-10 13:02:48 +02:00
}
else {
2025-12-26 20:36:51 +01:00
Start-Transcript -Path $script:DefaultLogPath -Append -IncludeInvocationHeader -Force | Out-Null
2025-05-10 13:02:48 +02:00
}
2024-06-26 20:27:25 +02:00
2026-08-09 06:24:14 +07:00
# When Group Policy overrides Run.bat's Process-scope Bypass, marked PowerShell source files
# can prompt as they are dot-sourced. Outside -WhatIf, remove Mark-of-the-Web only from marked
# .ps1, .psm1, and .psd1 files under Scripts; leave all other downloaded files untouched.
# See issue #720.
if ( -not $WhatIfPreference ) {
$gpoExecutionPolicySet = ( Get-ExecutionPolicy -Scope MachinePolicy ) -ne 'Undefined' -or
( Get-ExecutionPolicy -Scope UserPolicy ) -ne 'Undefined'
if ( $gpoExecutionPolicySet ) {
$markedScriptFiles = @ ( Get-ChildItem -LiteralPath $scriptsPath -Recurse -File |
Where-Object { $_ . Extension -in '.ps1' , '.psm1' , '.psd1' } |
Where-Object {
Get-Item -LiteralPath $_ . FullName -Stream * -ErrorAction SilentlyContinue |
Where-Object { $_ . Stream -eq 'Zone.Identifier' }
})
if ( $markedScriptFiles . Count -gt 0 ) {
Write-Host "Unblocking $( $markedScriptFiles . Count ) PowerShell file(s)..."
$unblockErrors = @ ()
$markedScriptFiles | Unblock-File -ErrorAction SilentlyContinue -ErrorVariable + unblockErrors
if ( $unblockErrors . Count -gt 0 ) {
Write-Warning "Failed to unblock $( $unblockErrors . Count ) PowerShell file(s)."
}
else {
Write-Host "All files were unblocked successfully."
}
}
}
}
2026-06-22 02:30:31 +07:00
# Check if the device is domain-joined and warn the user (Group Policy may override changes)
try {
$computerSystem = Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue
if ( $null -ne $computerSystem -and $computerSystem . PartOfDomain ) {
Write-Warning "This machine is domain-joined. Group Policy may override changes made by Win11Debloat."
}
}
catch { }
2026-02-01 01:41:12 +01:00
# Check if script has all required files
2026-05-08 21:19:52 +02:00
if ( -not (( Test-Path $script:DefaultSettingsFilePath ) -and ( Test-Path $script:AppsListFilePath ) -and ( Test-Path $script:RegfilesPath ) -and ( Test-Path $script:AssetsPath ) -and ( Test-Path $script:AppSelectionSchema ) -and ( Test-Path $script:ApplyChangesWindowSchema ) -and ( Test-Path $script:SharedStylesSchema ) -and ( Test-Path $script:BubbleHintSchema ) -and ( Test-Path $script:RestoreBackupWindowSchema ) -and ( Test-Path $script:FeaturesFilePath ))) {
2026-02-01 01:41:12 +01:00
Write-Error "Win11Debloat is unable to find required files, please ensure all script files are present"
Write-Output "Press any key to exit..."
$null = [ System.Console ]:: ReadKey ()
2026-08-12 15:56:29 +02:00
Exit 1
2026-02-01 01:41:12 +01:00
}
# Load feature info from file
$script:Features = @ {}
try {
$featuresData = Get-Content -Path $script:FeaturesFilePath -Raw | ConvertFrom-Json
foreach ( $feature in $featuresData . Features ) {
2026-06-23 00:41:33 +02:00
if ([ string ]:: IsNullOrWhiteSpace ([ string ] $feature . FeatureId ) -or [ string ]:: IsNullOrWhiteSpace ([ string ] $feature . Label ) -or [ string ]:: IsNullOrWhiteSpace ([ string ] $feature . ApplyText )) {
Write-Warning "Feature ' $( $feature . FeatureId ) ' is missing a FeatureId, Label, or ApplyText in Features.json and will be skipped."
continue
}
2026-02-01 01:41:12 +01:00
$script:Features [ $feature . FeatureId ] = $feature
}
}
catch {
Write-Error "Failed to load feature info from Features.json file"
Write-Output "Press any key to exit..."
$null = [ System.Console ]:: ReadKey ()
2026-08-12 15:56:29 +02:00
Exit 1
2026-02-01 01:41:12 +01:00
}
# Check if WinGet is installed & if it is, check if the version is at least v1.4
try {
2026-02-19 22:44:50 +01:00
if ( Get-Command winget -ErrorAction SilentlyContinue ) {
2026-02-01 01:41:12 +01:00
$script:WingetInstalled = $true
}
else {
$script:WingetInstalled = $false
}
}
catch {
2026-02-19 22:44:50 +01:00
Write-Error "Unable to determine if WinGet is installed, winget command failed: $_ "
2026-02-01 01:41:12 +01:00
$script:WingetInstalled = $false
}
# Show WinGet warning that requires user confirmation, Suppress confirmation if Silent parameter was passed
if ( -not $script:WingetInstalled -and -not $Silent ) {
Write-Warning "WinGet is not installed or outdated, this may prevent Win11Debloat from removing certain apps"
Write-Output ""
Write-Output "Press any key to continue anyway..."
$null = [ System.Console ]:: ReadKey ()
}
2025-12-15 23:22:29 +01:00
##################################################################################################################
# #
2026-03-15 22:58:06 +01:00
# FUNCTION IMPORTS #
2025-12-15 23:22:29 +01:00
# #
##################################################################################################################
2026-03-15 22:58:06 +01:00
# App removal functions
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/AppRemoval/Invoke-ForceRemoveEdge.ps1"
. " $PSScriptRoot /Scripts/AppRemoval/Remove-SelectedApps.ps1"
. " $PSScriptRoot /Scripts/AppRemoval/Get-WingetInstalledApps.ps1"
2026-06-22 22:13:01 +02:00
. " $PSScriptRoot /Scripts/AppRemoval/Test-AppInWingetList.ps1"
2026-03-07 20:28:48 +01:00
2026-03-15 22:58:06 +01:00
# CLI functions
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/CLI/Wait-ForKeyPress.ps1"
. " $PSScriptRoot /Scripts/CLI/Show-CliLastUsedSettings.ps1"
. " $PSScriptRoot /Scripts/CLI/Show-CliDefaultModeAppRemovalOptions.ps1"
. " $PSScriptRoot /Scripts/CLI/Show-CliDefaultModeOptions.ps1"
. " $PSScriptRoot /Scripts/CLI/Show-CliAppRemoval.ps1"
. " $PSScriptRoot /Scripts/CLI/Show-CliMenuOptions.ps1"
. " $PSScriptRoot /Scripts/CLI/Write-PendingChanges.ps1"
. " $PSScriptRoot /Scripts/CLI/Write-CliHeader.ps1"
2025-12-15 23:22:29 +01:00
2026-03-15 22:58:06 +01:00
# Features functions
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/Features/Get-CurrentTweakState.ps1"
. " $PSScriptRoot /Scripts/Features/Invoke-Changes.ps1"
2026-07-25 20:05:49 +02:00
. " $PSScriptRoot /Scripts/Features/Invoke-SystemRestorePoint.ps1"
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/Features/Backup-RegistryFeatureSelection.ps1"
. " $PSScriptRoot /Scripts/Features/Backup-RegistrySnapshotCapture.ps1"
. " $PSScriptRoot /Scripts/Features/Backup-RegistryState.ps1"
. " $PSScriptRoot /Scripts/Features/Registry-BackupValidation.ps1"
. " $PSScriptRoot /Scripts/Features/Restore-RegistryApplyState.ps1"
. " $PSScriptRoot /Scripts/Features/Restore-RegistryBackup.ps1"
. " $PSScriptRoot /Scripts/Features/Set-StoreSearchSuggestions.ps1"
. " $PSScriptRoot /Scripts/Features/Telemetry-ScheduledTasks.ps1"
. " $PSScriptRoot /Scripts/Features/Windows-OptionalFeatures.ps1"
. " $PSScriptRoot /Scripts/Features/Import-RegistryFile.ps1"
. " $PSScriptRoot /Scripts/Features/Replace-StartMenu.ps1"
. " $PSScriptRoot /Scripts/Features/Invoke-RestartExplorer.ps1"
2026-03-07 20:28:48 +01:00
2026-03-15 22:58:06 +01:00
# File I/O functions
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/FileIO/Import-JsonFile.ps1"
. " $PSScriptRoot /Scripts/FileIO/Save-ToFile.ps1"
. " $PSScriptRoot /Scripts/FileIO/Save-Settings.ps1"
. " $PSScriptRoot /Scripts/FileIO/Import-Settings.ps1"
. " $PSScriptRoot /Scripts/FileIO/Get-ValidatedAppList.ps1"
. " $PSScriptRoot /Scripts/FileIO/Import-AppsFromFile.ps1"
. " $PSScriptRoot /Scripts/FileIO/Import-AppDetailsFromJson.ps1"
. " $PSScriptRoot /Scripts/FileIO/Import-AppPresetsFromJson.ps1"
2026-03-15 22:58:06 +01:00
# GUI functions
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/GUI/Get-SystemUsesDarkMode.ps1"
. " $PSScriptRoot /Scripts/GUI/Set-WindowThemeResources.ps1"
. " $PSScriptRoot /Scripts/GUI/Attach-ShiftClickBehavior.ps1"
. " $PSScriptRoot /Scripts/GUI/Apply-SettingsToUiControls.ps1"
2026-02-15 23:08:54 +01:00
. " $PSScriptRoot /Scripts/GUI/Show-MessageBox.ps1"
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/GUI/Show-ImportExportConfigWindow.ps1"
2026-03-07 14:49:29 +01:00
. " $PSScriptRoot /Scripts/GUI/Show-ApplyModal.ps1"
2026-02-15 23:08:54 +01:00
. " $PSScriptRoot /Scripts/GUI/Show-AppSelectionWindow.ps1"
2026-05-08 21:19:52 +02:00
. " $PSScriptRoot /Scripts/GUI/Show-RestoreBackupWindow.ps1"
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/GUI/Restore-BackupDialogFeatureLists.ps1"
2026-05-08 21:19:52 +02:00
. " $PSScriptRoot /Scripts/GUI/Show-RestoreBackupDialog.ps1"
2026-06-10 17:40:31 +02:00
. " $PSScriptRoot /Scripts/GUI/MainWindow-WindowChrome.ps1"
. " $PSScriptRoot /Scripts/GUI/MainWindow-AppSelection.ps1"
. " $PSScriptRoot /Scripts/GUI/MainWindow-TweaksBuilder.ps1"
. " $PSScriptRoot /Scripts/GUI/MainWindow-Navigation.ps1"
. " $PSScriptRoot /Scripts/GUI/MainWindow-Deployment.ps1"
2026-02-15 23:08:54 +01:00
. " $PSScriptRoot /Scripts/GUI/Show-MainWindow.ps1"
. " $PSScriptRoot /Scripts/GUI/Show-AboutDialog.ps1"
2026-03-15 20:16:53 +01:00
. " $PSScriptRoot /Scripts/GUI/Show-Bubble.ps1"
2026-02-15 23:08:54 +01:00
2026-03-15 22:58:06 +01:00
# Helper functions
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/Helpers/Add-Parameter.ps1"
. " $PSScriptRoot /Scripts/Helpers/Resolve-UserProfilePath.ps1"
. " $PSScriptRoot /Scripts/Helpers/User-HiveHelpers.ps1"
. " $PSScriptRoot /Scripts/Helpers/Test-UserProfileExists.ps1"
. " $PSScriptRoot /Scripts/Helpers/Test-ModernStandbySupport.ps1"
. " $PSScriptRoot /Scripts/Helpers/Generate-AppsList.ps1"
. " $PSScriptRoot /Scripts/Helpers/Get-FriendlyRegistryBackupTarget.ps1"
. " $PSScriptRoot /Scripts/Helpers/Get-FriendlyTargetUserName.ps1"
2026-07-11 20:04:51 +02:00
. " $PSScriptRoot /Scripts/Helpers/Get-RebootFeatureLabels.ps1"
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/Helpers/Import-ConfigToParams.ps1"
. " $PSScriptRoot /Scripts/Helpers/Get-TargetUserForAppRemoval.ps1"
2026-05-08 21:19:52 +02:00
. " $PSScriptRoot /Scripts/Helpers/Get-RegFileOperations.ps1"
. " $PSScriptRoot /Scripts/Helpers/Test-TargetUserName.ps1"
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/Helpers/Get-UserDirectory.ps1"
. " $PSScriptRoot /Scripts/Helpers/Get-UserName.ps1"
. " $PSScriptRoot /Scripts/Helpers/Registry-PathHelpers.ps1"
. " $PSScriptRoot /Scripts/Helpers/Apply-RegistryRegFile.ps1"
. " $PSScriptRoot /Scripts/Helpers/Confirm-UnsafeAppRemoval.ps1"
2025-12-15 23:22:29 +01:00
2026-03-15 22:58:06 +01:00
# Threading functions
2026-07-19 22:06:07 +02:00
. " $PSScriptRoot /Scripts/Threading/Invoke-DoEvents.ps1"
2026-03-15 22:58:06 +01:00
. " $PSScriptRoot /Scripts/Threading/Invoke-NonBlocking.ps1"
2026-02-01 01:41:12 +01:00
2024-06-27 23:08:43 +02:00
##################################################################################################################
# #
# SCRIPT START #
# #
##################################################################################################################
2026-02-01 01:41:12 +01:00
# Get current Windows build version
2024-06-27 23:08:43 +02:00
$WinVersion = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' CurrentBuild
2025-08-22 17:50:47 +02:00
# Check if the machine supports Modern Standby, this is used to determine if the DisableModernStandbyNetworking option can be used
2026-07-19 22:06:07 +02:00
$script:ModernStandbySupported = Test-ModernStandbySupport
2025-08-19 23:24:28 +05:30
2025-05-10 13:02:48 +02:00
$script:Params = $PSBoundParameters
2026-06-10 17:40:31 +02:00
$script:UndoParams = @ {}
2023-09-27 21:03:25 +02:00
2025-12-26 20:36:51 +01:00
# Add default Apps parameter when RemoveApps is requested and Apps was not explicitly provided
if (( -not $script:Params . ContainsKey ( "Apps" )) -and $script:Params . ContainsKey ( "RemoveApps" )) {
$script:Params . Add ( 'Apps' , 'Default' )
}
$controlParamsCount = 0
# Count how many control parameters are set, to determine if any changes were selected by the user during runtime
foreach ( $Param in $script:ControlParams ) {
2025-05-10 13:02:48 +02:00
if ( $script:Params . ContainsKey ( $Param )) {
2025-12-26 20:36:51 +01:00
$controlParamsCount ++
2023-09-27 21:03:25 +02:00
}
}
2024-08-17 00:08:09 +02:00
# Hide progress bars for app removal, as they block Win11Debloat's output
2025-05-10 13:02:48 +02:00
if ( -not ( $script:Params . ContainsKey ( "Verbose" ))) {
2024-08-17 00:08:09 +02:00
$ProgressPreference = 'SilentlyContinue'
}
else {
2025-05-07 15:51:01 +02:00
Write-Host "Verbose mode is enabled"
Write-Output ""
Write-Output "Press any key to continue..."
$null = [ System.Console ]:: ReadKey ()
2024-08-17 00:08:09 +02:00
$ProgressPreference = 'Continue'
}
2025-05-10 13:02:48 +02:00
if ( $script:Params . ContainsKey ( "Sysprep" )) {
2026-07-19 22:06:07 +02:00
Get-UserDirectory -userName "Default" | Out-Null
2024-08-31 22:13:59 +02:00
2024-06-27 23:08:43 +02:00
# Exit script if run in Sysprep mode on Windows 10
if ( $WinVersion -lt 22000 ) {
2025-12-26 20:36:51 +01:00
Write-Error "Win11Debloat Sysprep mode is not supported on Windows 10"
2026-08-12 15:56:29 +02:00
Wait-ForKeyPress -ExitCode 1
2024-06-27 23:08:43 +02:00
}
}
2026-02-12 22:50:22 +01:00
# Ensure that target user exists, if User or AppRemovalTarget parameter was provided
2025-05-10 13:02:48 +02:00
if ( $script:Params . ContainsKey ( "User" )) {
2026-07-19 22:06:07 +02:00
Get-UserDirectory -userName $script:Params . Item ( "User" ) | Out-Null
2025-03-05 23:39:29 +01:00
}
2026-02-12 22:50:22 +01:00
if ( $script:Params . ContainsKey ( "AppRemovalTarget" )) {
2026-06-21 23:39:10 +07:00
$appRemovalTargetValue = $script:Params . Item ( "AppRemovalTarget" )
# 'AllUsers' / 'CurrentUser' are sentinel scope values, not real usernames - don't resolve them as a profile
if ( $appRemovalTargetValue -notin @ ( 'AllUsers' , 'CurrentUser' )) {
2026-07-19 22:06:07 +02:00
Get-UserDirectory -userName $appRemovalTargetValue | Out-Null
2026-06-21 23:39:10 +07:00
}
2026-02-12 22:50:22 +01:00
}
2025-03-05 23:39:29 +01:00
2025-12-26 20:36:51 +01:00
# Remove LastUsedSettings.json file if it exists and is empty
if (( Test-Path $script:SavedSettingsFilePath ) -and ([ String ]:: IsNullOrWhiteSpace (( Get-content $script:SavedSettingsFilePath )))) {
2026-08-12 16:40:26 +02:00
Remove-Item -Path $script:SavedSettingsFilePath -Force
2023-12-15 13:22:35 +01:00
}
2026-04-02 00:03:26 +02:00
# Default to CLI mode for deployment-targeted parameters.
$launchInCLI = $CLI -or $script:Params . ContainsKey ( "User" ) -or $script:Params . ContainsKey ( "Sysprep" ) -or $script:Params . ContainsKey ( "AppRemovalTarget" )
2023-08-07 00:49:41 +02:00
# Change script execution based on provided parameters or user input
2026-03-27 20:33:24 +01:00
if (( -not $script:Params . Count ) -or $RunDefaults -or $RunDefaultsLite -or $RunSavedSettings -or $Config -or ( $controlParamsCount -eq $script:Params . Count )) {
2025-09-13 23:36:38 +02:00
if ( $RunDefaults -or $RunDefaultsLite ) {
2026-07-19 22:06:07 +02:00
Show-CliDefaultModeOptions
2020-11-07 02:57:38 +01:00
}
2025-01-09 21:33:28 +01:00
elseif ( $RunSavedSettings ) {
2025-12-26 20:36:51 +01:00
if ( -not ( Test-Path $script:SavedSettingsFilePath )) {
2026-07-19 22:06:07 +02:00
Write-CliHeader 'Custom Mode'
2025-12-26 20:36:51 +01:00
Write-Error "Unable to find LastUsedSettings.json file, no changes were made"
2026-08-12 15:56:29 +02:00
Wait-ForKeyPress -ExitCode 1
2025-01-09 21:33:28 +01:00
}
2026-07-19 22:06:07 +02:00
Show-CliLastUsedSettings
2025-01-09 21:33:28 +01:00
}
2026-03-27 20:33:24 +01:00
elseif ( $Config ) {
try {
2026-07-19 22:06:07 +02:00
Import-ConfigToParams -ConfigPath $Config -CurrentBuild $WinVersion -ExpectedVersion '1.0'
2026-03-27 20:33:24 +01:00
}
catch {
Write-Error " $_ "
2026-08-12 15:56:29 +02:00
Wait-ForKeyPress -ExitCode 1
2026-03-27 20:33:24 +01:00
}
if ( -not $Silent ) {
2026-07-19 22:06:07 +02:00
Write-CliHeader 'Custom Mode'
Write-PendingChanges
Write-CliHeader 'Custom Mode'
2026-03-27 20:33:24 +01:00
}
}
2023-05-15 16:38:11 -06:00
else {
2026-04-02 00:03:26 +02:00
if ( $launchInCLI ) {
2026-07-19 22:06:07 +02:00
$Mode = Show-CliMenuOptions
2026-02-01 01:41:12 +01:00
}
else {
try {
2026-02-15 23:08:54 +01:00
$result = Show-MainWindow
2026-02-01 01:41:12 +01:00
2026-06-22 02:30:31 +07:00
try {
Stop-Transcript
}
catch { }
2026-02-01 01:41:12 +01:00
Exit
}
catch {
2026-08-12 16:38:14 +02:00
Write-Warning "The graphical interface could not start: $( $_ . Exception . Message ) "
Write-Verbose "GUI Failure details: $( $_ . Exception . ToString ()) "
2026-02-01 13:12:32 +01:00
if ( -not $Silent ) {
Write-Host ""
2026-08-12 16:38:14 +02:00
Write-Host "Press any key to continue in CLI mode..."
2026-02-01 13:12:32 +01:00
$null = [ System.Console ]:: ReadKey ()
}
2026-07-19 22:06:07 +02:00
$Mode = Show-CliMenuOptions
2026-02-01 01:41:12 +01:00
}
}
2020-11-07 02:57:38 +01:00
}
2020-10-27 23:26:39 +01:00
2022-04-09 18:52:16 +02:00
# Add execution parameters based on the mode
2023-05-15 16:38:11 -06:00
switch ( $Mode ) {
2025-12-15 23:22:29 +01:00
# Default mode, loads defaults and app removal options
2023-05-15 16:38:11 -06:00
'1' {
2026-07-19 22:06:07 +02:00
Show-CliDefaultModeOptions
2020-11-07 02:57:38 +01:00
}
2022-09-08 17:20:53 +02:00
2024-03-29 16:56:29 +01:00
# App removal, remove apps based on user selection
2026-02-01 01:41:12 +01:00
'2' {
2026-07-19 22:06:07 +02:00
Show-CliAppRemoval
2024-03-29 16:56:29 +01:00
}
2025-12-26 20:36:51 +01:00
# Load last used options from the "LastUsedSettings.json" file
2026-02-01 01:41:12 +01:00
'3' {
2026-07-19 22:06:07 +02:00
Show-CliLastUsedSettings
2020-11-07 02:57:38 +01:00
}
}
}
2023-05-15 16:38:11 -06:00
else {
2026-07-19 22:06:07 +02:00
Write-CliHeader 'Configuration'
2020-10-27 23:26:39 +01:00
}
2025-12-26 20:36:51 +01:00
# If the number of keys in ControlParams equals the number of keys in Params then no modifications/changes were selected
2024-03-01 13:54:02 +01:00
# or added by the user, and the script can exit without making any changes.
2025-12-26 20:36:51 +01:00
if (( $controlParamsCount -eq $script:Params . Keys . Count ) -or ( $script:Params . Keys . Count -eq 1 -and ( $script:Params . Keys -contains 'CreateRestorePoint' -or $script:Params . Keys -contains 'Apps' ))) {
2023-09-28 16:11:04 +02:00
Write-Output "The script completed without making any changes."
2026-07-19 22:06:07 +02:00
Wait-ForKeyPress
2020-10-27 23:26:39 +01:00
}
2025-02-13 21:08:47 +01:00
2026-02-01 01:41:12 +01:00
# Execute all selected/provided parameters using the consolidated function
# (This also handles restore point creation if requested)
2026-06-22 21:43:53 +02:00
Invoke-AllChanges
2025-05-04 23:33:20 +02:00
2026-07-14 23:06:40 +03:00
if ( $script:CancelRequested ) {
Write-Warning "Script execution was cancelled by the user. Any remaining changes were not applied."
2026-07-19 22:06:07 +02:00
Wait-ForKeyPress
2026-07-14 23:06:40 +03:00
}
2026-07-11 20:04:51 +02:00
# Restart Explorer process unless running in Sysprep or User context
if ( -not ( $script:Params . ContainsKey ( "Sysprep" ) -or $script:Params . ContainsKey ( "User" ))) {
2026-07-19 22:06:07 +02:00
Invoke-RestartExplorer
2026-07-11 20:04:51 +02:00
}
2025-05-04 23:33:20 +02:00
Write-Output ""
Write-Output ""
Write-Output ""
Write-Output "Script completed! Please check above for any errors."
2026-07-19 22:06:07 +02:00
Wait-ForKeyPress