- Agent: WAU registry config check (include/exclude URLs), pending updates count - Backend: /wau/compliance per customer, /wau/compliance/summary all customers - Frontend: compliance badge in customer list, compliance panel in WAU tab - config.js: no longer gitignored (secrets-free, reads from env/window.__RMM_CONFIG__) - vite.config.js: reads backend URL from .env instead of hardcoded value - .env.example added for clean setup
101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
//go:build windows
|
|
|
|
package collector
|
|
|
|
import (
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"golang.org/x/sys/windows/registry"
|
|
)
|
|
|
|
// WAUInfo enthält den Status von Winget-AutoUpdate auf diesem Gerät
|
|
type WAUInfo struct {
|
|
Installed bool `json:"installed"`
|
|
Version string `json:"version,omitempty"`
|
|
IncludeURL string `json:"include_url,omitempty"`
|
|
ExcludeURL string `json:"exclude_url,omitempty"`
|
|
PendingCount int `json:"pending_updates"`
|
|
}
|
|
|
|
// getWAUInfo liest WAU-Installations- und Konfigurationsstatus
|
|
func getWAUInfo(software []SoftwareInfo) WAUInfo {
|
|
info := WAUInfo{}
|
|
|
|
// WAU in installierter Software suchen
|
|
for _, s := range software {
|
|
lower := strings.ToLower(s.Name)
|
|
if strings.Contains(lower, "winget-autoupdate") || lower == "wau" {
|
|
info.Installed = true
|
|
info.Version = s.Version
|
|
break
|
|
}
|
|
}
|
|
|
|
// WAU-Konfiguration aus Registry lesen
|
|
// WAU speichert seine Einstellungen unter HKLM\SOFTWARE\Winget-AutoUpdate
|
|
regPaths := []string{
|
|
`SOFTWARE\Winget-AutoUpdate`,
|
|
`SOFTWARE\Policies\Microsoft\Windows\Winget-AutoUpdate`,
|
|
}
|
|
for _, path := range regPaths {
|
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, path, registry.QUERY_VALUE)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if url, _, err := k.GetStringValue("WAU_IncludeListURL"); err == nil && url != "" {
|
|
info.IncludeURL = url
|
|
}
|
|
if url, _, err := k.GetStringValue("WAU_ExcludeListURL"); err == nil && url != "" {
|
|
info.ExcludeURL = url
|
|
}
|
|
k.Close()
|
|
if info.IncludeURL != "" || info.ExcludeURL != "" {
|
|
info.Installed = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// Pending updates via winget upgrade --list zählen
|
|
wp := findWingetExe()
|
|
if wp != "" {
|
|
out, err := runPS(`& "` + wp + `" upgrade --list --accept-source-agreements 2>&1`)
|
|
if err == nil {
|
|
info.PendingCount = countWingetUpgradeLines(out)
|
|
}
|
|
}
|
|
|
|
return info
|
|
}
|
|
|
|
// findWingetExe sucht winget.exe im System
|
|
func findWingetExe() string {
|
|
if path, err := exec.LookPath("winget"); err == nil {
|
|
return path
|
|
}
|
|
script := `Get-ChildItem "C:\Program Files\WindowsApps" -Filter winget.exe -Recurse -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName`
|
|
out, err := runPS(script)
|
|
if err == nil && strings.TrimSpace(out) != "" {
|
|
return strings.TrimSpace(out)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// countWingetUpgradeLines zählt Pakete mit Updates aus "winget upgrade --list" Output
|
|
func countWingetUpgradeLines(output string) int {
|
|
lines := strings.Split(output, "\n")
|
|
count := 0
|
|
pastSeparator := false
|
|
for _, line := range lines {
|
|
trimmed := strings.TrimSpace(line)
|
|
if strings.Contains(trimmed, "---") {
|
|
pastSeparator = true
|
|
continue
|
|
}
|
|
if pastSeparator && trimmed != "" {
|
|
count++
|
|
}
|
|
}
|
|
return count
|
|
}
|