Add option to disable MS Store app results in Windows Search (#509)

This also includes:

* Update README for DisableSearchHighlights and DisableFindMyDevice

* Extracted more logic from main script into separate scripts

* Add event handler for tab changes to regenerate overview
This commit is contained in:
Jeffrey
2026-03-07 20:28:48 +01:00
committed by GitHub
parent bbfbd7193e
commit ad0b49060a
15 changed files with 623 additions and 529 deletions

View File

@@ -10,7 +10,7 @@
"Icon": "" "Icon": ""
}, },
{ {
"Name": "Start Menu", "Name": "Start Menu & Search",
"Icon": "" "Icon": ""
}, },
{ {
@@ -166,10 +166,11 @@
"GroupId": "ClearStart", "GroupId": "ClearStart",
"Label": "Remove pinned apps from the start menu", "Label": "Remove pinned apps from the start menu",
"ToolTip": "This setting allows you to quickly remove all pinned apps from the start menu.", "ToolTip": "This setting allows you to quickly remove all pinned apps from the start menu.",
"Category": "Start Menu", "Category": "Start Menu & Search",
"Priority": 1,
"Values": [ "Values": [
{ {
"Label": "Remove for the current user", "Label": "Remove for the selected user",
"FeatureIds": [ "FeatureIds": [
"ClearStart" "ClearStart"
] ]
@@ -397,19 +398,6 @@
"MinVersion": null, "MinVersion": null,
"MaxVersion": null "MaxVersion": null
}, },
{
"FeatureId": "DisableSearchHistory",
"Label": "local Windows Search history",
"ToolTip": "This setting disables local search history in Windows Search. This does not affect web search history or the search history saved in Microsoft Edge.",
"Category": "Privacy & Suggested Content",
"Action": "Disable",
"RegistryKey": "Disable_Search_History.reg",
"ApplyText": "Disabling search history...",
"UndoAction": "Enable",
"RegistryUndoKey": "Enable_Search_History.reg",
"MinVersion": null,
"MaxVersion": null
},
{ {
"FeatureId": "DisableLockscreenTips", "FeatureId": "DisableLockscreenTips",
"Label": "tips & tricks on the lock screen", "Label": "tips & tricks on the lock screen",
@@ -518,7 +506,7 @@
"FeatureId": "ClearStart", "FeatureId": "ClearStart",
"Action": "Clear Start Menu", "Action": "Clear Start Menu",
"Label": "Remove all pinned apps from the start menu for this user only", "Label": "Remove all pinned apps from the start menu for this user only",
"Category": "Start Menu", "Category": "Start Menu & Search",
"RegistryKey": null, "RegistryKey": null,
"ApplyText": null, "ApplyText": null,
"UndoAction": null, "UndoAction": null,
@@ -530,7 +518,7 @@
"FeatureId": "ClearStartAllUsers", "FeatureId": "ClearStartAllUsers",
"Action": "Clear Start Menu (All Users)", "Action": "Clear Start Menu (All Users)",
"Label": "Remove all pinned apps from the start menu for all existing and new users", "Label": "Remove all pinned apps from the start menu for all existing and new users",
"Category": "Start Menu", "Category": "Start Menu & Search",
"RegistryKey": null, "RegistryKey": null,
"ApplyText": null, "ApplyText": null,
"UndoAction": null, "UndoAction": null,
@@ -566,7 +554,7 @@
"FeatureId": "DisableStartRecommended", "FeatureId": "DisableStartRecommended",
"Label": "recommended section in the start menu", "Label": "recommended section in the start menu",
"ToolTip": "This will hide the recommended section in the start menu, which shows recently added apps, recently opened files and app recommendations. This feature uses policies, which will lock down certain settings.", "ToolTip": "This will hide the recommended section in the start menu, which shows recently added apps, recently opened files and app recommendations. This feature uses policies, which will lock down certain settings.",
"Category": "Start Menu", "Category": "Start Menu & Search",
"Action": "Hide", "Action": "Hide",
"RegistryKey": "Disable_Start_Recommended.reg", "RegistryKey": "Disable_Start_Recommended.reg",
"ApplyText": "Disabling the start menu recommended section...", "ApplyText": "Disabling the start menu recommended section...",
@@ -575,11 +563,24 @@
"MinVersion": 22621, "MinVersion": 22621,
"MaxVersion": null "MaxVersion": null
}, },
{
"FeatureId": "DisableStartPhoneLink",
"Label": "Phone Link integration in the start menu",
"ToolTip": "This will remove the Phone Link integration in the start menu when you have a mobile device linked to your PC.",
"Category": "Start Menu & Search",
"Action": "Disable",
"RegistryKey": "Disable_Phone_Link_In_Start.reg",
"ApplyText": "Disabling the Phone Link mobile devices integration in the start menu...",
"UndoAction": "Enable",
"RegistryUndoKey": "Enable_Phone_Link_In_Start.reg",
"MinVersion": 22621,
"MaxVersion": null
},
{ {
"FeatureId": "DisableBing", "FeatureId": "DisableBing",
"Label": "Bing web search & Copilot integration in search", "Label": "Bing web search & Copilot integration in search",
"ToolTip": "This will turn off Bing web search results and Copilot integration in the Windows search experience. This feature uses policies, which will lock down certain settings.", "ToolTip": "This will turn off Bing web search results and Copilot integration in the Windows search experience. This feature uses policies, which will lock down certain settings.",
"Category": "Start Menu", "Category": "Start Menu & Search",
"Action": "Disable", "Action": "Disable",
"RegistryKey": "Disable_Bing_Cortana_In_Search.reg", "RegistryKey": "Disable_Bing_Cortana_In_Search.reg",
"ApplyText": "Disabling Bing web search & Copilot integration in Windows search...", "ApplyText": "Disabling Bing web search & Copilot integration in Windows search...",
@@ -588,11 +589,24 @@
"MinVersion": null, "MinVersion": null,
"MaxVersion": null "MaxVersion": null
}, },
{
"FeatureId": "DisableStoreSearchSuggestions",
"Label": "Microsoft Store app suggestions in search",
"ToolTip": "This will disable the Microsoft Store app suggestions in Windows search.",
"Category": "Start Menu & Search",
"Action": "Disable",
"RegistryKey": null,
"ApplyText": null,
"UndoAction": null,
"RegistryUndoKey": null,
"MinVersion": 22621,
"MaxVersion": null
},
{ {
"FeatureId": "DisableSearchHighlights", "FeatureId": "DisableSearchHighlights",
"Label": "Search Highlights (dynamic/branded content in Windows search box)", "Label": "Search Highlights in the taskbar search box",
"ToolTip": "This will turn off Search Highlights, which shows dynamically curated branded content and trending topics in the Windows search box on the taskbar.", "ToolTip": "This will turn off Search Highlights, which shows dynamically curated branded content and trending topics in the Windows search box on the taskbar.",
"Category": "Privacy & Suggested Content", "Category": "Start Menu & Search",
"Action": "Disable", "Action": "Disable",
"RegistryKey": "Disable_Search_Highlights.reg", "RegistryKey": "Disable_Search_Highlights.reg",
"ApplyText": "> Disabling Search Highlights in the Windows search box...", "ApplyText": "> Disabling Search Highlights in the Windows search box...",
@@ -602,16 +616,16 @@
"MaxVersion": null "MaxVersion": null
}, },
{ {
"FeatureId": "DisableStartPhoneLink", "FeatureId": "DisableSearchHistory",
"Label": "Phone Link integration in the start menu", "Label": "local Windows Search history",
"ToolTip": "This will remove the Phone Link integration in the start menu when you have a mobile device linked to your PC.", "ToolTip": "This setting disables local search history in Windows Search. This does not affect web search history or the search history saved in Microsoft Edge.",
"Category": "Start Menu", "Category": "Start Menu & Search",
"Action": "Disable", "Action": "Disable",
"RegistryKey": "Disable_Phone_Link_In_Start.reg", "RegistryKey": "Disable_Search_History.reg",
"ApplyText": "Disabling the Phone Link mobile devices integration in the start menu...", "ApplyText": "Disabling search history...",
"UndoAction": "Enable", "UndoAction": "Enable",
"RegistryUndoKey": "Enable_Phone_Link_In_Start.reg", "RegistryUndoKey": "Enable_Search_History.reg",
"MinVersion": 22621, "MinVersion": null,
"MaxVersion": null "MaxVersion": null
}, },
{ {

View File

@@ -25,6 +25,10 @@
"Name": "DisableBing", "Name": "DisableBing",
"Value": true "Value": true
}, },
{
"Name": "DisableStoreSearchSuggestions",
"Value": true
},
{ {
"Name": "DisableSearchHighlights", "Name": "DisableSearchHighlights",
"Value": true "Value": true

View File

@@ -88,7 +88,7 @@ Below is an overview of the key features and functionality offered by Win11Deblo
- Disable telemetry, diagnostic data, activity history, app-launch tracking & targeted ads. - Disable telemetry, diagnostic data, activity history, app-launch tracking & targeted ads.
- Disable tips, tricks, suggestions & ads across Windows. - Disable tips, tricks, suggestions & ads across Windows.
- Disable Windows location services & app location access. - Disable Windows location services & app location access.
- Disable local Windows search history. - Disable Find My Device location tracking.
- Disable 'Windows Spotlight' and tips & tricks on the lock screen. - Disable 'Windows Spotlight' and tips & tricks on the lock screen.
- Disable 'Windows Spotlight' desktop background option. - Disable 'Windows Spotlight' desktop background option.
- Disable ads, suggestions and the MSN news feed in Microsoft Edge. - Disable ads, suggestions and the MSN news feed in Microsoft Edge.
@@ -125,12 +125,15 @@ Below is an overview of the key features and functionality offered by Win11Deblo
- Disable transparency effects - Disable transparency effects
- Disable animations and visual effects. - Disable animations and visual effects.
#### Start Menu #### Start Menu & Search
- Remove or replace all pinned apps from start for the current user, or for all existing & new users. (W11 only) - Remove or replace all pinned apps from start for the current user, or for all existing & new users. (W11 only)
- Disable the recommended section in the start menu. (W11 only) - Disable the recommended section in the start menu. (W11 only)
- Disable Bing web search & Copilot integration in Windows search.
- Disable the Phone Link mobile devices integration in the start menu. (W11 only) - Disable the Phone Link mobile devices integration in the start menu. (W11 only)
- Disable Bing web search & Copilot integration in Windows search.
- Disable Microsoft Store app suggestions in Windows search. (W11 only)
- Disable Search Highlights (dynamic/branded content) in the taskbar search box. (W11 only)
- Disable local Windows search history.
#### Taskbar #### Taskbar

View File

@@ -0,0 +1,57 @@
# Forcefully removes Microsoft Edge using its uninstaller
# Credit: Based on work from loadstring1 & ave9858
function ForceRemoveEdge {
Write-Host "> Forcefully uninstalling Microsoft Edge..."
$regView = [Microsoft.Win32.RegistryView]::Registry32
$hklm = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $regView)
$hklm.CreateSubKey('SOFTWARE\Microsoft\EdgeUpdateDev').SetValue('AllowUninstall', '')
# Create stub (This somehow allows uninstalling Edge)
$edgeStub = "$env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe"
New-Item $edgeStub -ItemType Directory | Out-Null
New-Item "$edgeStub\MicrosoftEdge.exe" | Out-Null
# Remove edge
$uninstallRegKey = $hklm.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge')
if ($null -ne $uninstallRegKey) {
Write-Host "Running uninstaller..."
$uninstallString = $uninstallRegKey.GetValue('UninstallString') + ' --force-uninstall'
Invoke-NonBlocking -ScriptBlock {
param($cmd)
Start-Process cmd.exe "/c $cmd" -WindowStyle Hidden -Wait
} -ArgumentList $uninstallString
Write-Host "Removing leftover files..."
$edgePaths = @(
"$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk",
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\Microsoft Edge.lnk",
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Microsoft Edge.lnk",
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Tombstones\Microsoft Edge.lnk",
"$env:PUBLIC\Desktop\Microsoft Edge.lnk",
"$env:USERPROFILE\Desktop\Microsoft Edge.lnk",
"$edgeStub"
)
foreach ($path in $edgePaths) {
if (Test-Path -Path $path) {
Remove-Item -Path $path -Force -Recurse -ErrorAction SilentlyContinue
Write-Host " Removed $path" -ForegroundColor DarkGray
}
}
Write-Host "Cleaning up registry..."
# Remove MS Edge from autostart
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "MicrosoftEdgeAutoLaunch_A9F6DCE4ABADF4F51CF45CD7129E3C6C" /f *>$null
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "Microsoft Edge Update" /f *>$null
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run" /v "MicrosoftEdgeAutoLaunch_A9F6DCE4ABADF4F51CF45CD7129E3C6C" /f *>$null
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run" /v "Microsoft Edge Update" /f *>$null
Write-Host "Microsoft Edge was uninstalled"
}
else {
Write-Host "Unable to forcefully uninstall Microsoft Edge, uninstaller could not be found" -ForegroundColor Red
}
}

View File

@@ -0,0 +1,111 @@
# Removes apps specified during function call based on the target scope.
function RemoveApps {
param (
$appslist
)
# Determine target from script-level params, defaulting to AllUsers
$targetUser = GetTargetUserForAppRemoval
$appIndex = 0
$appCount = @($appsList).Count
Foreach ($app in $appsList) {
if ($script:CancelRequested) {
return
}
$appIndex++
# Update step name and sub-progress to show which app is being removed (only for bulk removal)
if ($script:ApplySubStepCallback -and $appCount -gt 1) {
& $script:ApplySubStepCallback "Removing apps ($appIndex/$appCount)" $appIndex $appCount
}
Write-Host "Attempting to remove $app..."
# Use WinGet only to remove OneDrive and Edge
if (($app -eq "Microsoft.OneDrive") -or ($app -eq "Microsoft.Edge")) {
if ($script:WingetInstalled -eq $false) {
Write-Host "WinGet is either not installed or is outdated, $app could not be removed" -ForegroundColor Red
continue
}
$appName = $app -replace '\.', '_'
# Uninstall app via WinGet, or create a scheduled task to uninstall it later
if ($script:Params.ContainsKey("User")) {
ImportRegistryFile "Adding scheduled task to uninstall $app for user $(GetUserName)..." "Uninstall_$($appName).reg"
}
elseif ($script:Params.ContainsKey("Sysprep")) {
ImportRegistryFile "Adding scheduled task to uninstall $app after for new users..." "Uninstall_$($appName).reg"
}
else {
# Uninstall app via WinGet
$wingetOutput = Invoke-NonBlocking -ScriptBlock {
param($appId)
winget uninstall --accept-source-agreements --disable-interactivity --id $appId
} -ArgumentList $app
If (($app -eq "Microsoft.Edge") -and (Select-String -InputObject $wingetOutput -Pattern "Uninstall failed with exit code")) {
Write-Host "Unable to uninstall Microsoft Edge via WinGet" -ForegroundColor Red
if ($script:GuiWindow) {
$result = Show-MessageBox -Message 'Unable to uninstall Microsoft Edge via WinGet. Would you like to forcefully uninstall it? NOT RECOMMENDED!' -Title 'Force Uninstall Microsoft Edge?' -Button 'YesNo' -Icon 'Warning'
if ($result -eq 'Yes') {
Write-Host ""
ForceRemoveEdge
}
}
elseif ($( Read-Host -Prompt "Would you like to forcefully uninstall Microsoft Edge? NOT RECOMMENDED! (y/n)" ) -eq 'y') {
Write-Host ""
ForceRemoveEdge
}
}
}
continue
}
# Use Remove-AppxPackage to remove all other apps
$appPattern = '*' + $app + '*'
try {
switch ($targetUser) {
"AllUsers" {
# Remove installed app for all existing users, and from OS image
Invoke-NonBlocking -ScriptBlock {
param($pattern)
Get-AppxPackage -Name $pattern -AllUsers | Remove-AppxPackage -AllUsers -ErrorAction Continue
Get-AppxProvisionedPackage -Online | Where-Object { $_.PackageName -like $pattern } | ForEach-Object { Remove-ProvisionedAppxPackage -Online -AllUsers -PackageName $_.PackageName }
} -ArgumentList $appPattern
}
"CurrentUser" {
# Remove installed app for current user only
Invoke-NonBlocking -ScriptBlock {
param($pattern)
Get-AppxPackage -Name $pattern | Remove-AppxPackage -ErrorAction Continue
} -ArgumentList $appPattern
}
default {
# Target is a specific username - remove app for that user only
Invoke-NonBlocking -ScriptBlock {
param($pattern, $user)
$userAccount = New-Object System.Security.Principal.NTAccount($user)
$userSid = $userAccount.Translate([System.Security.Principal.SecurityIdentifier]).Value
Get-AppxPackage -Name $pattern -User $userSid | Remove-AppxPackage -User $userSid -ErrorAction Continue
} -ArgumentList @($appPattern, $targetUser)
}
}
}
catch {
if ($DebugPreference -ne "SilentlyContinue") {
Write-Host "Something went wrong while trying to remove $app" -ForegroundColor Yellow
Write-Host $psitem.Exception.StackTrace -ForegroundColor Gray
}
}
}
Write-Host ""
}

View File

@@ -0,0 +1,11 @@
function AwaitKeyToExit {
# Suppress prompt if Silent parameter was passed
if (-not $Silent) {
Write-Output ""
Write-Output "Press any key to exit..."
$null = [System.Console]::ReadKey()
}
Stop-Transcript
Exit
}

View File

@@ -0,0 +1,104 @@
function CreateSystemRestorePoint {
$SysRestore = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore" -Name "RPSessionInterval"
$failed = $false
if ($SysRestore.RPSessionInterval -eq 0) {
# In GUI mode, skip the prompt and just try to enable it
if ($script:GuiWindow -or $Silent -or $( Read-Host -Prompt "System restore is disabled, would you like to enable it and create a restore point? (y/n)") -eq 'y') {
$enableSystemRestoreJob = Start-Job {
try {
Enable-ComputerRestore -Drive "$env:SystemDrive"
}
catch {
return "Error: Failed to enable System Restore: $_"
}
return $null
}
$enableSystemRestoreJobDone = $enableSystemRestoreJob | Wait-Job -TimeOut 20
if (-not $enableSystemRestoreJobDone) {
Remove-Job -Job $enableSystemRestoreJob -Force -ErrorAction SilentlyContinue
Write-Host "Error: Failed to enable system restore and create restore point, operation timed out" -ForegroundColor Red
$failed = $true
}
else {
$result = Receive-Job $enableSystemRestoreJob
Remove-Job -Job $enableSystemRestoreJob -ErrorAction SilentlyContinue
if ($result) {
Write-Host $result -ForegroundColor Red
$failed = $true
}
}
}
else {
Write-Host ""
$failed = $true
}
}
if (-not $failed) {
$createRestorePointJob = Start-Job {
# Find existing restore points that are less than 24 hours old
try {
$recentRestorePoints = Get-ComputerRestorePoint | Where-Object { (Get-Date) - [System.Management.ManagementDateTimeConverter]::ToDateTime($_.CreationTime) -le (New-TimeSpan -Hours 24) }
}
catch {
return @{ Success = $false; Message = "Error: Unable to retrieve existing restore points: $_" }
}
if ($recentRestorePoints.Count -eq 0) {
try {
Checkpoint-Computer -Description "Restore point created by Win11Debloat" -RestorePointType "MODIFY_SETTINGS"
return @{ Success = $true; Message = "System restore point created successfully" }
}
catch {
return @{ Success = $false; Message = "Error: Unable to create restore point: $_" }
}
}
else {
return @{ Success = $true; Message = "A recent restore point already exists, no new restore point was created" }
}
}
$createRestorePointJobDone = $createRestorePointJob | Wait-Job -TimeOut 20
if (-not $createRestorePointJobDone) {
Remove-Job -Job $createRestorePointJob -Force -ErrorAction SilentlyContinue
Write-Host "Error: Failed to create system restore point, operation timed out" -ForegroundColor Red
$failed = $true
}
else {
$result = Receive-Job $createRestorePointJob
Remove-Job -Job $createRestorePointJob -ErrorAction SilentlyContinue
if ($result.Success) {
Write-Host $result.Message
}
else {
Write-Host $result.Message -ForegroundColor Red
$failed = $true
}
}
}
# Ensure that the user is aware if creating a restore point failed, and give them the option to continue without a restore point or cancel the script
if ($failed) {
if ($script:GuiWindow) {
$result = Show-MessageBox "Failed to create a system restore point. Do you want to continue without a restore point?" "Restore Point Creation Failed" "YesNo" "Warning"
if ($result -ne "Yes") {
$script:CancelRequested = $true
return
}
}
elseif (-not $Silent) {
Write-Host "Failed to create a system restore point. Do you want to continue without a restore point? (y/n)" -ForegroundColor Yellow
if ($( Read-Host ) -ne 'y') {
$script:CancelRequested = $true
return
}
}
Write-Host "Warning: Continuing without restore point" -ForegroundColor Yellow
}
}

View File

@@ -0,0 +1,52 @@
# Disables Microsoft Store search suggestions in the start menu for all users by denying access to the Store app database file for each user
function DisableStoreSearchSuggestionsForAllUsers {
# Get path to Store app database for all users
$userPathString = GetUserDirectory -userName "*" -fileName "AppData\Local\Packages"
$usersStoreDbPaths = get-childitem -path $userPathString
# Go through all users and disable start search suggestions
ForEach ($storeDbPath in $usersStoreDbPaths) {
DisableStoreSearchSuggestions ($storeDbPath.FullName + "\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db")
}
# Also disable start search suggestions for the default user profile
$defaultStoreDbPath = GetUserDirectory -userName "Default" -fileName "AppData\Local\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db" -exitIfPathNotFound $false
DisableStoreSearchSuggestions $defaultStoreDbPath
}
# Disables Microsoft Store search suggestions in the start menu by denying access to the Store app database file
function DisableStoreSearchSuggestions {
param (
$StoreAppsDatabase = "$env:LocalAppData\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db"
)
# Change path to correct user if a user was specified
if ($script:Params.ContainsKey("User")) {
$StoreAppsDatabase = GetUserDirectory -userName "$(GetUserName)" -fileName "AppData\Local\Packages\Microsoft.WindowsStore_8wekyb3d8bbwe\LocalState\store.db" -exitIfPathNotFound $false
}
$userName = [regex]::Match($StoreAppsDatabase, '(?:Users\\)([^\\]+)(?:\\AppData)').Groups[1].Value
# This file doesn't exist in EEA (No Store app suggestions).
if (-not (Test-Path -Path $StoreAppsDatabase))
{
Write-Host "Unable to find Store app database for user $userName, creating it now to prevent Windows from creating it later..." -ForegroundColor Yellow
$storeDbDir = Split-Path -Path $StoreAppsDatabase -Parent
if (-not (Test-Path -Path $storeDbDir)) {
New-Item -Path $storeDbDir -ItemType Directory -Force | Out-Null
}
New-Item -Path $StoreAppsDatabase -ItemType File -Force | Out-Null
}
$AccountSid = [System.Security.Principal.SecurityIdentifier]::new('S-1-1-0') # 'EVERYONE' group
$Acl = Get-Acl -Path $StoreAppsDatabase
$Ace = [System.Security.AccessControl.FileSystemAccessRule]::new($AccountSid, 'FullControl', 'Deny')
$Acl.SetAccessRule($Ace) | Out-Null
Set-Acl -Path $StoreAppsDatabase -AclObject $Acl | Out-Null
Write-Host "Disabled Microsoft Store search suggestions for user $userName"
}

View File

@@ -0,0 +1,16 @@
# Enables a Windows optional feature and pipes its output to the console
function EnableWindowsFeature {
param (
[string]$FeatureName
)
$result = Invoke-NonBlocking -ScriptBlock {
param($name)
Enable-WindowsOptionalFeature -Online -FeatureName $name -All -NoRestart
} -ArgumentList $FeatureName
$dismResult = @($result) | Where-Object { $_ -is [Microsoft.Dism.Commands.ImageObject] }
if ($dismResult) {
Write-Host ($dismResult | Out-String).Trim()
}
}

View File

@@ -0,0 +1,69 @@
# Import & execute regfile
function ImportRegistryFile {
param (
$message,
$path
)
Write-Host $message
# Validate that the regfile exists in both locations
if (-not (Test-Path "$script:RegfilesPath\$path") -or -not (Test-Path "$script:RegfilesPath\Sysprep\$path")) {
Write-Host "Error: Unable to find registry file: $path" -ForegroundColor Red
Write-Host ""
return
}
# Reset exit code before running reg.exe for reliable success detection
$global:LASTEXITCODE = 0
if ($script:Params.ContainsKey("Sysprep") -or $script:Params.ContainsKey("User")) {
# Sysprep targets Default user, User targets the specified user
$hiveDatPath = if ($script:Params.ContainsKey("Sysprep")) {
GetUserDirectory -userName "Default" -fileName "NTUSER.DAT"
} else {
GetUserDirectory -userName $script:Params.Item("User") -fileName "NTUSER.DAT"
}
$regResult = Invoke-NonBlocking -ScriptBlock {
param($datPath, $regFilePath)
$global:LASTEXITCODE = 0
reg load "HKU\Default" $datPath | Out-Null
$output = reg import $regFilePath 2>&1
$code = $LASTEXITCODE
reg unload "HKU\Default" | Out-Null
return @{ Output = $output; ExitCode = $code }
} -ArgumentList @($hiveDatPath, "$script:RegfilesPath\Sysprep\$path")
}
else {
$regResult = Invoke-NonBlocking -ScriptBlock {
param($regFilePath)
$global:LASTEXITCODE = 0
$output = reg import $regFilePath 2>&1
return @{ Output = $output; ExitCode = $LASTEXITCODE }
} -ArgumentList "$script:RegfilesPath\$path"
}
$regOutput = $regResult.Output
$hasSuccess = $regResult.ExitCode -eq 0
if ($regOutput) {
foreach ($line in $regOutput) {
$lineText = if ($line -is [System.Management.Automation.ErrorRecord]) { $line.Exception.Message } else { $line.ToString() }
if ($lineText -and $lineText.Length -gt 0) {
if ($hasSuccess) {
Write-Host $lineText
}
else {
Write-Host $lineText -ForegroundColor Red
}
}
}
}
if (-not $hasSuccess) {
Write-Host "Failed importing registry file: $path" -ForegroundColor Red
}
Write-Host ""
}

View File

@@ -0,0 +1,83 @@
# Replace the startmenu for all users, when using the default startmenuTemplate this clears all pinned apps
# Credit: https://lazyadmin.nl/win-11/customize-windows-11-start-menu-layout/
function ReplaceStartMenuForAllUsers {
param (
$startMenuTemplate = "$script:AssetsPath/Start/start2.bin"
)
Write-Host "> Removing all pinned apps from the start menu for all users..."
# Check if template bin file exists
if (-not (Test-Path $startMenuTemplate)) {
Write-Host "Error: Unable to clear start menu, start2.bin file missing from script folder" -ForegroundColor Red
Write-Host ""
return
}
# Get path to start menu file for all users
$userPathString = GetUserDirectory -userName "*" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState"
$usersStartMenuPaths = get-childitem -path $userPathString
# Go through all users and replace the start menu file
ForEach ($startMenuPath in $usersStartMenuPaths) {
ReplaceStartMenu $startMenuTemplate "$($startMenuPath.Fullname)\start2.bin"
}
# Also replace the start menu file for the default user profile
$defaultStartMenuPath = GetUserDirectory -userName "Default" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState" -exitIfPathNotFound $false
# Create folder if it doesn't exist
if (-not (Test-Path $defaultStartMenuPath)) {
new-item $defaultStartMenuPath -ItemType Directory -Force | Out-Null
Write-Host "Created LocalState folder for default user profile"
}
# Copy template to default profile
Copy-Item -Path $startMenuTemplate -Destination $defaultStartMenuPath -Force
Write-Host "Replaced start menu for the default user profile"
Write-Host ""
}
# Replace the startmenu for all users, when using the default startmenuTemplate this clears all pinned apps
# Credit: https://lazyadmin.nl/win-11/customize-windows-11-start-menu-layout/
function ReplaceStartMenu {
param (
$startMenuTemplate = "$script:AssetsPath/Start/start2.bin",
$startMenuBinFile = "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin"
)
# Change path to correct user if a user was specified
if ($script:Params.ContainsKey("User")) {
$startMenuBinFile = GetUserDirectory -userName "$(GetUserName)" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin" -exitIfPathNotFound $false
}
# Check if template bin file exists
if (-not (Test-Path $startMenuTemplate)) {
Write-Host "Error: Unable to replace start menu, template file not found" -ForegroundColor Red
return
}
if ([IO.Path]::GetExtension($startMenuTemplate) -ne ".bin" ) {
Write-Host "Error: Unable to replace start menu, template file is not a valid .bin file" -ForegroundColor Red
return
}
$userName = [regex]::Match($startMenuBinFile, '(?:Users\\)([^\\]+)(?:\\AppData)').Groups[1].Value
$backupBinFile = $startMenuBinFile + ".bak"
if (Test-Path $startMenuBinFile) {
# Backup current start menu file
Move-Item -Path $startMenuBinFile -Destination $backupBinFile -Force
}
else {
Write-Host "Unable to find original start2.bin file for user $userName, no backup was created for this user" -ForegroundColor Yellow
New-Item -ItemType File -Path $startMenuBinFile -Force
}
# Copy template file
Copy-Item -Path $startMenuTemplate -Destination $startMenuBinFile -Force
Write-Host "Replaced start menu for user $userName"
}

View File

@@ -0,0 +1,26 @@
# Restart the Windows Explorer process
function RestartExplorer {
Write-Host "> Attempting to restart the Windows Explorer process to apply all changes..."
if ($script:Params.ContainsKey("Sysprep") -or $script:Params.ContainsKey("User") -or $script:Params.ContainsKey("NoRestartExplorer")) {
Write-Host "Explorer process restart was skipped, please manually reboot your PC to apply all changes" -ForegroundColor Yellow
return
}
foreach ($paramKey in $script:Params.Keys) {
if ($script:Features.ContainsKey($paramKey) -and $script:Features[$paramKey].RequiresReboot -eq $true) {
$feature = $script:Features[$paramKey]
Write-Host "Warning: '$($feature.Action) $($feature.Label)' requires a reboot to take full effect" -ForegroundColor Yellow
}
}
# Only restart if the powershell process matches the OS architecture.
# Restarting explorer from a 32bit PowerShell window will fail on a 64bit OS
if ([Environment]::Is64BitProcess -eq [Environment]::Is64BitOperatingSystem) {
Write-Host "Restarting the Windows Explorer process... (This may cause your screen to flicker)"
Stop-Process -processName: Explorer -Force
}
else {
Write-Host "Unable to restart Windows Explorer process, please manually reboot your PC to apply all changes" -ForegroundColor Yellow
}
}

View File

@@ -1419,6 +1419,15 @@ function Show-MainWindow {
UpdateNavigationButtons UpdateNavigationButtons
}) })
# Add event handler for tab changes
$tabControl.Add_SelectionChanged({
# Regenerate overview when switching to Overview tab
if ($tabControl.SelectedIndex -eq ($tabControl.Items.Count - 2)) {
GenerateOverview
}
UpdateNavigationButtons
})
# Handle Load Defaults button # Handle Load Defaults button
$loadDefaultsBtn = $window.FindName('LoadDefaultsBtn') $loadDefaultsBtn = $window.FindName('LoadDefaultsBtn')
$loadDefaultsBtn.Add_Click({ $loadDefaultsBtn.Add_Click({

View File

@@ -33,6 +33,7 @@ param (
[switch]$PreventUpdateAutoReboot, [switch]$PreventUpdateAutoReboot,
[switch]$DisableDeliveryOptimization, [switch]$DisableDeliveryOptimization,
[switch]$DisableBing, [switch]$DisableBing,
[switch]$DisableStoreSearchSuggestions,
[switch]$DisableDesktopSpotlight, [switch]$DisableDesktopSpotlight,
[switch]$DisableLockscreenTips, [switch]$DisableLockscreenTips,
[switch]$DisableSuggestions, [switch]$DisableSuggestions,

526
Win11Debloat.ps1 Normal file → Executable file
View File

@@ -35,6 +35,7 @@ param (
[switch]$PreventUpdateAutoReboot, [switch]$PreventUpdateAutoReboot,
[switch]$DisableDeliveryOptimization, [switch]$DisableDeliveryOptimization,
[switch]$DisableBing, [switch]$DisableBing,
[switch]$DisableStoreSearchSuggestions,
[switch]$DisableSearchHighlights, [switch]$DisableSearchHighlights,
[switch]$DisableDesktopSpotlight, [switch]$DisableDesktopSpotlight,
[switch]$DisableLockscreenTips, [switch]$DisableLockscreenTips,
@@ -217,7 +218,12 @@ if (-not $script:WingetInstalled -and -not $Silent) {
# # # #
################################################################################################################## ##################################################################################################################
# Load app removal functions
. "$PSScriptRoot/Scripts/AppRemoval/ForceRemoveEdge.ps1"
. "$PSScriptRoot/Scripts/AppRemoval/RemoveApps.ps1"
# Load CLI functions # Load CLI functions
. "$PSScriptRoot/Scripts/CLI/AwaitKeyToExit.ps1"
. "$PSScriptRoot/Scripts/CLI/ShowCLILastUsedSettings.ps1" . "$PSScriptRoot/Scripts/CLI/ShowCLILastUsedSettings.ps1"
. "$PSScriptRoot/Scripts/CLI/ShowCLIDefaultModeAppRemovalOptions.ps1" . "$PSScriptRoot/Scripts/CLI/ShowCLIDefaultModeAppRemovalOptions.ps1"
. "$PSScriptRoot/Scripts/CLI/ShowCLIDefaultModeOptions.ps1" . "$PSScriptRoot/Scripts/CLI/ShowCLIDefaultModeOptions.ps1"
@@ -226,6 +232,14 @@ if (-not $script:WingetInstalled -and -not $Silent) {
. "$PSScriptRoot/Scripts/CLI/PrintPendingChanges.ps1" . "$PSScriptRoot/Scripts/CLI/PrintPendingChanges.ps1"
. "$PSScriptRoot/Scripts/CLI/PrintHeader.ps1" . "$PSScriptRoot/Scripts/CLI/PrintHeader.ps1"
# Load Feature functions
. "$PSScriptRoot/Scripts/Features/CreateSystemRestorePoint.ps1"
. "$PSScriptRoot/Scripts/Features/DisableStoreSearchSuggestions.ps1"
. "$PSScriptRoot/Scripts/Features/EnableWindowsFeature.ps1"
. "$PSScriptRoot/Scripts/Features/ImportRegistryFile.ps1"
. "$PSScriptRoot/Scripts/Features/ReplaceStartMenu.ps1"
. "$PSScriptRoot/Scripts/Features/RestartExplorer.ps1"
# Load GUI functions # Load GUI functions
. "$PSScriptRoot/Scripts/GUI/GetSystemUsesDarkMode.ps1" . "$PSScriptRoot/Scripts/GUI/GetSystemUsesDarkMode.ps1"
. "$PSScriptRoot/Scripts/GUI/SetWindowThemeResources.ps1" . "$PSScriptRoot/Scripts/GUI/SetWindowThemeResources.ps1"
@@ -480,334 +494,6 @@ function CheckModernStandbySupport {
} }
# Removes apps specified during function call based on the target scope.
function RemoveApps {
param (
$appslist
)
# Determine target from script-level params, defaulting to AllUsers
$targetUser = GetTargetUserForAppRemoval
$appIndex = 0
$appCount = @($appsList).Count
Foreach ($app in $appsList) {
if ($script:CancelRequested) {
return
}
$appIndex++
# Update step name and sub-progress to show which app is being removed (only for bulk removal)
if ($script:ApplySubStepCallback -and $appCount -gt 1) {
& $script:ApplySubStepCallback "Removing apps ($appIndex/$appCount)" $appIndex $appCount
}
Write-Host "Attempting to remove $app..."
# Use WinGet only to remove OneDrive and Edge
if (($app -eq "Microsoft.OneDrive") -or ($app -eq "Microsoft.Edge")) {
if ($script:WingetInstalled -eq $false) {
Write-Host "WinGet is either not installed or is outdated, $app could not be removed" -ForegroundColor Red
continue
}
$appName = $app -replace '\.', '_'
# Uninstall app via WinGet, or create a scheduled task to uninstall it later
if ($script:Params.ContainsKey("User")) {
RegImport "Adding scheduled task to uninstall $app for user $(GetUserName)..." "Uninstall_$($appName).reg"
}
elseif ($script:Params.ContainsKey("Sysprep")) {
RegImport "Adding scheduled task to uninstall $app after for new users..." "Uninstall_$($appName).reg"
}
else {
# Uninstall app via WinGet
$wingetOutput = Invoke-NonBlocking -ScriptBlock {
param($appId)
winget uninstall --accept-source-agreements --disable-interactivity --id $appId
} -ArgumentList $app
If (($app -eq "Microsoft.Edge") -and (Select-String -InputObject $wingetOutput -Pattern "Uninstall failed with exit code")) {
Write-Host "Unable to uninstall Microsoft Edge via WinGet" -ForegroundColor Red
if ($script:GuiWindow) {
$result = Show-MessageBox -Message 'Unable to uninstall Microsoft Edge via WinGet. Would you like to forcefully uninstall it? NOT RECOMMENDED!' -Title 'Force Uninstall Microsoft Edge?' -Button 'YesNo' -Icon 'Warning'
if ($result -eq 'Yes') {
Write-Host ""
ForceRemoveEdge
}
}
elseif ($( Read-Host -Prompt "Would you like to forcefully uninstall Microsoft Edge? NOT RECOMMENDED! (y/n)" ) -eq 'y') {
Write-Host ""
ForceRemoveEdge
}
}
}
continue
}
# Use Remove-AppxPackage to remove all other apps
$appPattern = '*' + $app + '*'
try {
switch ($targetUser) {
"AllUsers" {
# Remove installed app for all existing users, and from OS image
Invoke-NonBlocking -ScriptBlock {
param($pattern)
Get-AppxPackage -Name $pattern -AllUsers | Remove-AppxPackage -AllUsers -ErrorAction Continue
Get-AppxProvisionedPackage -Online | Where-Object { $_.PackageName -like $pattern } | ForEach-Object { Remove-ProvisionedAppxPackage -Online -AllUsers -PackageName $_.PackageName }
} -ArgumentList $appPattern
}
"CurrentUser" {
# Remove installed app for current user only
Invoke-NonBlocking -ScriptBlock {
param($pattern)
Get-AppxPackage -Name $pattern | Remove-AppxPackage -ErrorAction Continue
} -ArgumentList $appPattern
}
default {
# Target is a specific username - remove app for that user only
Invoke-NonBlocking -ScriptBlock {
param($pattern, $user)
$userAccount = New-Object System.Security.Principal.NTAccount($user)
$userSid = $userAccount.Translate([System.Security.Principal.SecurityIdentifier]).Value
Get-AppxPackage -Name $pattern -User $userSid | Remove-AppxPackage -User $userSid -ErrorAction Continue
} -ArgumentList @($appPattern, $targetUser)
}
}
}
catch {
if ($DebugPreference -ne "SilentlyContinue") {
Write-Host "Something went wrong while trying to remove $app" -ForegroundColor Yellow
Write-Host $psitem.Exception.StackTrace -ForegroundColor Gray
}
}
}
Write-Host ""
}
# Forcefully removes Microsoft Edge using its uninstaller
# Credit: Based on work from loadstring1 & ave9858
function ForceRemoveEdge {
Write-Host "> Forcefully uninstalling Microsoft Edge..."
$regView = [Microsoft.Win32.RegistryView]::Registry32
$hklm = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $regView)
$hklm.CreateSubKey('SOFTWARE\Microsoft\EdgeUpdateDev').SetValue('AllowUninstall', '')
# Create stub (This somehow allows uninstalling Edge)
$edgeStub = "$env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe"
New-Item $edgeStub -ItemType Directory | Out-Null
New-Item "$edgeStub\MicrosoftEdge.exe" | Out-Null
# Remove edge
$uninstallRegKey = $hklm.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Microsoft Edge')
if ($null -ne $uninstallRegKey) {
Write-Host "Running uninstaller..."
$uninstallString = $uninstallRegKey.GetValue('UninstallString') + ' --force-uninstall'
Invoke-NonBlocking -ScriptBlock {
param($cmd)
Start-Process cmd.exe "/c $cmd" -WindowStyle Hidden -Wait
} -ArgumentList $uninstallString
Write-Host "Removing leftover files..."
$edgePaths = @(
"$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk",
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\Microsoft Edge.lnk",
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Microsoft Edge.lnk",
"$env:APPDATA\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Tombstones\Microsoft Edge.lnk",
"$env:PUBLIC\Desktop\Microsoft Edge.lnk",
"$env:USERPROFILE\Desktop\Microsoft Edge.lnk",
"$edgeStub"
)
foreach ($path in $edgePaths) {
if (Test-Path -Path $path) {
Remove-Item -Path $path -Force -Recurse -ErrorAction SilentlyContinue
Write-Host " Removed $path" -ForegroundColor DarkGray
}
}
Write-Host "Cleaning up registry..."
# Remove MS Edge from autostart
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "MicrosoftEdgeAutoLaunch_A9F6DCE4ABADF4F51CF45CD7129E3C6C" /f *>$null
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "Microsoft Edge Update" /f *>$null
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run" /v "MicrosoftEdgeAutoLaunch_A9F6DCE4ABADF4F51CF45CD7129E3C6C" /f *>$null
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\StartupApproved\Run" /v "Microsoft Edge Update" /f *>$null
Write-Host "Microsoft Edge was uninstalled"
}
else {
Write-Host "Unable to forcefully uninstall Microsoft Edge, uninstaller could not be found" -ForegroundColor Red
}
}
# Import & execute regfile
function RegImport {
param (
$message,
$path
)
Write-Host $message
# Validate that the regfile exists in both locations
if (-not (Test-Path "$script:RegfilesPath\$path") -or -not (Test-Path "$script:RegfilesPath\Sysprep\$path")) {
Write-Host "Error: Unable to find registry file: $path" -ForegroundColor Red
Write-Host ""
return
}
# Reset exit code before running reg.exe for reliable success detection
$global:LASTEXITCODE = 0
if ($script:Params.ContainsKey("Sysprep") -or $script:Params.ContainsKey("User")) {
# Sysprep targets Default user, User targets the specified user
$hiveDatPath = if ($script:Params.ContainsKey("Sysprep")) {
GetUserDirectory -userName "Default" -fileName "NTUSER.DAT"
} else {
GetUserDirectory -userName $script:Params.Item("User") -fileName "NTUSER.DAT"
}
$regResult = Invoke-NonBlocking -ScriptBlock {
param($datPath, $regFilePath)
$global:LASTEXITCODE = 0
reg load "HKU\Default" $datPath | Out-Null
$output = reg import $regFilePath 2>&1
$code = $LASTEXITCODE
reg unload "HKU\Default" | Out-Null
return @{ Output = $output; ExitCode = $code }
} -ArgumentList @($hiveDatPath, "$script:RegfilesPath\Sysprep\$path")
}
else {
$regResult = Invoke-NonBlocking -ScriptBlock {
param($regFilePath)
$global:LASTEXITCODE = 0
$output = reg import $regFilePath 2>&1
return @{ Output = $output; ExitCode = $LASTEXITCODE }
} -ArgumentList "$script:RegfilesPath\$path"
}
$regOutput = $regResult.Output
$hasSuccess = $regResult.ExitCode -eq 0
if ($regOutput) {
foreach ($line in $regOutput) {
$lineText = if ($line -is [System.Management.Automation.ErrorRecord]) { $line.Exception.Message } else { $line.ToString() }
if ($lineText -and $lineText.Length -gt 0) {
if ($hasSuccess) {
Write-Host $lineText
}
else {
Write-Host $lineText -ForegroundColor Red
}
}
}
}
if (-not $hasSuccess) {
Write-Host "Failed importing registry file: $path" -ForegroundColor Red
}
Write-Host ""
}
# Replace the startmenu for all users, when using the default startmenuTemplate this clears all pinned apps
# Credit: https://lazyadmin.nl/win-11/customize-windows-11-start-menu-layout/
function ReplaceStartMenuForAllUsers {
param (
$startMenuTemplate = "$script:AssetsPath/Start/start2.bin"
)
Write-Host "> Removing all pinned apps from the start menu for all users..."
# Check if template bin file exists
if (-not (Test-Path $startMenuTemplate)) {
Write-Host "Error: Unable to clear start menu, start2.bin file missing from script folder" -ForegroundColor Red
Write-Host ""
return
}
# Get path to start menu file for all users
$userPathString = GetUserDirectory -userName "*" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState"
$usersStartMenuPaths = get-childitem -path $userPathString
# Go through all users and replace the start menu file
ForEach ($startMenuPath in $usersStartMenuPaths) {
ReplaceStartMenu $startMenuTemplate "$($startMenuPath.Fullname)\start2.bin"
}
# Also replace the start menu file for the default user profile
$defaultStartMenuPath = GetUserDirectory -userName "Default" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState" -exitIfPathNotFound $false
# Create folder if it doesn't exist
if (-not (Test-Path $defaultStartMenuPath)) {
new-item $defaultStartMenuPath -ItemType Directory -Force | Out-Null
Write-Host "Created LocalState folder for default user profile"
}
# Copy template to default profile
Copy-Item -Path $startMenuTemplate -Destination $defaultStartMenuPath -Force
Write-Host "Replaced start menu for the default user profile"
Write-Host ""
}
# Replace the startmenu for all users, when using the default startmenuTemplate this clears all pinned apps
# Credit: https://lazyadmin.nl/win-11/customize-windows-11-start-menu-layout/
function ReplaceStartMenu {
param (
$startMenuTemplate = "$script:AssetsPath/Start/start2.bin",
$startMenuBinFile = "$env:LOCALAPPDATA\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin"
)
# Change path to correct user if a user was specified
if ($script:Params.ContainsKey("User")) {
$startMenuBinFile = GetUserDirectory -userName "$(GetUserName)" -fileName "AppData\Local\Packages\Microsoft.Windows.StartMenuExperienceHost_cw5n1h2txyewy\LocalState\start2.bin" -exitIfPathNotFound $false
}
# Check if template bin file exists
if (-not (Test-Path $startMenuTemplate)) {
Write-Host "Error: Unable to replace start menu, template file not found" -ForegroundColor Red
return
}
if ([IO.Path]::GetExtension($startMenuTemplate) -ne ".bin" ) {
Write-Host "Error: Unable to replace start menu, template file is not a valid .bin file" -ForegroundColor Red
return
}
$userName = [regex]::Match($startMenuBinFile, '(?:Users\\)([^\\]+)(?:\\AppData)').Groups[1].Value
$backupBinFile = $startMenuBinFile + ".bak"
if (Test-Path $startMenuBinFile) {
# Backup current start menu file
Move-Item -Path $startMenuBinFile -Destination $backupBinFile -Force
}
else {
Write-Host "Unable to find original start2.bin file for user $userName, no backup was created for this user" -ForegroundColor Yellow
New-Item -ItemType File -Path $startMenuBinFile -Force
}
# Copy template file
Copy-Item -Path $startMenuTemplate -Destination $startMenuBinFile -Force
Write-Host "Replaced start menu for user $userName"
}
# Generates a list of apps to remove based on the Apps parameter # Generates a list of apps to remove based on the Apps parameter
function GenerateAppsList { function GenerateAppsList {
if (-not ($script:Params["Apps"] -and $script:Params["Apps"] -is [string])) { if (-not ($script:Params["Apps"] -and $script:Params["Apps"] -is [string])) {
@@ -843,11 +529,11 @@ function ExecuteParameter {
$feature = $script:Features[$paramKey] $feature = $script:Features[$paramKey]
} }
# If feature has RegistryKey and ApplyText, use dynamic RegImport # If feature has RegistryKey and ApplyText, use dynamic ImportRegistryFile
if ($feature -and $feature.RegistryKey -and $feature.ApplyText) { if ($feature -and $feature.RegistryKey -and $feature.ApplyText) {
RegImport "> $($feature.ApplyText)" $feature.RegistryKey ImportRegistryFile "> $($feature.ApplyText)" $feature.RegistryKey
# Handle special cases that have additional logic after RegImport # Handle special cases that have additional logic after ImportRegistryFile
switch ($paramKey) { switch ($paramKey) {
'DisableBing' { 'DisableBing' {
# Also remove the app package for Bing search # Also remove the app package for Bing search
@@ -950,6 +636,19 @@ function ExecuteParameter {
ReplaceStartMenuForAllUsers $script:Params.Item("ReplaceStartAllUsers") ReplaceStartMenuForAllUsers $script:Params.Item("ReplaceStartAllUsers")
return return
} }
'DisableStoreSearchSuggestions' {
if ($script:Params.ContainsKey("Sysprep")) {
Write-Host "> Disabling Microsoft Store search suggestions in the start menu for all users..."
DisableStoreSearchSuggestionsForAllUsers
Write-Host ""
return
}
Write-Host "> Disabling Microsoft Store search suggestions for user $(GetUserName)..."
DisableStoreSearchSuggestions
Write-Host ""
return
}
} }
} }
@@ -1015,171 +714,6 @@ function ExecuteAllChanges {
} }
function CreateSystemRestorePoint {
$SysRestore = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRestore" -Name "RPSessionInterval"
$failed = $false
if ($SysRestore.RPSessionInterval -eq 0) {
# In GUI mode, skip the prompt and just try to enable it
if ($script:GuiWindow -or $Silent -or $( Read-Host -Prompt "System restore is disabled, would you like to enable it and create a restore point? (y/n)") -eq 'y') {
$enableSystemRestoreJob = Start-Job {
try {
Enable-ComputerRestore -Drive "$env:SystemDrive"
}
catch {
return "Error: Failed to enable System Restore: $_"
}
return $null
}
$enableSystemRestoreJobDone = $enableSystemRestoreJob | Wait-Job -TimeOut 20
if (-not $enableSystemRestoreJobDone) {
Remove-Job -Job $enableSystemRestoreJob -Force -ErrorAction SilentlyContinue
Write-Host "Error: Failed to enable system restore and create restore point, operation timed out" -ForegroundColor Red
$failed = $true
}
else {
$result = Receive-Job $enableSystemRestoreJob
Remove-Job -Job $enableSystemRestoreJob -ErrorAction SilentlyContinue
if ($result) {
Write-Host $result -ForegroundColor Red
$failed = $true
}
}
}
else {
Write-Host ""
$failed = $true
}
}
if (-not $failed) {
$createRestorePointJob = Start-Job {
# Find existing restore points that are less than 24 hours old
try {
$recentRestorePoints = Get-ComputerRestorePoint | Where-Object { (Get-Date) - [System.Management.ManagementDateTimeConverter]::ToDateTime($_.CreationTime) -le (New-TimeSpan -Hours 24) }
}
catch {
return @{ Success = $false; Message = "Error: Unable to retrieve existing restore points: $_" }
}
if ($recentRestorePoints.Count -eq 0) {
try {
Checkpoint-Computer -Description "Restore point created by Win11Debloat" -RestorePointType "MODIFY_SETTINGS"
return @{ Success = $true; Message = "System restore point created successfully" }
}
catch {
return @{ Success = $false; Message = "Error: Unable to create restore point: $_" }
}
}
else {
return @{ Success = $true; Message = "A recent restore point already exists, no new restore point was created" }
}
}
$createRestorePointJobDone = $createRestorePointJob | Wait-Job -TimeOut 20
if (-not $createRestorePointJobDone) {
Remove-Job -Job $createRestorePointJob -Force -ErrorAction SilentlyContinue
Write-Host "Error: Failed to create system restore point, operation timed out" -ForegroundColor Red
$failed = $true
}
else {
$result = Receive-Job $createRestorePointJob
Remove-Job -Job $createRestorePointJob -ErrorAction SilentlyContinue
if ($result.Success) {
Write-Host $result.Message
}
else {
Write-Host $result.Message -ForegroundColor Red
$failed = $true
}
}
}
# Ensure that the user is aware if creating a restore point failed, and give them the option to continue without a restore point or cancel the script
if ($failed) {
if ($script:GuiWindow) {
$result = Show-MessageBox "Failed to create a system restore point. Do you want to continue without a restore point?" "Restore Point Creation Failed" "YesNo" "Warning"
if ($result -ne "Yes") {
$script:CancelRequested = $true
return
}
}
elseif (-not $Silent) {
Write-Host "Failed to create a system restore point. Do you want to continue without a restore point? (y/n)" -ForegroundColor Yellow
if ($( Read-Host ) -ne 'y') {
$script:CancelRequested = $true
return
}
}
Write-Host "Warning: Continuing without restore point" -ForegroundColor Yellow
}
}
# Enables a Windows optional feature and pipes its output to the console
function EnableWindowsFeature {
param (
[string]$FeatureName
)
$result = Invoke-NonBlocking -ScriptBlock {
param($name)
Enable-WindowsOptionalFeature -Online -FeatureName $name -All -NoRestart
} -ArgumentList $FeatureName
$dismResult = @($result) | Where-Object { $_ -is [Microsoft.Dism.Commands.ImageObject] }
if ($dismResult) {
Write-Host ($dismResult | Out-String).Trim()
}
}
# Restart the Windows Explorer process
function RestartExplorer {
Write-Host "> Attempting to restart the Windows Explorer process to apply all changes..."
if ($script:Params.ContainsKey("Sysprep") -or $script:Params.ContainsKey("User") -or $script:Params.ContainsKey("NoRestartExplorer")) {
Write-Host "Explorer process restart was skipped, please manually reboot your PC to apply all changes" -ForegroundColor Yellow
return
}
foreach ($paramKey in $script:Params.Keys) {
if ($script:Features.ContainsKey($paramKey) -and $script:Features[$paramKey].RequiresReboot -eq $true) {
$feature = $script:Features[$paramKey]
Write-Host "Warning: '$($feature.Action) $($feature.Label)' requires a reboot to take full effect" -ForegroundColor Yellow
}
}
# Only restart if the powershell process matches the OS architecture.
# Restarting explorer from a 32bit PowerShell window will fail on a 64bit OS
if ([Environment]::Is64BitProcess -eq [Environment]::Is64BitOperatingSystem) {
Write-Host "Restarting the Windows Explorer process... (This may cause your screen to flicker)"
Stop-Process -processName: Explorer -Force
}
else {
Write-Host "Unable to restart Windows Explorer process, please manually reboot your PC to apply all changes" -ForegroundColor Yellow
}
}
function AwaitKeyToExit {
# Suppress prompt if Silent parameter was passed
if (-not $Silent) {
Write-Output ""
Write-Output "Press any key to exit..."
$null = [System.Console]::ReadKey()
}
Stop-Transcript
Exit
}
################################################################################################################## ##################################################################################################################
# # # #