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

@@ -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
})
# 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
$loadDefaultsBtn = $window.FindName('LoadDefaultsBtn')
$loadDefaultsBtn.Add_Click({

View File

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