#[cfg(target_os = "windows")]
use super::super::run;
#[cfg(target_os = "windows")]
use crate::os::monitor::{CpuSnapshot, DiskSnapshot, GpuSnapshot, MemorySnapshot};
#[cfg(target_os = "windows")]
use serde_json::Value;
#[cfg(target_os = "windows")]
use std::path::Path;
#[cfg(target_os = "windows")]
pub fn collect_cpu(warnings: &mut Vec<String>) -> CpuSnapshot {
let logical_cores = std::thread::available_parallelism().map_or(1, usize::from);
let utilization_percent = powershell_json("(Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average | ConvertTo-Json -Compress")
.and_then(|value| value.as_f64());
if utilization_percent.is_none() {
warnings.push("Windows CPU utilization unavailable from CIM".into());
}
CpuSnapshot {
logical_cores,
utilization_percent,
load_average_1m: None,
source: "Win32_Processor".into(),
}
}
#[cfg(target_os = "windows")]
pub fn collect_memory(warnings: &mut Vec<String>) -> MemorySnapshot {
let value = powershell_json("$o=Get-CimInstance Win32_OperatingSystem; @{total=[uint64]$o.TotalVisibleMemorySize*1024;free=[uint64]$o.FreePhysicalMemory*1024}|ConvertTo-Json -Compress");
let total = value
.as_ref()
.and_then(|v| v.get("total"))
.and_then(Value::as_u64);
let free = value
.as_ref()
.and_then(|v| v.get("free"))
.and_then(Value::as_u64);
if total.is_none() || free.is_none() {
warnings.push("Windows memory telemetry unavailable from CIM".into());
}
MemorySnapshot {
total_bytes: total,
used_bytes: total.zip(free).map(|(t, f)| t.saturating_sub(f)),
source: "Win32_OperatingSystem".into(),
}
}
#[cfg(target_os = "windows")]
pub fn collect_disk(root: &Path, warnings: &mut Vec<String>) -> DiskSnapshot {
let root_literal = root.to_string_lossy().replace('\'', "''");
let script = format!(
r#"$p='{root_literal}'; if ($p.StartsWith('\\?\')) {{ $p = $p.Substring(4) }}; $drive=[System.IO.Path]::GetPathRoot($p).TrimEnd('\'); $d=Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='$drive'"; @{{total=[uint64]$d.Size;free=[uint64]$d.FreeSpace}}|ConvertTo-Json -Compress"#
);
let value = powershell_json(&script);
let total = value
.as_ref()
.and_then(|v| v.get("total"))
.and_then(Value::as_u64);
let available = value
.as_ref()
.and_then(|v| v.get("free"))
.and_then(Value::as_u64);
if total.is_none() || available.is_none() {
warnings.push("Windows disk telemetry unavailable from CIM".into());
}
DiskSnapshot {
total_bytes: total,
available_bytes: available,
source: "Win32_LogicalDisk".into(),
}
}
#[cfg(target_os = "windows")]
pub fn collect_gpus(warnings: &mut Vec<String>) -> Vec<GpuSnapshot> {
if let Some(gpus) = super::super::nvidia_gpus() {
return gpus;
}
let gpus = platform_gpus();
if gpus.is_empty() {
warnings.push("GPU inventory unavailable; no supported native adapter was detected".into());
}
gpus
}
#[cfg(target_os = "windows")]
fn platform_gpus() -> Vec<GpuSnapshot> {
let Some(value) = powershell_json("@(Get-CimInstance Win32_VideoController | Select-Object Name,AdapterRAM,AdapterCompatibility)|ConvertTo-Json -Compress") else { return Vec::new(); };
value
.as_array()
.into_iter()
.flatten()
.filter_map(|item| {
Some(GpuSnapshot {
name: item.get("Name")?.as_str()?.into(),
vendor: item
.get("AdapterCompatibility")
.and_then(Value::as_str)
.map(str::to_string),
utilization_percent: None,
memory_total_bytes: item.get("AdapterRAM").and_then(Value::as_u64),
memory_used_bytes: None,
source: "Win32_VideoController".into(),
status: "inventory-only".into(),
})
})
.collect()
}
#[cfg(target_os = "windows")]
pub(super) fn powershell_json(script: &str) -> Option<Value> {
let output = run(
"powershell.exe",
&["-NoProfile", "-NonInteractive", "-Command", script],
)
.ok()?;
output
.success
.then(|| serde_json::from_str(&output.stdout).ok())
.flatten()
}