<# Which UPS - hardware scan ------------------------- Reads ONLY the hardware list needed to estimate power usage: processor, graphics cards, memory size, disks, monitors and whether this is a laptop. It does NOT read files, user names, serial numbers, network details or anything personal. Nothing is sent over the internet. The result is shown on screen, saved to your Desktop as which-ups-scan.json and copied to the clipboard, so you can paste it into the site. #> $ErrorActionPreference = 'SilentlyContinue' function Get-Cim($class, $ns = 'root\cimv2') { try { Get-CimInstance -ClassName $class -Namespace $ns -ErrorAction Stop } catch { @() } } function Decode-Edid($arr) { if (-not $arr) { return '' } (($arr | Where-Object { $_ -ne 0 } | ForEach-Object { [char]$_ }) -join '').Trim() } Write-Host '' Write-Host ' Which UPS - hardware scan' -ForegroundColor Cyan Write-Host ' Reading hardware information (nothing leaves this computer)...' Write-Host '' # Chassis: laptop or desktop $laptopTypes = 8, 9, 10, 11, 12, 14, 18, 21, 30, 31, 32 $chassisTypes = @((Get-Cim Win32_SystemEnclosure).ChassisTypes) $hasBattery = [bool](Get-Cim Win32_Battery) $isLaptop = $hasBattery -or ($chassisTypes | Where-Object { $laptopTypes -contains $_ }) $chassis = if ($isLaptop) { 'laptop' } elseif ($chassisTypes.Count) { 'desktop' } else { 'unknown' } $cpu = @(Get-Cim Win32_Processor | ForEach-Object { [ordered]@{ name = ($_.Name -replace '\s+', ' ').Trim(); cores = $_.NumberOfCores } }) $gpu = @(Get-Cim Win32_VideoController | Where-Object { $_.Name } | ForEach-Object { [ordered]@{ name = $_.Name.Trim(); width = $_.CurrentHorizontalResolution; hz = $_.CurrentRefreshRate } }) $mods = @(Get-Cim Win32_PhysicalMemory) $totalBytes = ($mods | Measure-Object -Property Capacity -Sum).Sum $ddr = switch (($mods | Select-Object -First 1).SMBIOSMemoryType) { 26 { 'DDR4' } 34 { 'DDR5' } 24 { 'DDR3' } default { '' } } $memory = [ordered]@{ totalGB = [math]::Round($totalBytes / 1GB); modules = $mods.Count; type = $ddr } $disks = @() $pd = @(Get-Cim MSFT_PhysicalDisk 'root\Microsoft\Windows\Storage') if ($pd.Count) { $busMap = @{ 1 = 'SCSI'; 3 = 'ATA'; 7 = 'USB'; 8 = 'RAID'; 11 = 'SATA'; 12 = 'SD'; 13 = 'MMC'; 15 = 'File Backed Virtual'; 17 = 'NVMe' } $mediaMap = @{ 3 = 'HDD'; 4 = 'SSD'; 5 = 'SCM' } $disks = @($pd | ForEach-Object { [ordered]@{ model = ($_.FriendlyName -replace '\s+', ' ').Trim() media = $(if ($mediaMap.ContainsKey([int]$_.MediaType)) { $mediaMap[[int]$_.MediaType] } else { 'Unspecified' }) bus = $(if ($busMap.ContainsKey([int]$_.BusType)) { $busMap[[int]$_.BusType] } else { 'Other' }) sizeGB = [math]::Round($_.Size / 1GB) } }) } else { $disks = @(Get-Cim Win32_DiskDrive | ForEach-Object { [ordered]@{ model = $_.Model.Trim(); media = 'Unspecified'; bus = $_.InterfaceType; sizeGB = [math]::Round($_.Size / 1GB) } }) } # Monitors: model name from EDID + physical size -> diagonal in inches $ids = @(Get-Cim WmiMonitorID 'root\wmi') $params = @(Get-Cim WmiMonitorBasicDisplayParams 'root\wmi') $conn = @(Get-Cim WmiMonitorConnectionParams 'root\wmi') $monitors = @($ids | ForEach-Object { $inst = $_.InstanceName $p = $params | Where-Object { $_.InstanceName -eq $inst } | Select-Object -First 1 $c = $conn | Where-Object { $_.InstanceName -eq $inst } | Select-Object -First 1 $diag = $null if ($p -and $p.MaxHorizontalImageSize -gt 0) { $diag = [math]::Round([math]::Sqrt([math]::Pow($p.MaxHorizontalImageSize, 2) + [math]::Pow($p.MaxVerticalImageSize, 2)) / 2.54, 1) } # VideoOutputTechnology: 11 = internal (laptop panel), 0x80000000 = internal $internal = $c -and ($c.VideoOutputTechnology -eq 11 -or $c.VideoOutputTechnology -eq 2147483648 -or $c.VideoOutputTechnology -eq -2147483648) [ordered]@{ manufacturer = Decode-Edid $_.ManufacturerName name = Decode-Edid $_.UserFriendlyName diagonalIn = $diag internal = [bool]$internal } }) if ($gpu.Count -and $monitors.Count -eq 1) { $monitors[0].width = $gpu[0].width $monitors[0].hz = $gpu[0].hz } $result = [ordered]@{ tool = 'which-ups-scan' version = 1 chassis = $chassis cpu = $cpu gpu = @($gpu | ForEach-Object { [ordered]@{ name = $_.name } }) memory = $memory disks = $disks monitors = $monitors } $json = $result | ConvertTo-Json -Depth 5 -Compress Write-Host ' Found:' -ForegroundColor Green $cpu | ForEach-Object { Write-Host (' CPU: ' + $_.name) } $gpu | ForEach-Object { Write-Host (' GPU: ' + $_.name) } Write-Host (' Memory: ' + $memory.totalGB + ' GB (' + $memory.modules + ' modules) ' + $memory.type) $disks | ForEach-Object { Write-Host (' Disk: ' + $_.model + ' [' + $_.media + ', ' + $_.bus + ']') } $monitors | ForEach-Object { Write-Host (' Monitor: ' + $_.name + $(if ($_.diagonalIn) { ' (' + $_.diagonalIn + '")' } else { '' })) } Write-Host (' Type: ' + $chassis) Write-Host '' $desktop = [Environment]::GetFolderPath('Desktop') $out = Join-Path $desktop 'which-ups-scan.json' [IO.File]::WriteAllText($out, $json, (New-Object Text.UTF8Encoding $false)) $copied = $false try { Set-Clipboard -Value $json; $copied = $true } catch {} Write-Host (' Saved to: ' + $out) -ForegroundColor Cyan if ($copied) { Write-Host ' The result was also copied to your clipboard - just paste it on the website (Ctrl+V).' -ForegroundColor Cyan } Write-Host '' Write-Host ' Exact data that was collected:' -ForegroundColor DarkGray Write-Host (' ' + $json) -ForegroundColor DarkGray Write-Host ''