fix(tweaks): skip missing services instead of aborting the run (#5140)

Invoke-WinUtilTweaks caught a missing service with [System.ServiceProcess.ServiceNotFoundException], a type that does not exist in .NET. PowerShell could not resolve the catch type, so the missing-service case aborted the whole tweaks job rather than warning.

Catch on the error ID the way Set-WinUtilService already does: an absent service warns and logs, and any unrelated lookup failure is rethrown. The Tweaks guide documents the skip.
This commit is contained in:
Omar
2026-10-07 09:43:22 -05:00
committed by GitHub
parent 9c87c02fdb
commit 07ccd8e2e7
3 changed files with 73 additions and 3 deletions
+2
View File
@@ -29,6 +29,8 @@ Use the quick-selection buttons at the top of the Tweaks tab to speed up setup:
To see what each preset includes, view [preset.json](https://github.com/ChrisTitusTech/winutil/blob/main/config/preset.json). To see what each preset includes, view [preset.json](https://github.com/ChrisTitusTech/winutil/blob/main/config/preset.json).
::: :::
When a listed service does not exist, WinUtil logs a warning and skips it. The remaining services and tweaks still run.
:::caution :::caution
Some tweaks take effect immediately, while others may require Explorer to restart, a sign-out, or a full reboot. Some tweaks take effect immediately, while others may require Explorer to restart, a sign-out, or a full reboot.
::: :::
+10 -3
View File
@@ -48,14 +48,21 @@ function Invoke-WinUtilTweaks {
# The check for !($undo) is required, without it the script will throw an error for accessing unavailable member, which's the 'OriginalService' Property # The check for !($undo) is required, without it the script will throw an error for accessing unavailable member, which's the 'OriginalService' Property
if ($KeepServiceStartup -AND !($undo)) { if ($KeepServiceStartup -AND !($undo)) {
$serviceName = $psitem.Name
try { try {
# Check if the service exists # Check if the service exists
$service = Get-Service -Name $psitem.Name -ErrorAction Stop $service = Get-Service -Name $serviceName -ErrorAction Stop
if(!($service.StartType.ToString() -eq $psitem.$($values.OriginalService))) { if(!($service.StartType.ToString() -eq $psitem.$($values.OriginalService))) {
$changeservice = $false $changeservice = $false
} }
} catch [System.ServiceProcess.ServiceNotFoundException] { } catch {
Write-Warning "Service $($psitem.Name) was not found." if ($_.FullyQualifiedErrorId -like "NoServiceFoundForGivenName,*") {
$changeservice = $false
Write-Warning "Service $serviceName was not found."
Write-WinUtilLog -Level "WARN" -Component "Service" -Message "Service $serviceName was not found."
} else {
throw
}
} }
} }
+61
View File
@@ -177,6 +177,67 @@ Describe "Invoke-WinUtilTweaks" {
$Name -eq "DiagTrack" -and $StartupType -eq "Disabled" $Name -eq "DiagTrack" -and $StartupType -eq "Disabled"
} }
} }
It "skips a missing service and applies the remaining services and tweaks" {
$script:sync.configs.tweaks.WPFTweaksExample.service = @(
[pscustomobject]@{
Name = "CscService"
StartupType = "Disabled"
OriginalType = "Manual"
}
) + $script:sync.configs.tweaks.WPFTweaksExample.service
Mock Get-Service {
$exception = [Microsoft.PowerShell.Commands.ServiceCommandException]::new("Cannot find any service with service name '$Name'.")
$errorRecord = [System.Management.Automation.ErrorRecord]::new(
$exception,
"NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand",
[System.Management.Automation.ErrorCategory]::ObjectNotFound,
$Name
)
throw $errorRecord
} -ParameterFilter { $Name -eq "CscService" -and $ErrorAction -eq "Stop" }
foreach ($tweak in @("WPFTweaksExample", "WPFTweaksServiceOnly")) {
Invoke-WinUtilTweaks -CheckBox $tweak
}
Should -Invoke -CommandName Write-Warning -Times 1 -Exactly -ParameterFilter {
$Message -eq "Service CscService was not found."
}
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
$Level -eq "WARN" -and $Component -eq "Service" -and $Message -eq "Service CscService was not found."
}
Should -Invoke -CommandName Set-WinUtilService -Times 0 -Exactly -ParameterFilter {
$Name -eq "CscService"
}
Should -Invoke -CommandName Set-WinUtilService -Times 2 -Exactly -ParameterFilter {
$Name -eq "DiagTrack" -and $StartupType -eq "Disabled"
}
Should -Invoke -CommandName Invoke-WinUtilScript -Times 1 -Exactly -ParameterFilter {
$Name -eq "WPFTweaksExample"
}
}
It "rethrows service lookup errors that do not identify a missing service" {
Mock Get-Service {
$exception = [Microsoft.PowerShell.Commands.ServiceCommandException]::new("Service lookup failed.")
$errorRecord = [System.Management.Automation.ErrorRecord]::new(
$exception,
"ServiceLookupFailed",
[System.Management.Automation.ErrorCategory]::OpenError,
$Name
)
throw $errorRecord
}
{ Invoke-WinUtilTweaks -CheckBox "WPFTweaksExample" } | Should -Throw -ExpectedMessage "*Service lookup failed.*"
Should -Invoke -CommandName Set-WinUtilService -Times 0 -Exactly
Should -Invoke -CommandName Set-WinUtilRegistry -Times 0 -Exactly
Should -Invoke -CommandName Invoke-WinUtilScript -Times 0 -Exactly
Should -Invoke -CommandName Write-Warning -Times 0 -Exactly
}
} }
Describe "Invoke-WinUtilTweaks completion status" { Describe "Invoke-WinUtilTweaks completion status" {