USGC.MachineReport.psm1
|
#Requires -Version 5.1 # TR-100 Machine Report (PowerShell) # Copyright © 2024, U.S. Graphics, LLC. BSD-3-Clause License. # Windows 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 -ge $script:MAX_DATA_LEN -or $data_len -eq ($script:MAX_DATA_LEN - 1)) { $cut = $script:MAX_DATA_LEN - 5 if ($cut -lt 1) { $cut = 1 } if ($data.Length -gt $cut) { $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-NvidiaSmiPath { $cmd = Get-Command "nvidia-smi" -ErrorAction SilentlyContinue if ($cmd) { return $cmd.Source } $candidates = @( (Join-Path $env:SystemRoot "System32\nvidia-smi.exe"), (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 Show-MachineReport { [CmdletBinding()] param() try { [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding $false } catch { } $gpu_present = 0 $board_present = 0 $display_present = 0 $nic_present = 0 $storage_present = 0 $secure_boot_present = 0 $power_present = 0 $pagefile_present = 0 $script:gpus = @() $script:volume_lines = @() $script:display_lines = @() $script:net_dns_ip = @() $script:board_name = "" $script:nic_line = "" $script:pagefile_line = "" $script:storage_health = "" $script:power_plan = "" $script:secure_boot = "" $script:last_login_ip = "" $script:display_line = "" # 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() $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 } $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) } $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) { $cpu_load = [double]$cpu_perf.PercentProcessorTime } } catch { } # Memory $mem_total = 0 $mem_free = 0 if ($os) { $mem_total = [int64]$os.TotalVisibleMemorySize $mem_free = [int64]$os.FreePhysicalMemory } $mem_used = $mem_total - $mem_free if ($mem_used -lt 0) { $mem_used = 0 } $mem_percent = "0.00" if ($mem_total -gt 0) { $mem_percent = fmt2 (($mem_used / $mem_total) * 100.0) } $mem_total_gb = fmt2 ($mem_total / (1024.0 * 1024.0)) $mem_used_gb = fmt2 ($mem_used / (1024.0 * 1024.0)) $script:mem_line = "$mem_used_gb/$mem_total_gb GiB [$mem_percent%]" $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" $pagefile_present = 1 } } # Disks $volumes = @() $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%]" $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." } $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 " ") } } } } 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 = "" } } } if ($script:gpus.Count -gt 0) { $gpu_present = 1 } # Displays — every attached monitor, native pixels + refresh $displays = @() 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" } $displays += [pscustomobject]@{ Primary = [bool]$d.Primary Line = $line } } } catch { } } if ($displays.Count -gt 1) { $displays = @($displays | Sort-Object { -not $_.Primary }, Line) } foreach ($d in $displays) { $script:display_lines += $d.Line } if ($displays.Count -gt 0) { $display_present = 1 } # 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 $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" } $secure_boot_present = 1 } } catch { } set_current_len $cpu_load_bar_graph = bar_graph $cpu_load 100 $mem_bar_graph = bar_graph $mem_used $mem_total $vol_graphs = @{} foreach ($v in $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 ($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 ($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 PRINT_DATA "CPU FREQ" "$($script:cpu_freq) GHz" PRINT_DATA "CPU LOAD" $cpu_load_bar_graph if ($display_present -eq 1) { if ($displays.Count -eq 1) { PRINT_DATA "DISPLAY" $displays[0].Line } else { $n = 1 foreach ($d in $displays) { PRINT_DATA "DISPLAY $n" $d.Line $n++ } } } if ($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 PRINT_DATA $mem_label $g.MemGraph } 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 ($volumes.Count -gt 0) { PRINT_DIVIDER foreach ($v in $volumes) { PRINT_DATA "VOLUME $($v.Id):" $v.Line PRINT_DATA "USAGE $($v.Id):" $vol_graphs[$v.Id] } if ($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 ($pagefile_present -eq 1) { PRINT_DATA "PAGEFILE" $script:pagefile_line } PRINT_DIVIDER PRINT_DATA "LAST LOGIN" $script:last_login_time PRINT_DATA "UPTIME" $script:sys_uptime if ($power_present -eq 1) { PRINT_DATA "POWER" $script:power_plan } if ($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 |