# Creates: Desktop\run_benchmarks.ps1 # Then run: powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\Desktop\run_benchmarks.ps1" $desktop = [Environment]::GetFolderPath('Desktop') $scriptPath = Join-Path $desktop 'run_benchmarks.ps1' $script = @' Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' function Test-IsAdmin { $id = [Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object Security.Principal.WindowsPrincipal($id) return $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } # ---- IMPORTANT: UAC elevation without a prompt is not reliably possible. # If this shell is not already Admin, we will SKIP Chocolatey installs and continue with built-in tests. $IsAdmin = Test-IsAdmin $Desktop = [Environment]::GetFolderPath('Desktop') $Stamp = Get-Date -Format 'yyyyMMdd_HHmmss' $OutDir = Join-Path $Desktop "BenchResults_$Stamp" New-Item -ItemType Directory -Path $OutDir -Force | Out-Null function Out-FileUtf8([string]$Path, [string]$Text) { $Text | Set-Content -Path $Path -Encoding UTF8 } function Run-CmdToFile([string]$Title, [string]$Cmd, [string]$OutFile) { $full = Join-Path $OutDir $OutFile $header = @( "==== $Title ====" "Timestamp: $(Get-Date -Format o)" "Computer: $env:COMPUTERNAME" "User: $env:USERNAME" "IsAdmin: $IsAdmin" "Command: $Cmd" "================" "" ) -join "`r`n" $header | Set-Content -Path $full -Encoding UTF8 try { cmd.exe /c "$Cmd" 2>&1 | Add-Content -Path $full -Encoding UTF8 } catch { "`r`nERROR: $($_.Exception.Message)`r`n" | Add-Content -Path $full -Encoding UTF8 } } function Try-ChocoInstall([string[]]$Pkgs, [string]$OutFile) { $full = Join-Path $OutDir $OutFile $lines = @( "==== Chocolatey Install ====" "Timestamp: $(Get-Date -Format o)" "IsAdmin: $IsAdmin" "Packages: $($Pkgs -join ', ')" "============================" "" ) $lines | Set-Content -Path $full -Encoding UTF8 if (-not $IsAdmin) { "SKIPPED: Not running as Administrator. Chocolatey installs typically require elevation." | Add-Content -Path $full -Encoding UTF8 return } foreach ($p in $Pkgs) { "---- Installing: $p ----" | Add-Content -Path $full -Encoding UTF8 try { & choco install -y $p --no-progress 2>&1 | Add-Content -Path $full -Encoding UTF8 } catch { "ERROR installing $p : $($_.Exception.Message)" | Add-Content -Path $full -Encoding UTF8 } "" | Add-Content -Path $full -Encoding UTF8 } } # ========================= # 0) Baseline snapshot # ========================= try { $sys = Join-Path $OutDir "00_system_snapshot.txt" $content = New-Object System.Text.StringBuilder $null = $content.AppendLine("Timestamp: $(Get-Date -Format o)") $null = $content.AppendLine("IsAdmin: $IsAdmin") $null = $content.AppendLine("") $null = $content.AppendLine("== ComputerInfo (high level) ==") try { $ci = Get-ComputerInfo $null = $content.AppendLine(($ci | Out-String)) } catch { $null = $content.AppendLine("Get-ComputerInfo failed: $($_.Exception.Message)") } $null = $content.AppendLine("") $null = $content.AppendLine("== CPU ==") $null = $content.AppendLine((Get-CimInstance Win32_Processor | Select-Object Name,NumberOfCores,NumberOfLogicalProcessors,MaxClockSpeed,CurrentClockSpeed | Format-List | Out-String)) $null = $content.AppendLine("== Memory ==") $null = $content.AppendLine((Get-CimInstance Win32_ComputerSystem | Select-Object TotalPhysicalMemory | Format-List | Out-String)) $null = $content.AppendLine("== Disks ==") $null = $content.AppendLine((Get-CimInstance Win32_DiskDrive | Select-Object Model,InterfaceType,MediaType,Size | Format-Table -AutoSize | Out-String)) $null = $content.AppendLine("== OS ==") $null = $content.AppendLine((Get-CimInstance Win32_OperatingSystem | Select-Object Caption,Version,BuildNumber,LastBootUpTime | Format-List | Out-String)) Out-FileUtf8 $sys $content.ToString() } catch { Out-FileUtf8 (Join-Path $OutDir "00_system_snapshot_ERROR.txt") $_.Exception.Message } # Top processes (CPU and RAM) try { Get-Process | Select-Object Name,Id,CPU,WorkingSet,StartTime -ErrorAction SilentlyContinue | Sort-Object CPU -Descending | Select-Object -First 30 | Export-Csv -NoTypeInformation -Encoding UTF8 -Path (Join-Path $OutDir "01_top_processes_by_cpu.csv") } catch {} try { Get-Process | Select-Object Name,Id,CPU,WorkingSet,StartTime -ErrorAction SilentlyContinue | Sort-Object WorkingSet -Descending | Select-Object -First 30 | Export-Csv -NoTypeInformation -Encoding UTF8 -Path (Join-Path $OutDir "02_top_processes_by_ram.csv") } catch {} # Power plan Run-CmdToFile "Power plan and throttling-related settings" "powercfg /getactivescheme & echo. & powercfg /qh" "03_powercfg.txt" # ========================= # 1) Install tools via Chocolatey (if admin) # ========================= Try-ChocoInstall @( "7zip", "diskspd", "smartmontools" ) "10_choco_install.txt" # ========================= # 2) SMART / disk health # ========================= # Uses smartctl if installed. try { $smartOut = Join-Path $OutDir "20_smartctl.txt" "Timestamp: $(Get-Date -Format o)`r`nIsAdmin: $IsAdmin`r`n" | Set-Content -Path $smartOut -Encoding UTF8 $smartctl = Get-Command smartctl.exe -ErrorAction SilentlyContinue if (-not $smartctl) { "smartctl.exe not found (smartmontools not installed or install failed)." | Add-Content -Path $smartOut -Encoding UTF8 } else { "== smartctl --scan-open ==" | Add-Content -Path $smartOut -Encoding UTF8 $scan = & smartctl --scan-open 2>&1 $scan | Add-Content -Path $smartOut -Encoding UTF8 # Parse device paths: first token per line like \\.\PhysicalDrive0 $devs = @() foreach ($line in $scan) { if ($line -match '^(\\\\\.\\PhysicalDrive\d+)') { $devs += $Matches[1] } } $devs = $devs | Select-Object -Unique foreach ($d in $devs) { "" | Add-Content -Path $smartOut -Encoding UTF8 "== smartctl -a $d ==" | Add-Content -Path $smartOut -Encoding UTF8 try { & smartctl -a $d 2>&1 | Add-Content -Path $smartOut -Encoding UTF8 } catch { "ERROR running smartctl on $d : $($_.Exception.Message)" | Add-Content -Path $smartOut -Encoding UTF8 } } } } catch { Out-FileUtf8 (Join-Path $OutDir "20_smartctl_ERROR.txt") $_.Exception.Message } # ========================= # 3) Built-in Windows benchmark (WinSAT) # ========================= # Note: Some WinSAT modes may require elevation; we'll still attempt and record output. Run-CmdToFile "WinSAT CPU" "winsat cpu -v" "30_winsat_cpu.txt" Run-CmdToFile "WinSAT Disk (C:)" "winsat disk -drive c -seq -read -v & echo. & winsat disk -drive c -seq -write -v & echo. & winsat disk -drive c -ran -read -v & echo. & winsat disk -drive c -ran -write -v" "31_winsat_disk_c.txt" # ========================= # 4) 7-Zip benchmark (CPU-ish) # ========================= try { $sevenZip = @( (Join-Path $env:ProgramFiles '7-Zip\7z.exe'), (Join-Path ${env:ProgramFiles(x86)} '7-Zip\7z.exe'), (Get-Command 7z.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source -ErrorAction SilentlyContinue) ) | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1 if ($sevenZip) { Run-CmdToFile "7-Zip benchmark" "`"$sevenZip`" b -mmt=on" "40_7zip_benchmark.txt" } else { Out-FileUtf8 (Join-Path $OutDir "40_7zip_benchmark.txt") "7-Zip not found (install may have failed)." } } catch { Out-FileUtf8 (Join-Path $OutDir "40_7zip_benchmark_ERROR.txt") $_.Exception.Message } # ========================= # 5) DiskSpd benchmark (more reliable than GUI tools remotely) # ========================= try { $diskspd = @( (Get-Command diskspd.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source -ErrorAction SilentlyContinue), (Join-Path $env:ProgramData 'chocolatey\bin\diskspd.exe') ) | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1 $testFile = "C:\bench_diskspd_$Stamp.dat" if ($diskspd) { # 4K random read, then 1M sequential read, then 1M sequential write Run-CmdToFile "DiskSpd 4K random read (C:)" "`"$diskspd`" -c2G -d30 -Sh -w0 -r -b4K -t2 -o8 -L `"$testFile`"" "50_diskspd_4k_rr_c.txt" Run-CmdToFile "DiskSpd 1M sequential read (C:)" "`"$diskspd`" -c2G -d30 -Sh -w0 -si -b1M -t2 -o2 -L `"$testFile`"" "51_diskspd_1m_seqread_c.txt" Run-CmdToFile "DiskSpd 1M sequential write (C:)" "`"$diskspd`" -c2G -d30 -Sh -w100 -si -b1M -t2 -o2 -L `"$testFile`"" "52_diskspd_1m_seqwrite_c.txt" Remove-Item -Force -ErrorAction SilentlyContinue $testFile } else { Out-FileUtf8 (Join-Path $OutDir "50_diskspd_4k_rr_c.txt") "diskspd.exe not found (install may have failed)." } } catch { Out-FileUtf8 (Join-Path $OutDir "50_diskspd_ERROR.txt") $_.Exception.Message } # ========================= # 6) Throttle / overheating evidence without extra tools # - Create CPU load for 120s # - Sample perf counters each second to CSV # ========================= try { $csv = Join-Path $OutDir "60_cpu_throttle_sample.csv" $counters = @( '\Processor Information(_Total)\% Processor Utility', '\Processor Information(_Total)\Processor Frequency', '\Processor Information(_Total)\% Processor Performance' ) # Some systems don't expose all counters; we will filter to valid ones. $valid = @() foreach ($c in $counters) { try { Get-Counter -Counter $c -ErrorAction Stop | Out-Null; $valid += $c } catch {} } if ($valid.Count -eq 0) { Out-FileUtf8 $csv "No expected Processor Information counters available on this system." } else { # CPU load: spin up N jobs ~= logical cores $cores = (Get-CimInstance Win32_Processor | Select-Object -ExpandProperty NumberOfLogicalProcessors -ErrorAction SilentlyContinue) if (-not $cores -or $cores -lt 1) { $cores = 4 } $durationSec = 120 $end = (Get-Date).AddSeconds($durationSec) $jobs = @() for ($i=0; $i -lt $cores; $i++) { $jobs += Start-Job -ScriptBlock { $stop = (Get-Date).AddSeconds(120) while ((Get-Date) -lt $stop) { # cheap CPU burn [void][Math]::Sqrt((Get-Random) * (Get-Random)) } } } "Timestamp,Counter,Value" | Set-Content -Path $csv -Encoding UTF8 while ((Get-Date) -lt $end) { $t = Get-Date -Format o $sample = Get-Counter -Counter $valid foreach ($s in $sample.CounterSamples) { "$t,""{0}"",{1}" -f $s.Path, ([math]::Round($s.CookedValue,2)) | Add-Content -Path $csv -Encoding UTF8 } # Optional thermal zone temp (often useless on desktops, but harmless) try { $tz = Get-CimInstance -Namespace root/wmi -ClassName MSAcpi_ThermalZoneTemperature -ErrorAction Stop foreach ($z in $tz) { # Kelvin*10 -> C $c = [math]::Round(($z.CurrentTemperature / 10) - 273.15, 2) "$t,""ThermalZoneC"",$c" | Add-Content -Path $csv -Encoding UTF8 } } catch {} Start-Sleep -Seconds 1 } $jobs | ForEach-Object { Stop-Job $_ -ErrorAction SilentlyContinue } $jobs | ForEach-Object { Remove-Job $_ -Force -ErrorAction SilentlyContinue } } } catch { Out-FileUtf8 (Join-Path $OutDir "60_cpu_throttle_sample_ERROR.txt") $_.Exception.Message } # ========================= # 7) Event logs relevant to throttling / disk / WHEA (last 2 days) # ========================= try { $ev = Join-Path $OutDir "70_eventlog_system_filtered.txt" $since = (Get-Date).AddDays(-2) $events = Get-WinEvent -FilterHashtable @{ LogName='System'; StartTime=$since } -ErrorAction SilentlyContinue | Where-Object { $_.ProviderName -match 'WHEA|Disk|storahci|nvme|iaStor|Kernel-Power|Thermal|ACPI' -or $_.Id -in 7,51,55,129,153,157,6008,41 } | Select-Object TimeCreated,Id,LevelDisplayName,ProviderName,Message $events | Format-List | Out-File -FilePath $ev -Encoding UTF8 } catch { Out-FileUtf8 (Join-Path $OutDir "70_eventlog_system_filtered_ERROR.txt") $_.Exception.Message } # Final marker Out-FileUtf8 (Join-Path $OutDir "ZZ_done.txt") "Done. Results folder: $OutDir`r`nTimestamp: $(Get-Date -Format o)`r`nIsAdmin: $IsAdmin" '@ $script | Set-Content -Path $scriptPath -Encoding UTF8 Write-Host "Created: $scriptPath" Write-Host "Run it (same shell): powershell -ExecutionPolicy Bypass -File `"$scriptPath`""