2026-03-15 22:58:06 +01:00
|
|
|
# Executes a single parameter/feature based on its key
|
|
|
|
|
# Parameters:
|
|
|
|
|
# $paramKey - The parameter name to execute
|
|
|
|
|
function ExecuteParameter {
|
|
|
|
|
param (
|
|
|
|
|
[string]$paramKey
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-23 20:47:32 +01:00
|
|
|
# Check if this feature exists in Features.json
|
2026-03-15 22:58:06 +01:00
|
|
|
$feature = $null
|
|
|
|
|
if ($script:Features.ContainsKey($paramKey)) {
|
|
|
|
|
$feature = $script:Features[$paramKey]
|
|
|
|
|
}
|
2026-03-22 22:07:51 +01:00
|
|
|
|
2026-03-23 20:47:32 +01:00
|
|
|
# Check if undo is requested and if this feature supports undo
|
2026-03-22 22:07:51 +01:00
|
|
|
$undoChanges = $script:Params.ContainsKey('Undo')
|
|
|
|
|
|
2026-03-23 20:47:32 +01:00
|
|
|
if ($undoChanges) {
|
|
|
|
|
$undoFeature = GetUndoFeatureForParam -paramKey $paramKey
|
2026-03-22 22:07:51 +01:00
|
|
|
|
2026-03-23 20:47:32 +01:00
|
|
|
if ($null -eq $undoFeature) {
|
|
|
|
|
# This parameter doesn't support undo, so skip it
|
|
|
|
|
return
|
2026-03-22 22:07:51 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-23 20:47:32 +01:00
|
|
|
$undoRegFile = $undoFeature.RegistryUndoKey
|
|
|
|
|
$undoFolderPath = Join-Path $script:RegfilesPath (Join-Path 'Undo' $undoRegFile)
|
|
|
|
|
|
2026-03-22 22:07:51 +01:00
|
|
|
if (Test-Path $undoFolderPath) {
|
|
|
|
|
$undoRegFile = Join-Path 'Undo' $undoRegFile
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ImportRegistryFile "> $($undoFeature.UndoAction) $($undoFeature.Label)" $undoRegFile
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-03-15 22:58:06 +01:00
|
|
|
|
2026-03-23 20:47:32 +01:00
|
|
|
# If feature has RegistryKey and ApplyText, dynamically import the registry file for this feature
|
2026-03-15 22:58:06 +01:00
|
|
|
if ($feature -and $feature.RegistryKey -and $feature.ApplyText) {
|
|
|
|
|
ImportRegistryFile "> $($feature.ApplyText)" $feature.RegistryKey
|
|
|
|
|
|
|
|
|
|
# Handle special cases that have additional logic after ImportRegistryFile
|
|
|
|
|
switch ($paramKey) {
|
|
|
|
|
'DisableBing' {
|
|
|
|
|
# Also remove the app package for Bing search
|
|
|
|
|
RemoveApps 'Microsoft.BingSearch'
|
|
|
|
|
}
|
|
|
|
|
'DisableCopilot' {
|
|
|
|
|
# Also remove the app package for Copilot
|
|
|
|
|
RemoveApps 'Microsoft.Copilot'
|
|
|
|
|
}
|
|
|
|
|
'DisableWidgets' {
|
|
|
|
|
# Also remove the app package for Widgets
|
|
|
|
|
RemoveApps 'Microsoft.StartExperiencesApp'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Handle features without RegistryKey or with special logic
|
|
|
|
|
switch ($paramKey) {
|
|
|
|
|
'RemoveApps' {
|
|
|
|
|
Write-Host "> Removing selected apps for $(GetFriendlyTargetUserName)..."
|
|
|
|
|
$appsList = GenerateAppsList
|
|
|
|
|
|
|
|
|
|
if ($appsList.Count -eq 0) {
|
|
|
|
|
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
|
|
|
|
|
Write-Host ""
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Write-Host "$($appsList.Count) apps selected for removal"
|
|
|
|
|
RemoveApps $appsList
|
|
|
|
|
}
|
|
|
|
|
'RemoveAppsCustom' {
|
|
|
|
|
Write-Host "> Removing selected apps..."
|
|
|
|
|
$appsList = LoadAppsFromFile $script:CustomAppsListFilePath
|
|
|
|
|
|
|
|
|
|
if ($appsList.Count -eq 0) {
|
|
|
|
|
Write-Host "No valid apps were selected for removal" -ForegroundColor Yellow
|
|
|
|
|
Write-Host ""
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Write-Host "$($appsList.Count) apps selected for removal"
|
|
|
|
|
RemoveApps $appsList
|
|
|
|
|
}
|
|
|
|
|
'RemoveCommApps' {
|
|
|
|
|
$appsList = 'Microsoft.windowscommunicationsapps', 'Microsoft.People'
|
|
|
|
|
Write-Host "> Removing Mail, Calendar and People apps..."
|
|
|
|
|
RemoveApps $appsList
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
'RemoveW11Outlook' {
|
|
|
|
|
$appsList = 'Microsoft.OutlookForWindows'
|
|
|
|
|
Write-Host "> Removing new Outlook for Windows app..."
|
|
|
|
|
RemoveApps $appsList
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
'RemoveGamingApps' {
|
|
|
|
|
$appsList = 'Microsoft.GamingApp', 'Microsoft.XboxGameOverlay', 'Microsoft.XboxGamingOverlay'
|
|
|
|
|
Write-Host "> Removing gaming related apps..."
|
|
|
|
|
RemoveApps $appsList
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
'RemoveHPApps' {
|
|
|
|
|
$appsList = 'AD2F1837.HPAIExperienceCenter', 'AD2F1837.HPJumpStarts', 'AD2F1837.HPPCHardwareDiagnosticsWindows', 'AD2F1837.HPPowerManager', 'AD2F1837.HPPrivacySettings', 'AD2F1837.HPSupportAssistant', 'AD2F1837.HPSureShieldAI', 'AD2F1837.HPSystemInformation', 'AD2F1837.HPQuickDrop', 'AD2F1837.HPWorkWell', 'AD2F1837.myHP', 'AD2F1837.HPDesktopSupportUtilities', 'AD2F1837.HPQuickTouch', 'AD2F1837.HPEasyClean', 'AD2F1837.HPConnectedMusic', 'AD2F1837.HPFileViewer', 'AD2F1837.HPRegistration', 'AD2F1837.HPWelcome', 'AD2F1837.HPConnectedPhotopoweredbySnapfish', 'AD2F1837.HPPrinterControl'
|
|
|
|
|
Write-Host "> Removing HP apps..."
|
|
|
|
|
RemoveApps $appsList
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
"EnableWindowsSandbox" {
|
|
|
|
|
Write-Host "> Enabling Windows Sandbox..."
|
|
|
|
|
EnableWindowsFeature "Containers-DisposableClientVM"
|
|
|
|
|
Write-Host ""
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
"EnableWindowsSubsystemForLinux" {
|
|
|
|
|
Write-Host "> Enabling Windows Subsystem for Linux..."
|
|
|
|
|
EnableWindowsFeature "VirtualMachinePlatform"
|
|
|
|
|
EnableWindowsFeature "Microsoft-Windows-Subsystem-Linux"
|
|
|
|
|
Write-Host ""
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
'ClearStart' {
|
|
|
|
|
Write-Host "> Removing all pinned apps from the start menu for user $(GetUserName)..."
|
|
|
|
|
ReplaceStartMenu
|
|
|
|
|
Write-Host ""
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
'ReplaceStart' {
|
|
|
|
|
Write-Host "> Replacing the start menu for user $(GetUserName)..."
|
|
|
|
|
ReplaceStartMenu $script:Params.Item("ReplaceStart")
|
|
|
|
|
Write-Host ""
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
'ClearStartAllUsers' {
|
|
|
|
|
ReplaceStartMenuForAllUsers
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
'ReplaceStartAllUsers' {
|
|
|
|
|
ReplaceStartMenuForAllUsers $script:Params.Item("ReplaceStartAllUsers")
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Executes all selected parameters/features
|
|
|
|
|
function ExecuteAllChanges {
|
|
|
|
|
# Build list of actionable parameters (skip control params and data-only params)
|
2026-03-22 22:07:51 +01:00
|
|
|
$undoChanges = $script:Params.ContainsKey('Undo')
|
2026-03-15 22:58:06 +01:00
|
|
|
$actionableKeys = @()
|
2026-03-22 22:07:51 +01:00
|
|
|
$paramsToRemove = @()
|
2026-03-15 22:58:06 +01:00
|
|
|
foreach ($paramKey in $script:Params.Keys) {
|
|
|
|
|
if ($script:ControlParams -contains $paramKey) { continue }
|
|
|
|
|
if ($paramKey -eq 'Apps') { continue }
|
|
|
|
|
if ($paramKey -eq 'CreateRestorePoint') { continue }
|
2026-03-22 22:07:51 +01:00
|
|
|
|
|
|
|
|
if ($undoChanges) {
|
|
|
|
|
$undoFeature = GetUndoFeatureForParam -paramKey $paramKey
|
|
|
|
|
if (-not $undoFeature) {
|
|
|
|
|
$paramsToRemove += $paramKey
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-15 22:58:06 +01:00
|
|
|
$actionableKeys += $paramKey
|
|
|
|
|
}
|
2026-03-22 22:07:51 +01:00
|
|
|
|
|
|
|
|
if ($undoChanges -and $paramsToRemove.Count -gt 0) {
|
|
|
|
|
foreach ($paramKey in ($paramsToRemove | Sort-Object -Unique)) {
|
|
|
|
|
if ($script:Params.ContainsKey($paramKey)) {
|
|
|
|
|
$null = $script:Params.Remove($paramKey)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($undoChanges -and $actionableKeys.Count -eq 0) {
|
2026-03-23 20:47:32 +01:00
|
|
|
throw "Undo was requested but none of the selected parameters support undo. No changes were reverted."
|
2026-03-22 22:07:51 +01:00
|
|
|
}
|
2026-03-15 22:58:06 +01:00
|
|
|
|
|
|
|
|
$totalSteps = $actionableKeys.Count
|
|
|
|
|
if ($script:Params.ContainsKey("CreateRestorePoint")) { $totalSteps++ }
|
|
|
|
|
$currentStep = 0
|
|
|
|
|
|
|
|
|
|
# Create restore point if requested (CLI only - GUI handles this separately)
|
|
|
|
|
if ($script:Params.ContainsKey("CreateRestorePoint")) {
|
|
|
|
|
$currentStep++
|
|
|
|
|
if ($script:ApplyProgressCallback) {
|
|
|
|
|
& $script:ApplyProgressCallback $currentStep $totalSteps "Creating system restore point"
|
|
|
|
|
}
|
|
|
|
|
Write-Host "> Attempting to create a system restore point..."
|
|
|
|
|
CreateSystemRestorePoint
|
|
|
|
|
Write-Host ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Execute all parameters
|
|
|
|
|
foreach ($paramKey in $actionableKeys) {
|
|
|
|
|
if ($script:CancelRequested) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$currentStep++
|
|
|
|
|
|
|
|
|
|
# Get friendly name for the step
|
|
|
|
|
$stepName = $paramKey
|
|
|
|
|
if ($script:Features.ContainsKey($paramKey)) {
|
|
|
|
|
$feature = $script:Features[$paramKey]
|
2026-03-22 22:07:51 +01:00
|
|
|
if ($undoChanges -and $feature.UndoAction) {
|
|
|
|
|
$stepName = "$($feature.UndoAction) $($feature.Label)"
|
|
|
|
|
}
|
|
|
|
|
elseif ($feature.ApplyText) {
|
2026-03-15 22:58:06 +01:00
|
|
|
# Prefer explicit ApplyText when provided
|
|
|
|
|
$stepName = $feature.ApplyText
|
|
|
|
|
} elseif ($feature.Label) {
|
|
|
|
|
# Fallback: construct a name from Action and Label, or just Label
|
|
|
|
|
if ($feature.Action) {
|
|
|
|
|
$stepName = "$($feature.Action) $($feature.Label)"
|
|
|
|
|
} else {
|
|
|
|
|
$stepName = $feature.Label
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($script:ApplyProgressCallback) {
|
|
|
|
|
& $script:ApplyProgressCallback $currentStep $totalSteps $stepName
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExecuteParameter -paramKey $paramKey
|
|
|
|
|
}
|
|
|
|
|
}
|