USGC.MachineReport.psm1

#Requires -Version 5.1
# TR-100 Machine Report (PowerShell)
# Copyright © 2024, U.S. Graphics, LLC. BSD-3-Clause License.
# Windows / macOS / Linux port of the USGC bash original. Edit this file directly.

# Global variables
$script:MIN_NAME_LEN = 5
$script:MAX_NAME_LEN = 13
$script:MIN_DATA_LEN = 20
$script:MAX_DATA_LEN = 32
$script:BORDERS_AND_PADDING = 7
$script:CURRENT_LEN = $script:MIN_DATA_LEN

# Basic configuration, change as needed
$script:report_title = "UNITED STATES GRAPHICS COMPANY"

$script:Invariant = [System.Globalization.CultureInfo]::InvariantCulture

$script:PnpVendors = @{
    ACR = 'Acer';  ACI = 'ASUS';  AUS = 'ASUS';  BNQ = 'BenQ'
    DEL = 'Dell';  ENC = 'Eizo';  GSM = 'LG';    HPN = 'HP'
    HWP = 'HP';    IVM = 'Iiyama'; LEN = 'Lenovo'; MEI = 'Panasonic'
    MSI = 'MSI';   PHL = 'Philips'; SAM = 'Samsung'; SEC = 'Samsung'
    VSC = 'ViewSonic'
}

$script:NativeDisplaysSrc = @'
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

public static class NativeDisplays {
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct DISPLAY_DEVICE {
        public int cb;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string DeviceName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceString;
        public int StateFlags;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceID;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string DeviceKey;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct DEVMODE {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string dmDeviceName;
        public short dmSpecVersion, dmDriverVersion, dmSize, dmDriverExtra;
        public int dmFields, dmPositionX, dmPositionY, dmDisplayOrientation, dmDisplayFixedOutput;
        public short dmColor, dmDuplex, dmYResolution, dmTTOption, dmCollate;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string dmFormName;
        public short dmLogPixels;
        public int dmBitsPerPel, dmPelsWidth, dmPelsHeight, dmDisplayFlags, dmDisplayFrequency;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

    public class Info {
        public string DeviceName;
        public string MonitorName;
        public string AdapterName;
        public string HardwareId;
        public bool Primary;
        public int Width;
        public int Height;
        public int Frequency;
    }

    public static List<Info> GetAll() {
        var result = new List<Info>();
        uint i = 0;
        while (true) {
            var dd = new DISPLAY_DEVICE();
            dd.cb = Marshal.SizeOf(dd);
            if (!EnumDisplayDevices(null, i, ref dd, 0)) break;
            i++;
            bool attached = (dd.StateFlags & 0x1) != 0;
            bool mirror = (dd.StateFlags & 0x8) != 0;
            bool primary = (dd.StateFlags & 0x4) != 0;
            if (!attached || mirror) continue;

            var dm = new DEVMODE();
            dm.dmSize = (short)Marshal.SizeOf(dm);
            int w = 0, h = 0, hz = 0;
            if (EnumDisplaySettings(dd.DeviceName, -1, ref dm)) {
                w = dm.dmPelsWidth; h = dm.dmPelsHeight; hz = dm.dmDisplayFrequency;
            }

            uint m = 0;
            bool any = false;
            while (true) {
                var mon = new DISPLAY_DEVICE();
                mon.cb = Marshal.SizeOf(mon);
                if (!EnumDisplayDevices(dd.DeviceName, m, ref mon, 0)) break;
                m++;
                any = true;
                var info = new Info();
                info.DeviceName = dd.DeviceName;
                info.MonitorName = mon.DeviceString;
                info.AdapterName = dd.DeviceString;
                info.HardwareId = mon.DeviceID;
                info.Primary = primary;
                info.Width = w; info.Height = h; info.Frequency = hz;
                result.Add(info);
            }
            if (!any) {
                var info = new Info();
                info.DeviceName = dd.DeviceName;
                info.MonitorName = dd.DeviceString;
                info.AdapterName = dd.DeviceString;
                info.HardwareId = dd.DeviceID;
                info.Primary = primary;
                info.Width = w; info.Height = h; info.Frequency = hz;
                result.Add(info);
            }
        }
        return result;
    }
}
'@


function fmt2 {
    param($n)
    ([double]$n).ToString('0.00', $script:Invariant)
}

function max_length {
    param([string[]]$Strings)

    $max_len = 0
    foreach ($str in $Strings) {
        if ($null -eq $str) { continue }
        $len = $str.Length
        if ($len -gt $max_len) { $max_len = $len }
    }

    if ($max_len -lt $script:MIN_DATA_LEN) {
        $script:MIN_DATA_LEN
    } elseif ($max_len -lt $script:MAX_DATA_LEN) {
        $max_len
    } else {
        $script:MAX_DATA_LEN
    }
}

function set_current_len {
    $all = @(
        $script:report_title
        $script:os_name
        $script:os_kernel
        $script:board_name
        $script:net_hostname
        $script:net_machine_ip
        $script:net_client_ip
        $script:net_current_user
        $script:nic_line
        $script:cpu_model
        $script:cpu_cores_line
        $script:cpu_hypervisor
        "$($script:cpu_freq) GHz"
        $script:mem_line
        $script:pagefile_line
        $script:storage_health
        $script:last_login_time
        $script:last_login_ip
        $script:sys_uptime
        $script:power_plan
        $script:secure_boot
    )
    if ($script:net_dns_ip) { $all += @($script:net_dns_ip) }
    if ($script:volume_lines) { $all += @($script:volume_lines) }
    if ($script:display_lines) { $all += @($script:display_lines) }
    foreach ($g in @($script:gpus)) {
        $all += @($g.Name, $g.Driver, $g.VramLine, $g.Thermals)
    }
    $script:CURRENT_LEN = max_length $all
}

function PRINT_HEADER {
    $length = $script:CURRENT_LEN + $script:MAX_NAME_LEN + $script:BORDERS_AND_PADDING
    $top = "┌"
    $bottom = "├"
    for ($i = 0; $i -lt ($length - 2); $i++) {
        $top += "┬"
        $bottom += "┴"
    }
    $top += "┐"
    $bottom += "┤"
    Write-Output $top
    Write-Output $bottom
}

function PRINT_CENTERED_DATA {
    param([string]$text)

    $max_len = $script:CURRENT_LEN + $script:MAX_NAME_LEN - $script:BORDERS_AND_PADDING
    $total_width = $max_len + 12
    $text_len = $text.Length
    $padding_left = [int][math]::Floor(($total_width - $text_len) / 2)
    if ($padding_left -lt 0) { $padding_left = 0 }
    $padding_right = $total_width - $text_len - $padding_left
    if ($padding_right -lt 0) { $padding_right = 0 }
    Write-Output ("│" + (" " * $padding_left) + $text + (" " * $padding_right) + "│")
}

function PRINT_DIVIDER {
    param([string]$side)

    switch ($side) {
        "top" {
            $left_symbol = "├"; $middle_symbol = "┬"; $right_symbol = "┤"
        }
        "bottom" {
            $left_symbol = "└"; $middle_symbol = "┴"; $right_symbol = "┘"
        }
        default {
            $left_symbol = "├"; $middle_symbol = "┼"; $right_symbol = "┤"
        }
    }

    $length = $script:CURRENT_LEN + $script:MAX_NAME_LEN + $script:BORDERS_AND_PADDING
    $divider = $left_symbol
    for ($i = 0; $i -lt ($length - 3); $i++) {
        $divider += "─"
        if ($i -eq 14) { $divider += $middle_symbol }
    }
    $divider += $right_symbol
    Write-Output $divider
}

function PRINT_DATA {
    param(
        [string]$name,
        [string]$data
    )

    $max_data_len = $script:CURRENT_LEN
    $name_len = $name.Length
    if ($name_len -lt $script:MIN_NAME_LEN) {
        $name = $name.PadRight($script:MIN_NAME_LEN)
    } elseif ($name_len -gt $script:MAX_NAME_LEN) {
        $name = $name.Substring(0, $script:MAX_NAME_LEN - 3) + "..."
    } else {
        $name = $name.PadRight($script:MAX_NAME_LEN)
    }

    if ($null -eq $data) { $data = "" }
    $data_len = $data.Length
    if ($data_len -gt $max_data_len) {
        $cut = $max_data_len - 3
        if ($cut -lt 1) { $cut = 1 }
        $data = $data.Substring(0, $cut) + "..."
    } else {
        $data = $data.PadRight($max_data_len)
    }

    Write-Output ("│ " + $name.PadRight($script:MAX_NAME_LEN) + " │ " + $data + " │")
}

function bar_graph {
    param($used, $total)

    $width = $script:CURRENT_LEN
    $used_n = 0.0
    $total_n = 0.0
    try { $used_n = [double]$used } catch { $used_n = 0.0 }
    try { $total_n = [double]$total } catch { $total_n = 0.0 }

    if ($total_n -eq 0) { $percent = 0.0 } else { $percent = ($used_n / $total_n) * 100.0 }

    $num_blocks = [int][math]::Floor(($percent / 100.0) * $width)
    if ($num_blocks -gt $width) { $num_blocks = $width }
    if ($num_blocks -lt 0) { $num_blocks = 0 }

    $filled = if ($num_blocks -gt 0) { "█" * $num_blocks } else { "" }
    $empty = if (($width - $num_blocks) -gt 0) { "░" * ($width - $num_blocks) } else { "" }
    $filled + $empty
}

function Get-ReportPlatform {
    if ($PSVersionTable.PSVersion.Major -lt 6) { return 'Windows' }
    if ($IsWindows) { return 'Windows' }
    if ($IsMacOS) { return 'macOS' }
    if ($IsLinux) { return 'Linux' }
    'Windows'
}

function Get-FileText {
    param([string]$Path)
    if (-not $Path -or -not (Test-Path -LiteralPath $Path)) { return $null }
    try {
        return [System.IO.File]::ReadAllText($Path)
    } catch {
        return $null
    }
}

function Get-CommandOutput {
    param(
        [Parameter(Mandatory)][string]$FileName,
        [string[]]$ArgumentList
    )
    $cmd = Get-Command $FileName -ErrorAction SilentlyContinue
    if (-not $cmd) { return $null }
    try {
        if ($ArgumentList) {
            return & $cmd.Source @ArgumentList 2>$null
        }
        return & $cmd.Source 2>$null
    } catch {
        return $null
    }
}

function Format-Uptime {
    param($Seconds)
    try { $td = [TimeSpan]::FromSeconds([double]$Seconds) } catch { return "Unknown" }
    $parts = @()
    if ($td.Days -gt 0) { $parts += "$($td.Days) d" }
    if ($td.Hours -gt 0) { $parts += "$($td.Hours) h" }
    if ($td.Minutes -gt 0 -or $td.Days -gt 0 -or $td.Hours -gt 0) {
        $parts += "$($td.Minutes) m"
    } else {
        $parts += "$([int][math]::Floor($td.TotalSeconds)) s"
    }
    $parts -join ", "
}

function Format-CpuName {
    param([string]$Name)
    if (-not $Name) { return "Unknown" }
    ($Name -replace "\(R\)", "" -replace "\(TM\)", "" -replace "\(C\)", "" -replace "\s+", " ").Trim()
}

function Get-VolumePrintName {
    param([string]$Id)
    if ($Id -match '^[A-Za-z]$') { return "VOLUME ${Id}:" }
    "VOLUME $Id"
}

function Get-UsagePrintName {
    param([string]$Id)
    if ($Id -match '^[A-Za-z]$') { return "USAGE ${Id}:" }
    "USAGE $Id"
}

function Get-NvidiaSmiPath {
    $cmd = Get-Command "nvidia-smi" -ErrorAction SilentlyContinue
    if ($cmd) { return $cmd.Source }
    $candidates = @(
        "/usr/bin/nvidia-smi",
        "/usr/lib/wsl/lib/nvidia-smi"
    )
    if ($env:SystemRoot) {
        $candidates += (Join-Path $env:SystemRoot "System32\nvidia-smi.exe")
    }
    if (${env:ProgramFiles}) {
        $candidates += (Join-Path ${env:ProgramFiles} "NVIDIA Corporation\NVSMI\nvidia-smi.exe")
    }
    foreach ($path in $candidates) {
        if ($path -and (Test-Path -LiteralPath $path)) { return $path }
    }
    $null
}

function Get-NativeDisplaysType {
    'NativeDisplays' -as [type]
}

function Initialize-NativeDisplays {
    if (Get-NativeDisplaysType) { return $true }

    $cacheDir = Join-Path $env:LOCALAPPDATA "USGC.MachineReport"
    $dllName = "NativeDisplays.{0}.dll" -f $PSVersionTable.PSVersion
    $dll = Join-Path $cacheDir $dllName

    if (Test-Path -LiteralPath $dll) {
        try {
            [void][Reflection.Assembly]::LoadFrom($dll)
            if (Get-NativeDisplaysType) { return $true }
        } catch {
        }
    }

    try {
        if (-not (Test-Path -LiteralPath $cacheDir)) {
            New-Item -ItemType Directory -Path $cacheDir -Force | Out-Null
        }
        Add-Type -TypeDefinition $script:NativeDisplaysSrc -OutputAssembly $dll -OutputType Library -ErrorAction Stop
        if (-not (Get-NativeDisplaysType)) {
            [void][Reflection.Assembly]::LoadFrom($dll)
        }
        if (Get-NativeDisplaysType) { return $true }
    } catch {
    }

    try {
        Add-Type -TypeDefinition $script:NativeDisplaysSrc -ErrorAction Stop
        return [bool](Get-NativeDisplaysType)
    } catch {
        return $false
    }
}

function Get-MonitorVendor {
    param([string]$HardwareId)
    if ($HardwareId -match 'MONITOR\\([A-Z]{3})') {
        $id = $Matches[1]
        if ($script:PnpVendors.ContainsKey($id)) { return $script:PnpVendors[$id] }
    }
    $null
}

function Format-LinkSpeed {
    param($speed)
    if (-not $speed) { return $null }
    try { $n = [double]$speed } catch { return $null }
    if ($n -ge 1000000000) { return ("{0:0} Gbps" -f ($n / 1000000000.0)) }
    if ($n -ge 1000000)    { return ("{0:0} Mbps" -f ($n / 1000000.0)) }
    if ($n -ge 1000)       { return ("{0:0} Kbps" -f ($n / 1000.0)) }
    "$n bps"
}

function Test-VirtualGpuName {
    param([string]$Name)
    $Name -match "Virtual|Remote Display|Basic Display|Basic Render|Microsoft Remote|IddSample"
}

function Reset-ReportState {
    $script:gpu_present = 0
    $script:board_present = 0
    $script:display_present = 0
    $script:nic_present = 0
    $script:storage_present = 0
    $script:secure_boot_present = 0
    $script:power_present = 0
    $script:pagefile_present = 0
    $script:cpu_freq_present = 0
    $script:gpus = @()
    $script:volumes = @()
    $script:displays = @()
    $script:volume_lines = @()
    $script:display_lines = @()
    $script:net_dns_ip = @()
    $script:board_name = ""
    $script:nic_line = ""
    $script:pagefile_line = ""
    $script:pagefile_label = "PAGEFILE"
    $script:storage_health = ""
    $script:power_plan = ""
    $script:secure_boot = ""
    $script:last_login_ip = ""
    $script:last_login_time = "Unknown"
    $script:sys_uptime = "Unknown"
    $script:os_name = ""
    $script:os_kernel = ""
    $script:net_hostname = ""
    $script:net_machine_ip = "No IP found"
    $script:net_client_ip = "Not connected"
    $script:net_current_user = ""
    $script:cpu_model = "Unknown"
    $script:cpu_cores_line = ""
    $script:cpu_hypervisor = "Bare Metal"
    $script:cpu_freq = "0.00"
    $script:cpu_load = 0.0
    $script:load_avgs = $null
    $script:load_cpus = 1
    $script:mem_used = 0
    $script:mem_total = 0
    $script:mem_line = ""
}

function Set-ClientAndUser {
    if ($env:SSH_CLIENT) {
        $script:net_client_ip = ($env:SSH_CLIENT -split "\s+")[0]
    } elseif ($env:SESSIONNAME -match "^RDP") {
        $script:net_client_ip = "RDP"
    } else {
        $script:net_client_ip = "Console"
    }

    $script:net_current_user = $env:USER
    if (-not $script:net_current_user) { $script:net_current_user = $env:USERNAME }
    try {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
        if ($id) { $script:net_current_user = $id }
    } catch {
    }
    if (-not $script:net_current_user) { $script:net_current_user = "Unknown" }

    $script:net_hostname = [System.Net.Dns]::GetHostName()
    if (-not $script:net_hostname) { $script:net_hostname = $env:COMPUTERNAME }
    if (-not $script:net_hostname) { $script:net_hostname = $env:HOSTNAME }
    if (-not $script:net_hostname) { $script:net_hostname = "Not Defined" }
}

function Set-DotNetNetworkInfo {
    $chosen = $null
    try {
        $nics = [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces()
        foreach ($i in $nics) {
            if ($i.OperationalStatus -ne 'Up') { continue }
            if ($i.NetworkInterfaceType -eq 'Loopback' -or $i.NetworkInterfaceType -eq 'Tunnel') { continue }
            if ($i.Name -match '^(lo\d*|docker|br-|veth|cni|flannel|VMnet|vEthernet)') { continue }
            $props = $i.GetIPProperties()
            $gw = @($props.GatewayAddresses | ForEach-Object { $_.Address } | Where-Object { $_ -and $_.ToString() -ne '0.0.0.0' -and $_.ToString() -ne '::' })
            if ($gw.Count -gt 0) { $chosen = $i; break }
            if (-not $chosen) { $chosen = $i }
        }
    } catch {
    }

    if ($chosen) {
        $props = $chosen.GetIPProperties()
        $unicast = @($props.UnicastAddresses | ForEach-Object { $_.Address })
        $v4 = $unicast | Where-Object { $_.AddressFamily -eq 'InterNetwork' -and $_.ToString() -notlike '127.*' -and $_.ToString() -notlike '169.254.*' } | Select-Object -First 1
        $v6 = $unicast | Where-Object { $_.AddressFamily -eq 'InterNetworkV6' -and -not $_.IsIPv6LinkLocal } | Select-Object -First 1
        if ($v4) { $script:net_machine_ip = $v4.ToString() }
        elseif ($v6) { $script:net_machine_ip = $v6.ToString() }
        $dns = @($props.DnsAddresses | Where-Object { $_ -and $_.ToString() -notlike 'fec0:*' } | ForEach-Object { $_.ToString() })
        if ($dns.Count -gt 0) { $script:net_dns_ip = $dns }
        $speed = $null
        if ($chosen.Speed -gt 0 -and $chosen.Speed -lt 9223372036854775807) {
            $speed = Format-LinkSpeed $chosen.Speed
        }
        if ($speed) { $script:nic_line = "$($chosen.Name) $speed" } else { $script:nic_line = $chosen.Name }
        $script:nic_present = 1
    }

    if (-not $script:net_dns_ip -or $script:net_dns_ip.Count -eq 0) {
        $resolv = Get-FileText '/etc/resolv.conf'
        if ($resolv) {
            $script:net_dns_ip = @([regex]::Matches($resolv, '(?m)^nameserver\s+(\S+)') | ForEach-Object { $_.Groups[1].Value })
        }
    }
}

function Set-UnixVolumes {
    $out = Get-CommandOutput 'df' @('-kP')
    if (-not $out) { return }
    foreach ($line in @($out)) {
        if ($line -notmatch '^(/dev/\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)$') { continue }
        $mp = $Matches[6]
        if ($mp -match '^/(proc|sys|dev|run|snap)(/|$)') { continue }
        if ($mp -match '^/System/Volumes/(Preboot|VM|Update|iSCSI)') { continue }
        if ($mp -eq '/private/var/vm') { continue }
        $totalKb = [int64]$Matches[2]
        $usedKb = [int64]$Matches[3]
        if ($totalKb -le 0) { continue }
        $used = $usedKb * 1024L
        $total = $totalKb * 1024L
        $used_gb = fmt2 ($used / 1GB)
        $total_gb = fmt2 ($total / 1GB)
        $pct = fmt2 (($used / $total) * 100.0)
        $volLine = "$used_gb/$total_gb GB [$pct%]"
        $script:volumes += [pscustomobject]@{ Id = $mp; Used = $used; Total = $total; Line = $volLine }
        $script:volume_lines += $volLine
    }
}

function Set-NvidiaSmiGpus {
    $smi = Get-NvidiaSmiPath
    if (-not $smi) { return }
    $raw = Get-CommandOutput $smi @(
        "--query-gpu=name,driver_version,memory.total,memory.used,utilization.gpu,temperature.gpu,power.draw,power.limit,clocks.gr,fan.speed",
        "--format=csv,noheader,nounits"
    )
    if (-not $raw) { return }
    foreach ($row in @($raw)) {
        if (-not $row) { continue }
        $parts = @($row -split "," | ForEach-Object { $_.Trim() })
        if ($parts.Count -lt 5) { continue }
        if (Test-VirtualGpuName $parts[0]) { continue }

        $mem_total_mib = 0.0
        $mem_used_mib = 0.0
        $util = 0.0
        try { $mem_total_mib = [double]$parts[2] } catch { }
        try { $mem_used_mib = [double]$parts[3] } catch { }
        try { $util = [double]$parts[4] } catch { }

        $vram_pct = "0.00"
        if ($mem_total_mib -gt 0) { $vram_pct = fmt2 (($mem_used_mib / $mem_total_mib) * 100.0) }
        $vram_line = "$(fmt2 ($mem_used_mib / 1024.0))/$(fmt2 ($mem_total_mib / 1024.0)) GiB [$vram_pct%]"

        $thermo = @()
        if ($parts.Count -gt 5 -and $parts[5] -notmatch "N/A|^$") { $thermo += "$($parts[5]) C" }
        if ($parts.Count -gt 7 -and $parts[6] -notmatch "N/A|^$" -and $parts[7] -notmatch "N/A|^$") {
            $pwr = [int][math]::Round([double]$parts[6])
            $cap = [int][math]::Round([double]$parts[7])
            $thermo += "$pwr/$cap W"
        } elseif ($parts.Count -gt 6 -and $parts[6] -notmatch "N/A|^$") {
            $pwr = [int][math]::Round([double]$parts[6])
            $thermo += "$pwr W"
        }
        if ($parts.Count -gt 8 -and $parts[8] -notmatch "N/A|^$") {
            $clk = [int][math]::Round([double]$parts[8])
            $thermo += "$clk MHz"
        }

        $script:gpus += [pscustomobject]@{
            Name      = $parts[0]
            Driver    = $parts[1]
            MemUsed   = $mem_used_mib
            MemTotal  = $mem_total_mib
            Util      = $util
            VramLine  = $vram_line
            Thermals  = ($thermo -join " ")
            HasMeters = $true
        }
    }
}

function Set-MemoryLine {
    param($UsedBytes, $TotalBytes)
    $script:mem_used = [int64]$UsedBytes
    $script:mem_total = [int64]$TotalBytes
    if ($script:mem_used -lt 0) { $script:mem_used = 0 }
    $pct = "0.00"
    if ($script:mem_total -gt 0) { $pct = fmt2 (($script:mem_used / $script:mem_total) * 100.0) }
    $script:mem_line = "$(fmt2 ($script:mem_used / 1GB))/$(fmt2 ($script:mem_total / 1GB)) GiB [$pct%]"
}

function Add-DisplayLine {
    param(
        [string]$Line,
        [bool]$Primary = $false
    )
    if (-not $Line) { return }
    $script:displays += [pscustomobject]@{ Primary = $Primary; Line = $Line }
    $script:display_lines += $Line
    $script:display_present = 1
}

function Collect-LinuxReport {
    Set-ClientAndUser

    $osrel = Get-FileText '/etc/os-release'
    $pretty = $null
    if ($osrel -match '(?m)^PRETTY_NAME="?([^"\r\n]+)"?') { $pretty = $Matches[1] }
    if (-not $pretty -and $osrel -match '(?m)^NAME="?([^"\r\n]+)"?') { $pretty = $Matches[1] }
    if (-not $pretty) { $pretty = "Linux" }
    $script:os_name = $pretty

    $kernel = (Get-CommandOutput 'uname' @('-s')).Trim()
    $krel = (Get-CommandOutput 'uname' @('-r')).Trim()
    if ($kernel -and $krel) { $script:os_kernel = "$kernel $krel" }
    elseif ($PSVersionTable.OS) { $script:os_kernel = [string]$PSVersionTable.OS }
    else { $script:os_kernel = "Linux" }

    $board = (Get-FileText '/sys/class/dmi/id/board_name')
    if ($board) { $board = $board.Trim() }
    if ($board -and $board -notmatch 'O\.E\.M\.|Default string|None|To be filled') {
        $script:board_name = $board
        $script:board_present = 1
    }

    Set-DotNetNetworkInfo

    $cpuinfo = Get-FileText '/proc/cpuinfo'
    $script:cpu_model = "Unknown"
    $mhz = $null
    $procs = 0
    if ($cpuinfo) {
        $m = [regex]::Match($cpuinfo, '(?m)^model name\s*:\s*(.+)$')
        if ($m.Success) { $script:cpu_model = Format-CpuName $m.Groups[1].Value }
        else {
            $h = [regex]::Match($cpuinfo, '(?m)^Hardware\s*:\s*(.+)$')
            if ($h.Success) { $script:cpu_model = Format-CpuName $h.Groups[1].Value }
        }
        $z = [regex]::Match($cpuinfo, '(?m)^cpu MHz\s*:\s*([\d.]+)')
        if ($z.Success) { $mhz = [double]$z.Groups[1].Value }
        $procs = [regex]::Matches($cpuinfo, '(?m)^processor\s*:').Count
    }
    if ($procs -lt 1) { $procs = 1 }
    $script:load_cpus = $procs
    $script:cpu_cores_line = "$procs Thread(s)"
    if ($mhz -and $mhz -gt 1) {
        $script:cpu_freq = fmt2 ($mhz / 1000.0)
        $script:cpu_freq_present = 1
    }

    if ($env:WSL_DISTRO_NAME) {
        $script:cpu_hypervisor = "WSL"
    } else {
        $virt = Get-CommandOutput 'systemd-detect-virt'
        if ($virt) { $virt = "$virt".Trim() }
        if ($virt -and $virt -ne 'none') {
            if ($virt -eq 'wsl') { $script:cpu_hypervisor = "WSL" }
            else { $script:cpu_hypervisor = $virt }
        } elseif ($cpuinfo -match 'hypervisor') {
            $script:cpu_hypervisor = "Hypervisor"
        }
    }

    $lavg = Get-FileText '/proc/loadavg'
    if ($lavg -match '^([\d.]+)\s+([\d.]+)\s+([\d.]+)') {
        $script:load_avgs = @([double]$Matches[1], [double]$Matches[2], [double]$Matches[3])
    }

    $meminfo = Get-FileText '/proc/meminfo'
    if ($meminfo) {
        $mt = 0L; $ma = 0L; $st = 0L; $sf = 0L
        if ($meminfo -match '(?m)^MemTotal:\s+(\d+)') { $mt = [int64]$Matches[1] * 1024L }
        if ($meminfo -match '(?m)^MemAvailable:\s+(\d+)') { $ma = [int64]$Matches[1] * 1024L }
        Set-MemoryLine ($mt - $ma) $mt
        if ($meminfo -match '(?m)^SwapTotal:\s+(\d+)') { $st = [int64]$Matches[1] }
        if ($meminfo -match '(?m)^SwapFree:\s+(\d+)') { $sf = [int64]$Matches[1] }
        if ($st -gt 0) {
            $script:pagefile_label = "SWAP"
            $script:pagefile_line = "$(fmt2 (($st - $sf) / (1024.0 * 1024.0)))/$(fmt2 ($st / (1024.0 * 1024.0))) GiB"
            $script:pagefile_present = 1
        }
    }

    Set-UnixVolumes

    $ssd = 0; $hdd = 0
    if (-not $env:WSL_DISTRO_NAME) {
    foreach ($b in @(Get-ChildItem '/sys/block' -ErrorAction SilentlyContinue)) {
        if ($b.Name -match '^(loop|ram|sr|fd|dm-|zram|nbd)') { continue }
        $rot = Get-FileText (Join-Path $b.FullName 'queue/rotational')
        if ($null -eq $rot) { continue }
        if ($rot.Trim() -eq '0') { $ssd++ } else { $hdd++ }
    }
    }
    if (($ssd + $hdd) -gt 0) {
        $bits = @()
        if ($ssd -gt 0) { $bits += "$ssd SSD" }
        if ($hdd -gt 0) { $bits += "$hdd HDD" }
        $script:storage_health = "$($bits -join ' / ') HEALTH O.K."
        $script:storage_present = 1
    }

    Set-NvidiaSmiGpus
    if ($script:gpus.Count -eq 0) {
        $lspci = Get-CommandOutput 'lspci'
        foreach ($line in @($lspci)) {
            if ($line -notmatch 'VGA compatible controller|3D controller|Display controller') { continue }
            $name = ($line -replace '^[^:]+:\s*', '').Trim()
            if (-not $name -or (Test-VirtualGpuName $name)) { continue }
            $script:gpus += [pscustomobject]@{
                Name = $name; Driver = ""; MemUsed = 0; MemTotal = 0; Util = 0
                VramLine = ""; Thermals = ""; HasMeters = $false
            }
        }
    }
    if ($script:gpus.Count -gt 0) { $script:gpu_present = 1 }

    $xr = Get-CommandOutput 'xrandr' @('--query')
    if ($xr) {
        $cur = $null
        foreach ($line in @($xr)) {
            if ($line -match '^(\S+)\s+connected(\s+primary)?(?:\s+(\d+)x(\d+))?') {
                if ($cur) { Add-DisplayLine $cur.Line $cur.Primary }
                $primary = [bool]$Matches[2]
                $lineText = $null
                if ($Matches[3]) { $lineText = "$($Matches[3]) x $($Matches[4])" }
                $cur = [pscustomobject]@{ Primary = $primary; Line = $lineText }
            } elseif ($cur -and $line -match '^\s+\d+x\d+\s+([\d.]+).*\*') {
                $hz = [int][math]::Round([double]$Matches[1])
                if ($cur.Line) { $cur.Line = "$($cur.Line) @ $hz Hz" }
                Add-DisplayLine $cur.Line $cur.Primary
                $cur = $null
            }
        }
        if ($cur -and $cur.Line) { Add-DisplayLine $cur.Line $cur.Primary }
    }
    if ($script:displays.Count -eq 0) {
        foreach ($d in @(Get-ChildItem '/sys/class/drm' -ErrorAction SilentlyContinue)) {
            if ($d.Name -notmatch '^card\d+-') { continue }
            $status = Get-FileText (Join-Path $d.FullName 'status')
            if ("$status".Trim() -ne 'connected') { continue }
            $mode = Get-FileText (Join-Path $d.FullName 'modes')
            if ($mode -match '(\d+)x(\d+)') {
                Add-DisplayLine "$($Matches[1]) x $($Matches[2])" $false
            }
        }
    }
    if ($script:displays.Count -gt 1) {
        $script:displays = @($script:displays | Sort-Object { -not $_.Primary }, Line)
        $script:display_lines = @($script:displays | ForEach-Object { $_.Line })
    }

    $user = $env:USER
    $ll = $null
    if ($user) { $ll = Get-CommandOutput 'lastlog' @('-u', $user) }
    if ($ll) {
        $row = @($ll | Select-Object -Skip 1 | Select-Object -First 1)
        if ($row -match 'Never logged in') {
            $script:last_login_time = "Never logged in"
        } elseif ($row -match '([A-Z][a-z]{2}\s+\w.+\d{4})') {
            try {
                $dt = [datetime]::Parse($Matches[1])
                $script:last_login_time = $dt.ToString("MMM dd yyyy HH:mm", $script:Invariant)
            } catch {
                $script:last_login_time = $Matches[1].Trim()
            }
        }
    }

    $upt = Get-FileText '/proc/uptime'
    if ($upt -match '^([\d.]+)') { $script:sys_uptime = Format-Uptime $Matches[1] }

    $prof = Get-CommandOutput 'powerprofilesctl' @('get')
    if ($prof) {
        $script:power_plan = "$prof".Trim()
        $script:power_present = 1
    }

    $mok = Get-CommandOutput 'mokutil' @('--sb-state')
    if ("$mok" -match 'enabled') { $script:secure_boot = "On"; $script:secure_boot_present = 1 }
    elseif ("$mok" -match 'disabled') { $script:secure_boot = "Off"; $script:secure_boot_present = 1 }
}

function Collect-MacReport {
    Set-ClientAndUser

    $prod = (Get-CommandOutput 'sw_vers' @('-productName') | Out-String).Trim()
    $ver = (Get-CommandOutput 'sw_vers' @('-productVersion') | Out-String).Trim()
    if ($prod -and $ver) { $script:os_name = "$prod $ver" }
    elseif ($ver) { $script:os_name = "macOS $ver" }
    else { $script:os_name = "macOS" }

    $kernel = (Get-CommandOutput 'uname' @('-s') | Out-String).Trim()
    $krel = (Get-CommandOutput 'uname' @('-r') | Out-String).Trim()
    if ($kernel -and $krel) { $script:os_kernel = "$kernel $krel" }
    else { $script:os_kernel = "Darwin" }

    $model = (Get-CommandOutput 'sysctl' @('-n', 'hw.model') | Out-String).Trim()
    if ($model) {
        $script:board_name = $model
        $script:board_present = 1
    }

    Set-DotNetNetworkInfo

    $brand = (Get-CommandOutput 'sysctl' @('-n', 'machdep.cpu.brand_string') | Out-String).Trim()
    if ($brand) { $script:cpu_model = Format-CpuName $brand }
    $phys = (Get-CommandOutput 'sysctl' @('-n', 'hw.physicalcpu') | Out-String).Trim()
    $logi = (Get-CommandOutput 'sysctl' @('-n', 'hw.logicalcpu') | Out-String).Trim()
    $pN = 0; $lN = 0
    try { $pN = [int]$phys } catch { }
    try { $lN = [int]$logi } catch { }
    if ($lN -lt 1) { $lN = 1 }
    $script:load_cpus = $lN
    if ($pN -gt 0 -and $pN -ne $lN) {
        $script:cpu_cores_line = "$pN Core(s) / $lN Thread(s)"
    } else {
        $script:cpu_cores_line = "$lN Thread(s)"
    }

    $freq = (Get-CommandOutput 'sysctl' @('-n', 'hw.cpufrequency') | Out-String).Trim()
    $freqN = 0
    try { $freqN = [int64]$freq } catch { }
    if ($freqN -gt 1000000) {
        $script:cpu_freq = fmt2 ($freqN / 1000000000.0)
        $script:cpu_freq_present = 1
    }

    $virt = (Get-CommandOutput 'sysctl' @('-n', 'kern.hv_vmm_present') | Out-String).Trim()
    if ($model -match 'VMware|VirtualBox|Parallels|QEMU|VirtualMac') {
        $script:cpu_hypervisor = $Matches[0]
    } elseif ($virt -eq '1') {
        $script:cpu_hypervisor = "Virtual"
    }

    $lavg = (Get-CommandOutput 'sysctl' @('-n', 'vm.loadavg') | Out-String).Trim()
    if ($lavg -match '([\d.]+)\s+([\d.]+)\s+([\d.]+)') {
        $script:load_avgs = @([double]$Matches[1], [double]$Matches[2], [double]$Matches[3])
    }

    $memTotal = 0L
    $ms = (Get-CommandOutput 'sysctl' @('-n', 'hw.memsize') | Out-String).Trim()
    try { $memTotal = [int64]$ms } catch { }
    $vm = Get-CommandOutput 'vm_stat'
    $page = 4096L
    $freePages = 0L
    foreach ($line in @($vm)) {
        if ($line -match 'page size of (\d+)') { $page = [int64]$Matches[1] }
        if ($line -match '^Pages free:\s+(\d+)') { $freePages += [int64]$Matches[1] }
        if ($line -match '^Pages speculative:\s+(\d+)') { $freePages += [int64]$Matches[1] }
        if ($line -match '^Pages inactive:\s+(\d+)') { $freePages += [int64]$Matches[1] }
    }
    if ($memTotal -gt 0) {
        $used = $memTotal - ($freePages * $page)
        Set-MemoryLine $used $memTotal
    }

    $swap = (Get-CommandOutput 'sysctl' @('-n', 'vm.swapusage') | Out-String)
    if ($swap -match 'total\s*=\s*([\d.]+)([KMGT])\s+used\s*=\s*([\d.]+)([KMGT])') {
        $mult = @{ K = 1KB; M = 1MB; G = 1GB; T = 1TB }
        $tot = [double]$Matches[1] * $mult[$Matches[2]]
        $usedSw = [double]$Matches[3] * $mult[$Matches[4]]
        if ($tot -gt 0) {
            $script:pagefile_label = "SWAP"
            $script:pagefile_line = "$(fmt2 ($usedSw / 1GB))/$(fmt2 ($tot / 1GB)) GiB"
            $script:pagefile_present = 1
        }
    }

    Set-UnixVolumes

    Set-NvidiaSmiGpus
    $sp = Get-CommandOutput 'system_profiler' @('SPDisplaysDataType')
    $chip = $null
    $vramGb = $null
    $pending = $null
    foreach ($line in @($sp)) {
        $t = $line.Trim()
        if ($t -match '^Chipset Model:\s+(.+)') { $chip = $Matches[1].Trim() }
        if ($t -match '^VRAM.*:\s+(\d+)\s*GB') { $vramGb = [double]$Matches[1] }
        if ($t -match '^Resolution:\s+(\d+)\s*x\s*(\d+)') {
            if ($pending -and $pending.Line) { Add-DisplayLine $pending.Line $pending.Primary }
            $pending = [pscustomobject]@{ Line = "$($Matches[1]) x $($Matches[2])"; Primary = $false }
            if ($t -match '@\s*([\d.]+)\s*Hz') {
                $pending.Line += " @ $([int][math]::Round([double]$Matches[1])) Hz"
            }
        }
        if ($pending -and $t -match 'UI Looks like:.*@\s*([\d.]+)\s*Hz') {
            if ($pending.Line -notmatch 'Hz') {
                $pending.Line += " @ $([int][math]::Round([double]$Matches[1])) Hz"
            }
        }
        if ($pending -and $t -match '^Main Display:\s+Yes') { $pending.Primary = $true }
    }
    if ($pending -and $pending.Line) { Add-DisplayLine $pending.Line $pending.Primary }
    if ($script:displays.Count -gt 1) {
        $script:displays = @($script:displays | Sort-Object { -not $_.Primary }, Line)
        $script:display_lines = @($script:displays | ForEach-Object { $_.Line })
    }

    if ($script:gpus.Count -eq 0 -and $chip) {
        $vramLine = ""
        $memTotal = 0.0
        if ($vramGb) {
            $memTotal = $vramGb * 1024.0
            $vramLine = "0.00/$(fmt2 $vramGb) GiB [0.00%]"
        }
        $script:gpus += [pscustomobject]@{
            Name = $chip; Driver = ""; MemUsed = 0; MemTotal = $memTotal; Util = 0
            VramLine = $vramLine; Thermals = ""; HasMeters = $false
        }
    }
    if ($script:gpus.Count -gt 0) { $script:gpu_present = 1 }

    $user = $env:USER
    if ($user) {
        $last = Get-CommandOutput 'last' @('-1', $user)
        $row = @($last | Select-Object -First 1)
        if ($row -and $row -notmatch '^wtmp') {
            if ($row -match '(\w{3}\s+\w{3}\s+\d+\s+\d+:\d+)') {
                $script:last_login_time = $Matches[1]
            }
        }
    }

    $boot = (Get-CommandOutput 'sysctl' @('-n', 'kern.boottime') | Out-String)
    if ($boot -match 'sec\s*=\s*(\d+)') {
        $script:sys_uptime = Format-Uptime ((([DateTimeOffset]::Now.ToUnixTimeSeconds()) - [int64]$Matches[1]))
    }

    $batt = Get-CommandOutput 'pmset' @('-g', 'batt')
    if ("$batt" -match "'([^']+)'") {
        $script:power_plan = $Matches[1]
        $script:power_present = 1
    }

    $sip = Get-CommandOutput 'csrutil' @('status')
    if ("$sip" -match 'enabled') { $script:secure_boot = "On"; $script:secure_boot_present = 1 }
    elseif ("$sip" -match 'disabled') { $script:secure_boot = "Off"; $script:secure_boot_present = 1 }
}

function Show-MachineReport {
    [CmdletBinding()]
    param()

    try {
        [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $false
    } catch {
    }

    Reset-ReportState
    $platform = Get-ReportPlatform
    if ($platform -eq 'Linux') {
        Collect-LinuxReport
    } elseif ($platform -eq 'macOS') {
        Collect-MacReport
    } else {

    # Kick nvidia-smi off while we do CIM/registry work
    $smiPath = Get-NvidiaSmiPath
    $smiProc = $null
    $smiOutFile = $null
    $smiErrFile = $null
    if ($smiPath) {
        $smiOutFile = [System.IO.Path]::GetTempFileName()
        $smiErrFile = [System.IO.Path]::GetTempFileName()
        try {
            $smiProc = Start-Process -FilePath $smiPath -ArgumentList @(
                "--query-gpu=name,driver_version,memory.total,memory.used,utilization.gpu,temperature.gpu,power.draw,power.limit,clocks.gr,fan.speed",
                "--format=csv,noheader,nounits"
            ) -NoNewWindow -PassThru -RedirectStandardOutput $smiOutFile -RedirectStandardError $smiErrFile
        } catch {
            $smiProc = $null
        }
    }

    # Operating system / kernel (registry is faster than Win32_OperatingSystem for the caption)
    $cv = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -ErrorAction SilentlyContinue
    $os = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction SilentlyContinue

    $os_caption = ""
    if ($os -and $os.Caption) {
        $os_caption = ($os.Caption -replace "^Microsoft ", "" -replace " Insider Preview", "").Trim()
    }
    if (-not $os_caption) { $os_caption = "Windows" }
    if ($cv -and $cv.DisplayVersion) {
        $script:os_name = "$os_caption $($cv.DisplayVersion)"
    } else {
        $script:os_name = $os_caption
    }

    $os_build = $null
    if ($os -and $os.Version) { $os_build = $os.Version }
    if ($cv -and $null -ne $cv.UBR -and $os_build) {
        $script:os_kernel = "Windows NT $os_build.$($cv.UBR)"
    } elseif ($os_build) {
        $script:os_kernel = "Windows NT $os_build"
    } else {
        $script:os_kernel = "Windows NT"
    }

    $board = Get-CimInstance -ClassName Win32_BaseBoard -ErrorAction SilentlyContinue
    if ($board -and $board.Product -and ($board.Product -notmatch "O\.E\.M\.|Default string|System Product|To be filled")) {
        $script:board_name = $board.Product.Trim()
        $script:board_present = 1
    }

    # Network
    $script:net_current_user = $env:USERNAME
    try {
        $script:net_current_user = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
    } catch {
    }
    if (-not $script:net_current_user) { $script:net_current_user = $env:USERNAME }

    $script:net_hostname = [System.Net.Dns]::GetHostName()
    if (-not $script:net_hostname) { $script:net_hostname = $env:COMPUTERNAME }
    if (-not $script:net_hostname) { $script:net_hostname = "Not Defined" }

    $script:net_machine_ip = "No IP found"
    $nics = @(Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled=TRUE" -ErrorAction SilentlyContinue)
    $primaryNic = $nics | Where-Object { $_.DefaultIPGateway -and @($_.DefaultIPGateway).Count -gt 0 } | Select-Object -First 1
    if (-not $primaryNic) { $primaryNic = $nics | Select-Object -First 1 }

    if ($primaryNic) {
        $ipv4 = @($primaryNic.IPAddress) | Where-Object { $_ -match '^\d+\.\d+\.\d+\.\d+$' -and $_ -notlike '169.254.*' } | Select-Object -First 1
        if ($ipv4) {
            $script:net_machine_ip = $ipv4
        } else {
            $ipv6 = @($primaryNic.IPAddress) | Where-Object { $_ -and $_ -notlike 'fe80*' } | Select-Object -First 1
            if ($ipv6) { $script:net_machine_ip = $ipv6 }
        }
        if ($primaryNic.DNSServerSearchOrder) {
            $script:net_dns_ip = @($primaryNic.DNSServerSearchOrder | Where-Object { $_ })
        }
        $nicName = $primaryNic.Description
        $nicSpeed = $null
        if ($primaryNic.SettingID) {
            $connPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\$($primaryNic.SettingID)\Connection"
            $conn = Get-ItemProperty -Path $connPath -ErrorAction SilentlyContinue
            if ($conn -and $conn.Name) { $nicName = $conn.Name }
        }
        try {
            $netAdp = Get-CimInstance -Namespace "root\StandardCimv2" -ClassName MSFT_NetAdapter -Filter "InterfaceIndex=$($primaryNic.InterfaceIndex)" -ErrorAction SilentlyContinue
            if ($netAdp) {
                if ($netAdp.Name) { $nicName = $netAdp.Name }
                if ($netAdp.TransmitLinkSpeed) { $nicSpeed = Format-LinkSpeed $netAdp.TransmitLinkSpeed }
                elseif ($netAdp.ReceiveLinkSpeed) { $nicSpeed = Format-LinkSpeed $netAdp.ReceiveLinkSpeed }
            }
        } catch {
        }
        if ($nicName) {
            if ($nicSpeed) { $script:nic_line = "$nicName $nicSpeed" } else { $script:nic_line = $nicName }
            $script:nic_present = 1
        }
    }

    $script:net_client_ip = "Not connected"
    if ($env:SSH_CLIENT) {
        $script:net_client_ip = ($env:SSH_CLIENT -split "\s+")[0]
    } elseif ($env:SESSIONNAME -match "^RDP") {
        $script:net_client_ip = "RDP"
    } elseif ($env:SESSIONNAME -eq "Console" -or -not $env:SESSIONNAME) {
        $script:net_client_ip = "Console"
    }

    # CPU: registry + ComputerSystem, skip Win32_Processor (it costs ~1s)
    $cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction SilentlyContinue
    $cpuReg = Get-ItemProperty -Path "HKLM:\HARDWARE\DESCRIPTION\System\CentralProcessor\0" -ErrorAction SilentlyContinue
    $script:cpu_model = "Unknown"
    if ($cpuReg -and $cpuReg.ProcessorNameString) {
        $script:cpu_model = ($cpuReg.ProcessorNameString -replace "\(R\)", "" -replace "\(TM\)", "" -replace "\(C\)", "" -replace "\s+", " ").Trim()
    }

    $cpu_threads = 0
    $cpu_sockets = 1
    if ($cs -and $cs.NumberOfLogicalProcessors) { $cpu_threads = [int]$cs.NumberOfLogicalProcessors }
    if ($cpu_threads -eq 0) {
        $cpu_threads = @(Get-ChildItem "HKLM:\HARDWARE\DESCRIPTION\System\CentralProcessor" -ErrorAction SilentlyContinue).Count
    }
    if ($cs -and $cs.NumberOfProcessors) { $cpu_sockets = [int]$cs.NumberOfProcessors }
    if ($cpu_sockets -gt 1) {
        $script:cpu_cores_line = "$cpu_threads Thread(s) / $cpu_sockets Socket(s)"
    } else {
        $script:cpu_cores_line = "$cpu_threads Thread(s)"
    }

    $script:cpu_hypervisor = "Bare Metal"
    if ($cs) {
        $mfg = [string]$cs.Manufacturer
        $model = [string]$cs.Model
        if ($model -match "Virtual Machine" -or ($mfg -match "^Microsoft" -and $model -match "Virtual")) {
            $script:cpu_hypervisor = "Hyper-V"
        } elseif ($mfg -match "VMware" -or $model -match "VMware") {
            $script:cpu_hypervisor = "VMware"
        } elseif ($mfg -match "innotek|Oracle" -or $model -match "VirtualBox") {
            $script:cpu_hypervisor = "VirtualBox"
        } elseif ($mfg -match "QEMU|Bochs|Xen|Parallels|Google|Amazon|OpenStack") {
            $script:cpu_hypervisor = $mfg.Trim()
        } elseif ($env:WSL_DISTRO_NAME) {
            $script:cpu_hypervisor = "WSL"
        }
    }

    $script:cpu_freq = "0.00"
    if ($cpuReg -and $cpuReg."~MHz") {
        $script:cpu_freq = fmt2 ([double]$cpuReg."~MHz" / 1000.0)
        $script:cpu_freq_present = 1
    }

    $script:cpu_load = 0.0
    try {
        $cpu_perf = Get-CimInstance -ClassName Win32_PerfFormattedData_PerfOS_Processor -Filter "Name='_Total'" -ErrorAction SilentlyContinue
        if ($cpu_perf -and $null -ne $cpu_perf.PercentProcessorTime) {
            $script:cpu_load = [double]$cpu_perf.PercentProcessorTime
        }
    } catch {
    }

    # Memory (CIM values are kibibytes)
    $mem_total_ki = 0
    $mem_free_ki = 0
    if ($os) {
        $mem_total_ki = [int64]$os.TotalVisibleMemorySize
        $mem_free_ki = [int64]$os.FreePhysicalMemory
    }
    Set-MemoryLine (($mem_total_ki - $mem_free_ki) * 1024L) ($mem_total_ki * 1024L)

    $pf = @(Get-CimInstance -ClassName Win32_PageFileUsage -ErrorAction SilentlyContinue)
    if ($pf.Count -gt 0) {
        $pf_used = ($pf | Measure-Object -Property CurrentUsage -Sum).Sum
        $pf_total = ($pf | Measure-Object -Property AllocatedBaseSize -Sum).Sum
        if ($pf_total -gt 0) {
            $script:pagefile_line = "$(fmt2 ($pf_used / 1024.0))/$(fmt2 ($pf_total / 1024.0)) GiB"
            $script:pagefile_present = 1
        }
    }

    # Disks
    $disks = @(Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" -ErrorAction SilentlyContinue)
    foreach ($d in $disks) {
        if (-not $d.Size -or [int64]$d.Size -le 0) { continue }
        $used = [int64]$d.Size - [int64]$d.FreeSpace
        if ($used -lt 0) { $used = 0 }
        $id = ([string]$d.DeviceID).TrimEnd(":")
        $used_gb = fmt2 ($used / 1GB)
        $total_gb = fmt2 ([int64]$d.Size / 1GB)
        $pct = fmt2 (($used / [int64]$d.Size) * 100.0)
        $line = "$used_gb/$total_gb GB [$pct%]"
        $script:volumes += [pscustomobject]@{ Id = $id; Used = $used; Total = [int64]$d.Size; Line = $line }
        $script:volume_lines += $line
    }

    try {
        $pd = @(Get-CimInstance -Namespace "root\microsoft\windows\storage" -ClassName MSFT_PhysicalDisk -ErrorAction SilentlyContinue)
        if ($pd.Count -gt 0) {
            $ssd = @($pd | Where-Object { $_.MediaType -eq 4 }).Count
            $hdd = @($pd | Where-Object { $_.MediaType -eq 3 }).Count
            $scm = @($pd | Where-Object { $_.MediaType -eq 5 }).Count
            $bits = @()
            if ($ssd -gt 0) { $bits += "$ssd SSD" }
            if ($hdd -gt 0) { $bits += "$hdd HDD" }
            if ($scm -gt 0) { $bits += "$scm SCM" }
            if ($bits.Count -eq 0) { $bits += "$($pd.Count) DISK" }
            $unhealthy = @($pd | Where-Object { $null -ne $_.HealthStatus -and $_.HealthStatus -ne 0 })
            if ($unhealthy.Count -gt 0) {
                $script:storage_health = "$($bits -join ' / ') DEGRADED"
            } else {
                $script:storage_health = "$($bits -join ' / ') HEALTH O.K."
            }
            $script:storage_present = 1
        }
    } catch {
    }

    # GPU from nvidia-smi (started earlier)
    if ($smiProc) {
        try { $null = $smiProc.WaitForExit(3000) } catch { }
        $smi_out = $null
        if (Test-Path -LiteralPath $smiOutFile) {
            $smi_out = Get-Content -LiteralPath $smiOutFile -ErrorAction SilentlyContinue
        }
        if ($smiOutFile) { Remove-Item -LiteralPath $smiOutFile -Force -ErrorAction SilentlyContinue }
        if ($smiErrFile) { Remove-Item -LiteralPath $smiErrFile -Force -ErrorAction SilentlyContinue }

        if ($smi_out) {
            foreach ($row in @($smi_out)) {
                if (-not $row) { continue }
                $parts = @($row -split "," | ForEach-Object { $_.Trim() })
                if ($parts.Count -lt 5) { continue }
                if (Test-VirtualGpuName $parts[0]) { continue }

                $mem_total_mib = 0.0
                $mem_used_mib = 0.0
                $util = 0.0
                try { $mem_total_mib = [double]$parts[2] } catch { }
                try { $mem_used_mib = [double]$parts[3] } catch { }
                try { $util = [double]$parts[4] } catch { }

                $vram_pct = "0.00"
                if ($mem_total_mib -gt 0) { $vram_pct = fmt2 (($mem_used_mib / $mem_total_mib) * 100.0) }
                $vram_line = "$(fmt2 ($mem_used_mib / 1024.0))/$(fmt2 ($mem_total_mib / 1024.0)) GiB [$vram_pct%]"

                $thermo = @()
                if ($parts.Count -gt 5 -and $parts[5] -notmatch "N/A|^$") { $thermo += "$($parts[5]) C" }
                if ($parts.Count -gt 7 -and $parts[6] -notmatch "N/A|^$" -and $parts[7] -notmatch "N/A|^$") {
                    $pwr = [int][math]::Round([double]$parts[6])
                    $cap = [int][math]::Round([double]$parts[7])
                    $thermo += "$pwr/$cap W"
                } elseif ($parts.Count -gt 6 -and $parts[6] -notmatch "N/A|^$") {
                    $pwr = [int][math]::Round([double]$parts[6])
                    $thermo += "$pwr W"
                }
                if ($parts.Count -gt 8 -and $parts[8] -notmatch "N/A|^$") {
                    $clk = [int][math]::Round([double]$parts[8])
                    $thermo += "$clk MHz"
                }

                $script:gpus += [pscustomobject]@{
                    Name      = $parts[0]
                    Driver    = $parts[1]
                    MemUsed   = $mem_used_mib
                    MemTotal  = $mem_total_mib
                    Util      = $util
                    VramLine  = $vram_line
                    Thermals  = ($thermo -join " ")
                    HasMeters = $true
                }
            }
        }
    }

    if ($script:gpus.Count -eq 0) {
        $vc = @(Get-CimInstance -ClassName Win32_VideoController -ErrorAction SilentlyContinue)
        $reg_vram = @{}
        try {
            $keys = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0*" -ErrorAction SilentlyContinue
            foreach ($k in @($keys)) {
                $as = $k."HardwareInformation.AdapterString"
                $qw = $k."HardwareInformation.qwMemorySize"
                if ($as -and $qw) { $reg_vram[$as] = [int64]$qw }
            }
        } catch {
        }
        foreach ($g in $vc) {
            if (-not $g.Name) { continue }
            if (Test-VirtualGpuName $g.Name) { continue }
            if ($g.Status -and $g.Status -ne "OK") { continue }
            $total_bytes = 0
            if ($reg_vram.ContainsKey($g.Name)) { $total_bytes = [int64]$reg_vram[$g.Name] }
            elseif ($g.AdapterRAM -and [int64]$g.AdapterRAM -gt 0) { $total_bytes = [int64]$g.AdapterRAM }
            $mem_total_mib = 0.0
            $vram_line = ""
            if ($total_bytes -gt 0) {
                $mem_total_mib = $total_bytes / 1MB
                $vram_line = "0.00/$(fmt2 ($mem_total_mib / 1024.0)) GiB [0.00%]"
            }
            $script:gpus += [pscustomobject]@{
                Name      = $g.Name
                Driver    = $g.DriverVersion
                MemUsed   = 0.0
                MemTotal  = $mem_total_mib
                Util      = 0.0
                VramLine  = $vram_line
                Thermals  = ""
                HasMeters = $false
            }
        }
    }

    if ($script:gpus.Count -gt 0) { $script:gpu_present = 1 }

    # Displays: every attached monitor, native pixels + refresh
    if (Initialize-NativeDisplays) {
        try {
            $raw = [NativeDisplays]::GetAll()
            foreach ($d in @($raw)) {
                if (-not $d.Width -or -not $d.Height) { continue }
                $vendor = Get-MonitorVendor $d.HardwareId
                $line = "$($d.Width) x $($d.Height)"
                if ($d.Frequency -gt 1) { $line += " @ $($d.Frequency) Hz" }
                if ($vendor) { $line = "$vendor $line" }
                Add-DisplayLine $line ([bool]$d.Primary)
            }
        } catch {
        }
    }
    if ($script:displays.Count -gt 1) {
        $script:displays = @($script:displays | Sort-Object { -not $_.Primary }, Line)
        $script:display_lines = @($script:displays | ForEach-Object { $_.Line })
    }

    # Last login / uptime / power / Secure Boot
    $script:last_login_time = "Unknown"
    try {
        $q = quser 2>$null
        $cur = @($q | Where-Object { $_ -match "^\s*>" } | Select-Object -First 1)
        if ($cur -and $cur[0] -match "(\d{1,2}/\d{1,2}/\d{4}\s+\d{1,2}:\d{2}(?:\s*[AP]M)?)") {
            $dt = [datetime]::Parse($Matches[1])
            $script:last_login_time = $dt.ToString("MMM dd yyyy HH:mm", $script:Invariant)
        }
    } catch {
    }

    if ($os -and $os.LastBootUpTime) {
        $td = (Get-Date) - [datetime]$os.LastBootUpTime
        $parts = @()
        if ($td.Days -gt 0) { $parts += "$($td.Days) d" }
        if ($td.Hours -gt 0) { $parts += "$($td.Hours) h" }
        $parts += "$($td.Minutes) m"
        $script:sys_uptime = $parts -join ", "
    } else {
        $script:sys_uptime = "Unknown"
    }

    try {
        $schemeGuid = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes" -ErrorAction SilentlyContinue).ActivePowerScheme
        if ($schemeGuid) {
            $friendly = $null
            $scheme = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes\$schemeGuid" -ErrorAction SilentlyContinue
            if ($scheme -and $scheme.FriendlyName -match ',([^,]+)$') { $friendly = $Matches[1].Trim() }
            if (-not $friendly) {
                switch ($schemeGuid.ToLower()) {
                    '381b4222-f694-41f0-9685-ff5bb260df2e' { $friendly = 'Balanced' }
                    '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c' { $friendly = 'High performance' }
                    'a1841308-3541-4fab-bc81-f71556f20b4a' { $friendly = 'Power saver' }
                    'e9a42b02-d5df-448d-aa00-03f14749eb61' { $friendly = 'Ultimate Performance' }
                }
            }
            if ($friendly) {
                $script:power_plan = $friendly
                $script:power_present = 1
            }
        }
    } catch {
    }

    try {
        $sb = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecureBoot\State" -ErrorAction SilentlyContinue
        if ($sb -and $sb.PSObject.Properties.Name -contains "UEFISecureBootEnabled") {
            if ([int]$sb.UEFISecureBootEnabled -eq 1) { $script:secure_boot = "On" } else { $script:secure_boot = "Off" }
            $script:secure_boot_present = 1
        }
    } catch {
    }

    } # Windows collection

    set_current_len

    $cpu_load_bar_graph = bar_graph $script:cpu_load 100
    $load_1_graph = $null
    $load_5_graph = $null
    $load_15_graph = $null
    if ($script:load_avgs -and $script:load_avgs.Count -ge 3) {
        $load_1_graph = bar_graph $script:load_avgs[0] $script:load_cpus
        $load_5_graph = bar_graph $script:load_avgs[1] $script:load_cpus
        $load_15_graph = bar_graph $script:load_avgs[2] $script:load_cpus
    }
    $mem_bar_graph = bar_graph $script:mem_used $script:mem_total

    $vol_graphs = @{}
    foreach ($v in $script:volumes) {
        $vol_graphs[$v.Id] = bar_graph $v.Used $v.Total
    }
    foreach ($g in $script:gpus) {
        $g | Add-Member -NotePropertyName MemGraph -NotePropertyValue (bar_graph $g.MemUsed $g.MemTotal) -Force
        $g | Add-Member -NotePropertyName UtilGraph -NotePropertyValue (bar_graph $g.Util 100) -Force
    }

    # Machine Report
    PRINT_HEADER
    PRINT_CENTERED_DATA $script:report_title
    PRINT_CENTERED_DATA "TR-100 MACHINE REPORT"
    PRINT_DIVIDER "top"
    PRINT_DATA "OS" $script:os_name
    PRINT_DATA "KERNEL" $script:os_kernel
    if ($script:board_present -eq 1) {
        PRINT_DATA "BOARD" $script:board_name
    }
    PRINT_DIVIDER
    PRINT_DATA "HOSTNAME" $script:net_hostname
    PRINT_DATA "MACHINE IP" $script:net_machine_ip
    PRINT_DATA "CLIENT IP" $script:net_client_ip

    $dns_num = 1
    foreach ($dns in $script:net_dns_ip) {
        PRINT_DATA "DNS IP $dns_num" $dns
        $dns_num++
    }

    if ($script:nic_present -eq 1) {
        PRINT_DATA "NIC" $script:nic_line
    }
    PRINT_DATA "USER" $script:net_current_user
    PRINT_DIVIDER
    PRINT_DATA "PROCESSOR" $script:cpu_model
    PRINT_DATA "CORES" $script:cpu_cores_line
    PRINT_DATA "HYPERVISOR" $script:cpu_hypervisor
    if ($script:cpu_freq_present -eq 1) {
        PRINT_DATA "CPU FREQ" "$($script:cpu_freq) GHz"
    }
    if ($load_1_graph) {
        PRINT_DATA "LOAD 1m" $load_1_graph
        PRINT_DATA "LOAD 5m" $load_5_graph
        PRINT_DATA "LOAD 15m" $load_15_graph
    } else {
        PRINT_DATA "CPU LOAD" $cpu_load_bar_graph
    }
    if ($script:display_present -eq 1) {
        if ($script:displays.Count -eq 1) {
            PRINT_DATA "DISPLAY" $script:displays[0].Line
        } else {
            $n = 1
            foreach ($d in $script:displays) {
                PRINT_DATA "DISPLAY $n" $d.Line
                $n++
            }
        }
    }

    if ($script:gpu_present -eq 1) {
        PRINT_DIVIDER
        $gi = 0
        foreach ($g in $script:gpus) {
            $label = "GRAPHICS"
            $vram_label = "VRAM"
            $mem_label = "GPU MEMORY"
            $load_label = "GPU LOAD"
            if ($script:gpus.Count -gt 1) {
                $label = "GRAPHICS $gi"
                $vram_label = "VRAM $gi"
                $mem_label = "GPU MEM $gi"
                $load_label = "GPU LOAD$gi"
            }
            PRINT_DATA $label $g.Name
            if ($g.Driver) {
                $drv_label = if ($script:gpus.Count -gt 1) { "DRIVER $gi" } else { "DRIVER" }
                PRINT_DATA $drv_label $g.Driver
            }
            if ($g.VramLine) {
                PRINT_DATA $vram_label $g.VramLine
                if ($g.HasMeters) { PRINT_DATA $mem_label $g.MemGraph }
            }
            if ($g.HasMeters) {
                PRINT_DATA $load_label $g.UtilGraph
            }
            if ($g.Thermals) {
                $th_label = if ($script:gpus.Count -gt 1) { "THERMALS$gi" } else { "THERMALS" }
                PRINT_DATA $th_label $g.Thermals
            }
            $gi++
        }
    }

    if ($script:volumes.Count -gt 0) {
        PRINT_DIVIDER
        foreach ($v in $script:volumes) {
            PRINT_DATA (Get-VolumePrintName $v.Id) $v.Line
            PRINT_DATA (Get-UsagePrintName $v.Id) $vol_graphs[$v.Id]
        }
        if ($script:storage_present -eq 1) {
            PRINT_DATA "STORAGE" $script:storage_health
        }
    }

    PRINT_DIVIDER
    PRINT_DATA "MEMORY" $script:mem_line
    PRINT_DATA "USAGE" $mem_bar_graph
    if ($script:pagefile_present -eq 1) {
        PRINT_DATA $script:pagefile_label $script:pagefile_line
    }
    PRINT_DIVIDER
    PRINT_DATA "LAST LOGIN" $script:last_login_time
    PRINT_DATA "UPTIME" $script:sys_uptime
    if ($script:power_present -eq 1) {
        PRINT_DATA "POWER" $script:power_plan
    }
    if ($script:secure_boot_present -eq 1) {
        PRINT_DATA "SECURE BOOT" $script:secure_boot
    }
    PRINT_DIVIDER "bottom"
}

New-Alias -Name machine-report -Value Show-MachineReport -Force -ErrorAction SilentlyContinue
Export-ModuleMember -Function Show-MachineReport -Alias machine-report