From 27cccd33aa044846c20657c43b7de0aa4ae440b2 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Tue, 26 May 2026 09:34:51 -0700 Subject: [PATCH] Make Windows service uninstall idempotent Treat sc.exe delete error 1060 as success when the service is already absent so repeated uninstalls do not fail. Signed-off-by: Bryan Frimin --- pkg/deviceagent/service/service_windows.go | 7 +++++- pkg/deviceagent/service/validate_windows.go | 24 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 pkg/deviceagent/service/validate_windows.go diff --git a/pkg/deviceagent/service/service_windows.go b/pkg/deviceagent/service/service_windows.go index 027a4a132..48a22e800 100644 --- a/pkg/deviceagent/service/service_windows.go +++ b/pkg/deviceagent/service/service_windows.go @@ -67,7 +67,12 @@ func Uninstall(cfg Config) error { name := DefaultWindowsName _ = exec.Command("sc.exe", "stop", name).Run() if out, err := exec.Command("sc.exe", "delete", name).CombinedOutput(); err != nil { - return fmt.Errorf("cannot run sc.exe delete: %w: %s", err, strings.TrimSpace(string(out))) + msg := strings.TrimSpace(string(out)) + if isWindowsServiceMissing(msg) { + return nil + } + + return fmt.Errorf("cannot run sc.exe delete: %w: %s", err, msg) } return nil } diff --git a/pkg/deviceagent/service/validate_windows.go b/pkg/deviceagent/service/validate_windows.go new file mode 100644 index 000000000..8a4d2aaae --- /dev/null +++ b/pkg/deviceagent/service/validate_windows.go @@ -0,0 +1,24 @@ +// Copyright (c) 2025-2026 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package service + +import "strings" + +func isWindowsServiceMissing(out string) bool { + lower := strings.ToLower(out) + return strings.Contains(lower, "1060") || + strings.Contains(lower, "does not exist as an installed service") || + strings.Contains(lower, "specified service does not exist") +}