# diag2.ps1 - полное чтение библиотек игр: ловим сбойные и "медленные" файлы # Запускать, если diag1 не дал однозначного ответа. Время: 10-25 мин на ~150 ГБ SATA SSD. # Запуск: powershell -NoProfile -ExecutionPolicy Bypass -File C:\diag2.ps1 $ErrorActionPreference = 'Continue' $out = "$env:USERPROFILE\Desktop\diag2.txt" Start-Transcript -Path $out -Force | Out-Null # Порог "медленного" чтения. Для SATA SSD норма 300-550 МБ/с. # Ниже 80 МБ/с на крупном файле = контроллер уходит в ретраи (потеря заряда в ячейках). $SLOW_MBS = 80 $MIN_MB_FOR_SPEED = 8 # файлы мельче не оцениваем по скорости - оверхед искажает $libs = @() foreach ($drv in (Get-Volume | Where-Object { $_.DriveLetter -and $_.FileSystem -eq 'NTFS' }).DriveLetter) { foreach ($cand in @("${drv}:\steam\steamapps\common", "${drv}:\SteamLibrary\steamapps\common", "${drv}:\Program Files (x86)\Steam\steamapps\common")) { if (Test-Path $cand) { $libs += $cand } } } "Библиотеки: $($libs -join ', ')" # Проверяем проблемные игры; если их нет - всю библиотеку $targets = @() foreach ($l in $libs) { $targets += Get-ChildItem $l -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'Counter-Strike|Tsushima|Rome|Serious Sam' } } if (-not $targets) { $targets = $libs | ForEach-Object { Get-Item $_ } } "Проверяю: $(($targets | ForEach-Object { $_.Name }) -join ' | ')`n" $files = $targets | ForEach-Object { Get-ChildItem $_.FullName -Recurse -File -ErrorAction SilentlyContinue } $totalGB = [math]::Round(($files | Measure-Object -Sum Length).Sum / 1GB, 1) "Файлов: $($files.Count), объём: $totalGB ГБ`n" $buf = New-Object byte[] 4194304 $bad = @(); $slow = @(); $i = 0 $swAll = [Diagnostics.Stopwatch]::StartNew() foreach ($f in $files) { $i++ if ($i % 200 -eq 0) { Write-Progress -Activity "Чтение" -Status "$i / $($files.Count)" -PercentComplete ($i * 100 / $files.Count) } try { $fs = [IO.File]::Open($f.FullName, 'Open', 'Read', 'Read') $sw = [Diagnostics.Stopwatch]::StartNew() $total = 0 while (($n = $fs.Read($buf, 0, $buf.Length)) -gt 0) { $total += $n } $sw.Stop(); $fs.Close() $mb = $total / 1MB if ($mb -ge $MIN_MB_FOR_SPEED -and $sw.Elapsed.TotalSeconds -gt 0) { $spd = $mb / $sw.Elapsed.TotalSeconds if ($spd -lt $SLOW_MBS) { $slow += [pscustomobject]@{ MBs = [math]::Round($spd, 1); MB = [math]::Round($mb, 1); Path = $f.FullName } "SLOW {0,7:N1} MB/s {1,8:N1} MB {2}" -f $spd, $mb, $f.FullName } } } catch { $bad += [pscustomobject]@{ Path = $f.FullName; Err = $_.Exception.Message } "FAIL $($f.FullName)`n -> $($_.Exception.Message)" } } $swAll.Stop() Write-Progress -Activity "Чтение" -Completed "`n" + ('=' * 70) "ИТОГ: прочитано $totalGB ГБ за $([math]::Round($swAll.Elapsed.TotalMinutes,1)) мин" "Средняя скорость: $([math]::Round($totalGB * 1024 / $swAll.Elapsed.TotalSeconds, 1)) МБ/с" "Ошибок чтения: $($bad.Count)" "Медленных файлов (<$SLOW_MBS МБ/с): $($slow.Count)" ('=' * 70) if ($bad) { "`n--- ФАЙЛЫ С ОШИБКОЙ ЧТЕНИЯ (прямое доказательство сбойных секторов):" $bad | Format-List } if ($slow) { "`n--- ТОП-30 МЕДЛЕННЫХ (ретраи контроллера / потеря заряда в ячейках):" $slow | Sort-Object MBs | Select-Object -First 30 | Format-Table -AutoSize } if (-not $bad -and -not $slow) { "`nЧисто: все файлы читаются на полной скорости. Версия про накопитель слабеет -" "переходим к питанию и драйверу (стресс GPU с логом HWiNFO)." } "`n--- SMART ПОСЛЕ ПРОГОНА (сравнить C5/05/BB с diag1: рост = диск сыплется прямо сейчас)" $sm = "C:\Program Files\smartmontools\bin\smartctl.exe" if (Test-Path $sm) { & $sm --scan 2>&1 | ForEach-Object { if ($_ -match '^(\S+)\s') { "`n=== $($Matches[1])"; & $sm -A $Matches[1] 2>&1 } } } Stop-Transcript | Out-Null Write-Host "`nОтчёт сохранён: $out" -ForegroundColor Green