All checks were successful
release / build-and-release (push) Successful in 40s
Add three GUI feature toggles to the bloatware step: - standardBloatware (default on) - the bulk AppX/capability/feature list - removeNewOutlook (default on) - new Outlook for Windows (Microsoft.OutlookForWindows) - removeSnippingTool (default OFF) - Snipping Tool across all three lists Each toggle is independent via Test-RemovalAllowed in 01-bloatware.ps1. Snipping Tool (ScreenSketch + legacy capability/feature) is now kept by default as a common productivity tool, like Calculator. Classic Outlook from M365 is a Win32 app and was never touched; only the bundled new Outlook is. Also fix a latent bug: the Go Config struct had no Bloatware field, so the GUI's runtime-config regeneration silently dropped bloatware.keepPackages. Added the field so the keep-list survives to the script. Docs: SPEC.md, CHANGELOG.md, web/data/descriptions.json, web/spec/index.html. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
234 lines
8.9 KiB
PowerShell
234 lines
8.9 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Removes pre-installed bloatware: AppX packages, Capabilities, and Optional Features.
|
|
|
|
.DESCRIPTION
|
|
Removes Microsoft-bundled apps and features not needed in a business MSP deployment.
|
|
Removal is done for all users (-AllUsers) and from the provisioning store so new
|
|
users do not get them either. Calculator is intentionally kept.
|
|
|
|
.ITEMS
|
|
appx-balicky-odstraneni-pro-vsechny-uziv: Uses Remove-AppxPackage -AllUsers and Remove-AppxProvisionedPackage. The provisioned removal prevents apps from reinstalling for new user profiles. Covers ~35 apps including Cortana, Copilot, Teams personal, Xbox, Skype, News, Weather, Maps.
|
|
zachovano-microsoft-windowscalculator: Calculator is explicitly excluded. Lightweight utility frequently used by technicians and end users. Removing it would require manual reinstall from Store.
|
|
windows-capabilities-fax-ie-openssh-wmp-: Removed via Remove-WindowsCapability: Fax & Scan, Internet Explorer mode, OpenSSH client, Windows Media Player (legacy), WordPad, Handwriting recognition, Steps Recorder, Math Input Panel, Quick Assist.
|
|
windows-optional-features-ps-2-0-mediapl: Disabled via Disable-WindowsOptionalFeature: PowerShell 2.0 (security risk - allows unsigned script execution bypass on older hosts), MediaPlayback, Windows Recall (AI screenshot surveillance), Snipping Tool optional component.
|
|
feature-toggles: Three GUI feature flags gate removal. standardBloatware (default on) covers the bulk list. removeNewOutlook (default on) controls Microsoft.OutlookForWindows; classic Outlook from M365 is a Win32 app and is never touched. removeSnippingTool (default OFF) controls Snipping Tool across all three lists (ScreenSketch app + legacy capability + legacy feature) - kept by default as a common productivity tool, like Calculator.
|
|
#>
|
|
param(
|
|
[string]$ConfigPath,
|
|
[string]$LogFile
|
|
)
|
|
|
|
. "$PSScriptRoot\common.ps1"
|
|
$Config = Load-Config $ConfigPath
|
|
|
|
# -----------------------------------------------------------------------
|
|
# Feature flags (see CLAUDE.md features system)
|
|
# standardBloatware - removes the bulk AppX/capability/feature list
|
|
# removeNewOutlook - new Outlook for Windows (Microsoft.OutlookForWindows)
|
|
# removeSnippingTool - Snipping Tool, spans all three lists; default OFF
|
|
# Outlook and Snipping items are gated by their own flag, independent of the
|
|
# standard flag, so each GUI checkbox does exactly what it says.
|
|
# -----------------------------------------------------------------------
|
|
$DoStandard = Get-Feature $Config "bloatware" "standardBloatware" $true
|
|
$DoOutlook = Get-Feature $Config "bloatware" "removeNewOutlook" $true
|
|
$DoSnipping = Get-Feature $Config "bloatware" "removeSnippingTool" $false
|
|
|
|
# Snipping Tool appears as an AppX package (ScreenSketch, the modern app),
|
|
# a legacy capability, and a legacy optional feature.
|
|
$SnippingItems = @(
|
|
"Microsoft.ScreenSketch"
|
|
"Microsoft.Windows.SnippingTool"
|
|
"Microsoft-SnippingTool"
|
|
)
|
|
|
|
function Test-RemovalAllowed {
|
|
param([string]$Name)
|
|
if ($Name -eq "Microsoft.OutlookForWindows") { return $DoOutlook }
|
|
if ($SnippingItems -contains $Name) { return $DoSnipping }
|
|
return $DoStandard
|
|
}
|
|
|
|
# -----------------------------------------------------------------------
|
|
# 1a - AppX packages
|
|
# -----------------------------------------------------------------------
|
|
$AppxToRemove = @(
|
|
"Microsoft.Microsoft3DViewer"
|
|
"Microsoft.BingSearch"
|
|
"Microsoft.WindowsCamera"
|
|
"Clipchamp.Clipchamp"
|
|
"Microsoft.WindowsAlarms"
|
|
"Microsoft.Copilot"
|
|
"Microsoft.549981C3F5F10"
|
|
"Microsoft.Windows.DevHome"
|
|
"MicrosoftCorporationII.MicrosoftFamily"
|
|
"Microsoft.WindowsFeedbackHub"
|
|
"Microsoft.Edge.GameAssist"
|
|
"Microsoft.GetHelp"
|
|
"Microsoft.Getstarted"
|
|
"microsoft.windowscommunicationsapps"
|
|
"Microsoft.WindowsMaps"
|
|
"Microsoft.MixedReality.Portal"
|
|
"Microsoft.BingNews"
|
|
"Microsoft.MicrosoftOfficeHub"
|
|
"Microsoft.Office.OneNote"
|
|
"Microsoft.OutlookForWindows"
|
|
"Microsoft.Paint"
|
|
"Microsoft.MSPaint"
|
|
"Microsoft.People"
|
|
"Microsoft.Windows.Photos"
|
|
"Microsoft.PowerAutomateDesktop"
|
|
"MicrosoftCorporationII.QuickAssist"
|
|
"Microsoft.SkypeApp"
|
|
"Microsoft.ScreenSketch"
|
|
"Microsoft.MicrosoftSolitaireCollection"
|
|
"Microsoft.MicrosoftStickyNotes"
|
|
"MicrosoftTeams"
|
|
"MSTeams"
|
|
"Microsoft.Todos"
|
|
"Microsoft.WindowsSoundRecorder"
|
|
"Microsoft.Wallet"
|
|
"Microsoft.BingWeather"
|
|
"Microsoft.WindowsTerminal"
|
|
"Microsoft.Xbox.TCUI"
|
|
"Microsoft.XboxApp"
|
|
"Microsoft.XboxGameOverlay"
|
|
"Microsoft.XboxGamingOverlay"
|
|
"Microsoft.XboxIdentityProvider"
|
|
"Microsoft.XboxSpeechToTextOverlay"
|
|
"Microsoft.GamingApp"
|
|
"Microsoft.YourPhone"
|
|
"Microsoft.ZuneMusic"
|
|
"Microsoft.ZuneVideo"
|
|
"7EE7776C.LinkedInforWindows"
|
|
)
|
|
|
|
# Packages to always keep
|
|
$KeepPackages = @("Microsoft.WindowsCalculator")
|
|
if ($Config -and $Config.bloatware -and $Config.bloatware.keepPackages) {
|
|
$KeepPackages += $Config.bloatware.keepPackages
|
|
}
|
|
$KeepPackages = $KeepPackages | Select-Object -Unique
|
|
|
|
Write-Log "1a - Removing AppX packages" -Level STEP
|
|
|
|
foreach ($pkg in $AppxToRemove) {
|
|
if ($KeepPackages -contains $pkg) {
|
|
Write-Log " KEEP $pkg" -Level INFO
|
|
continue
|
|
}
|
|
if (-not (Test-RemovalAllowed $pkg)) {
|
|
Write-Log " KEEP (feature off): $pkg" -Level INFO
|
|
continue
|
|
}
|
|
|
|
# Installed packages (current user + all users)
|
|
$installed = Get-AppxPackage -Name $pkg -AllUsers -ErrorAction SilentlyContinue
|
|
if ($installed) {
|
|
try {
|
|
$installed | Remove-AppxPackage -AllUsers -ErrorAction Stop
|
|
Write-Log " Removed AppxPackage: $pkg" -Level OK
|
|
}
|
|
catch {
|
|
Write-Log " Failed to remove AppxPackage $pkg - $_" -Level WARN
|
|
}
|
|
}
|
|
|
|
# Provisioned packages (for new users)
|
|
$provisioned = Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue |
|
|
Where-Object { $_.DisplayName -eq $pkg }
|
|
if ($provisioned) {
|
|
try {
|
|
$provisioned | Remove-AppxProvisionedPackage -Online -ErrorAction Stop | Out-Null
|
|
Write-Log " Removed provisioned: $pkg" -Level OK
|
|
}
|
|
catch {
|
|
Write-Log " Failed to remove provisioned $pkg - $_" -Level WARN
|
|
}
|
|
}
|
|
|
|
if (-not $installed -and -not $provisioned) {
|
|
Write-Log " Not found (already removed): $pkg" -Level INFO
|
|
}
|
|
}
|
|
|
|
# -----------------------------------------------------------------------
|
|
# 1b - Windows Capabilities
|
|
# -----------------------------------------------------------------------
|
|
$CapabilitiesToRemove = @(
|
|
"Print.Fax.Scan"
|
|
"Language.Handwriting"
|
|
"Browser.InternetExplorer"
|
|
"MathRecognizer"
|
|
"OneCoreUAP.OneSync"
|
|
"OpenSSH.Client"
|
|
"Microsoft.Windows.MSPaint"
|
|
"Microsoft.Windows.PowerShell.ISE"
|
|
"App.Support.QuickAssist"
|
|
"Microsoft.Windows.SnippingTool"
|
|
"App.StepsRecorder"
|
|
"Hello.Face"
|
|
"Media.WindowsMediaPlayer"
|
|
"Microsoft.Windows.WordPad"
|
|
)
|
|
|
|
Write-Log "1b - Removing Windows Capabilities" -Level STEP
|
|
|
|
$installedCaps = Get-WindowsCapability -Online -ErrorAction SilentlyContinue
|
|
|
|
foreach ($cap in $CapabilitiesToRemove) {
|
|
if (-not (Test-RemovalAllowed $cap)) {
|
|
Write-Log " KEEP (feature off): $cap" -Level INFO
|
|
continue
|
|
}
|
|
# Match by prefix (e.g. Hello.Face matches Hello.Face.20134.0.0.0)
|
|
$matches = $installedCaps | Where-Object {
|
|
$_.Name -like "$cap*" -and $_.State -eq "Installed"
|
|
}
|
|
if ($matches) {
|
|
foreach ($c in $matches) {
|
|
try {
|
|
Remove-WindowsCapability -Online -Name $c.Name -ErrorAction Stop | Out-Null
|
|
Write-Log " Removed capability: $($c.Name)" -Level OK
|
|
}
|
|
catch {
|
|
Write-Log " Failed to remove capability $($c.Name) - $_" -Level WARN
|
|
}
|
|
}
|
|
} else {
|
|
Write-Log " Not found or not installed: $cap" -Level INFO
|
|
}
|
|
}
|
|
|
|
# -----------------------------------------------------------------------
|
|
# 1c - Windows Optional Features
|
|
# -----------------------------------------------------------------------
|
|
$FeaturesToDisable = @(
|
|
"MediaPlayback"
|
|
"MicrosoftWindowsPowerShellV2Root"
|
|
"Recall"
|
|
"Microsoft-SnippingTool"
|
|
)
|
|
|
|
Write-Log "1c - Disabling Windows Optional Features" -Level STEP
|
|
|
|
foreach ($feat in $FeaturesToDisable) {
|
|
if (-not (Test-RemovalAllowed $feat)) {
|
|
Write-Log " KEEP (feature off): $feat" -Level INFO
|
|
continue
|
|
}
|
|
$feature = Get-WindowsOptionalFeature -Online -FeatureName $feat -ErrorAction SilentlyContinue
|
|
if ($feature -and $feature.State -eq "Enabled") {
|
|
try {
|
|
Disable-WindowsOptionalFeature -Online -FeatureName $feat -NoRestart -ErrorAction Stop | Out-Null
|
|
Write-Log " Disabled feature: $feat" -Level OK
|
|
}
|
|
catch {
|
|
Write-Log " Failed to disable feature $feat - $_" -Level WARN
|
|
}
|
|
} else {
|
|
Write-Log " Not enabled or not found: $feat" -Level INFO
|
|
}
|
|
}
|
|
|
|
Write-Log "Step 1 complete" -Level OK
|