MCPcopy Index your code
hub / github.com/PatchMon/PatchMon / runPatchWindows

Function runPatchWindows

agent-source-code/cmd/patchmon-agent/commands/serve.go:2504–2641  ·  view source on GitHub ↗

runPatchWindows handles patching on Windows hosts. For patch_all: installs all approved WUA updates (by GUID from server) + upgrades all WinGet apps. For patch_package: routes by package name - "KB..." prefix -> WUA, otherwise -> WinGet upgrade.

(ctx context.Context, httpClient *client.Client, patchRunID, patchType string, packageNames []string, dryRun bool)

Source from the content-addressed store, hash-verified

2502// For patch_all: installs all approved WUA updates (by GUID from server) + upgrades all WinGet apps.
2503// For patch_package: routes by package name - "KB..." prefix -> WUA, otherwise -> WinGet upgrade.
2504func runPatchWindows(ctx context.Context, httpClient *client.Client, patchRunID, patchType string, packageNames []string, dryRun bool) error {
2505 patcher := packages.NewWindowsPatcher()
2506 var fullOutput strings.Builder
2507
2508 if err := httpClient.SendPatchOutput(ctx, patchRunID, "started", "", ""); err != nil {
2509 logger.WithError(err).Warn("Failed to send patch started to server")
2510 }
2511
2512 if patchType == "patch_all" {
2513 // Step 1: WUA - install approved OS/KB updates
2514 guids, err := httpClient.GetApprovedWindowsUpdateGUIDs(ctx)
2515 if err != nil {
2516 logger.WithError(err).Warn("Could not fetch approved Windows Update GUIDs; skipping WUA step")
2517 }
2518 if len(guids) > 0 {
2519 fmt.Fprintf(&fullOutput, "[Windows Update] Installing %d approved update(s)...\n", len(guids))
2520 _ = httpClient.SendPatchOutput(ctx, patchRunID, "progress", fullOutput.String(), "")
2521 for _, guid := range guids {
2522 out, err := patcher.InstallWindowsUpdate(ctx, guid)
2523 fmt.Fprintf(&fullOutput, " [%s] %s\n", guid, out)
2524 success := err == nil && !packages.IsSuperseded(out)
2525 result := client.WindowsUpdateResult{GUID: guid, Success: success}
2526 if err != nil {
2527 result.Error = err.Error()
2528 }
2529 _ = httpClient.SendWindowsUpdateResult(ctx, patchRunID, result)
2530 _ = httpClient.SendPatchOutput(ctx, patchRunID, "progress", fullOutput.String(), "")
2531 }
2532 }
2533
2534 // Step 2: WinGet - upgrade all applications
2535 fullOutput.WriteString("\n[WinGet] Upgrading applications...\n")
2536 _ = httpClient.SendPatchOutput(ctx, patchRunID, "progress", fullOutput.String(), "")
2537 wingetOut, wingetErr := patcher.WinGetUpgradeAll(ctx, dryRun)
2538 fullOutput.WriteString(wingetOut)
2539 fullOutput.WriteString("\n")
2540 if wingetErr != nil {
2541 logger.WithError(wingetErr).Warn("winget upgrade --all had errors (non-fatal)")
2542 }
2543
2544 // Step 3: report reboot status
2545 needsReboot := packages.RebootRequired()
2546 _ = httpClient.SendWindowsRebootStatus(ctx, patchRunID, needsReboot)
2547 if needsReboot {
2548 fullOutput.WriteString("\n[Reboot Required] A system restart is needed to complete the update installation.\n")
2549 }
2550 } else {
2551 // patch_package: each name is either a KB/GUID (WUA) or a WinGet package ID
2552 if len(packageNames) == 0 {
2553 _ = httpClient.SendPatchOutput(ctx, patchRunID, "failed", "", "package_names required for patch_package")
2554 return fmt.Errorf("package_names required for patch_package")
2555 }
2556 for _, name := range packageNames {
2557 name = strings.TrimSpace(name)
2558 if name == "" {
2559 continue
2560 }
2561 // Treat as WUA GUID if it looks like a UUID (36 chars with dashes), or KB prefix

Callers 1

runPatchFunction · 0.85

Calls 12

InstallWindowsUpdateMethod · 0.95
WinGetUpgradeAllMethod · 0.95
WinGetUpgradePackageMethod · 0.95
patchRunTrailerFunction · 0.85
sendReportFunction · 0.85
SendPatchOutputMethod · 0.80
ErrorMethod · 0.80
WriteStringMethod · 0.80

Tested by

no test coverage detected