# Полный отчет с исправленной ёмкостью и буквами томов Write-Host "`n============================================" -ForegroundColor Cyan Write-Host " ОТЧЕТ О СОСТОЯНИИ ДИСКОВ" -ForegroundColor Cyan Write-Host " Дата: $(Get-Date -Format 'dd.MM.yyyy HH:mm')" -ForegroundColor Cyan Write-Host "============================================`n" -ForegroundColor Cyan $overallStatus = "ХОРОШО" $diskResults = @() $problemDisks = @() # Получаем все диски и тома для сопоставления $allPhysicalDrives = Get-WmiObject Win32_DiskDrive -ErrorAction SilentlyContinue $disks = .\smartctl.exe --scan | Where-Object { $_ -notmatch "^#" -and $_ -ne "" } foreach ($diskLine in $disks) { $diskPath = ($diskLine -split ' ')[0] Write-Host "Проверка: $diskPath" -ForegroundColor Yellow Write-Host "-------------------------------------------" -ForegroundColor DarkGray # Получаем информацию $infoOutput = .\smartctl.exe -i $diskPath 2>$null $model = "Unknown" $serial = "Unknown" $capacity = "Unknown" # Простой парсинг построчно foreach ($line in $infoOutput) { if ($line -match "Device Model:\s*(.+)") { $model = $matches[1].Trim() } if ($line -match "Serial Number:\s*(.+)") { $serial = $matches[1].Trim() } # Парсим ёмкость - самый простой вариант if ($line -match "User Capacity:") { # Находим часть в квадратных скобках [500 GB] if ($line -match "\[([^\]]+)\]") { $capacity = $matches[1].Trim() } else { # Если нет скобок, берем число байт if ($line -match "(\d+)\s+bytes") { $bytes = [uint64]$matches[1] $gb = [math]::Round($bytes / 1GB, 1) $tb = [math]::Round($bytes / 1TB, 2) if ($tb -ge 1) { $capacity = "$tb TB ($bytes байт)" } else { $capacity = "$gb GB ($bytes байт)" } } } } } $diskKind = "HDD" foreach ($line in $infoOutput) { if ($line -match "Solid State Device|Rotation Rate.*Solid") { $diskKind = "SSD" break } } # Получаем букву тома через DiskIndex $driveLetters = @() $diskIndex = -1 if ($diskPath -match "/dev/sd([a-z])") { $letter = $matches[1] $diskIndex = [int][char]$letter - [int][char]'a' } if ($diskIndex -ge 0) { try { # Получаем все разделы этого диска $partitions = Get-WmiObject Win32_DiskPartition -Filter "DiskIndex=$diskIndex" -ErrorAction SilentlyContinue foreach ($part in $partitions) { # Ищем логические диски для каждого раздела $associators = Get-WmiObject -Query "ASSOCIATORS OF {$part} WHERE AssocClass=Win32_LogicalDiskToPartition" -ErrorAction SilentlyContinue foreach ($assoc in $associators) { if ($assoc.DeviceID) { $driveLetters += $assoc.DeviceID } } } } catch { # Игнорируем ошибки WMI } } $driveLetter = if ($driveLetters.Count -gt 0) { ($driveLetters | Sort-Object -Unique) -join ", " } else { "N/A" } # Получаем SMART статус $healthOutput = .\smartctl.exe -H $diskPath 2>$null $smartStatus = "UNKNOWN" foreach ($line in $healthOutput) { if ($line -match "PASSED") { $smartStatus = "PASSED"; break } if ($line -match "FAILED") { $smartStatus = "FAILED"; break } } # Получаем атрибуты $attributesOutput = .\smartctl.exe -A $diskPath 2>$null # Инициализируем ВСЕ атрибуты $reallocated = 0 $pending = 0 $uncorrectable = 0 $reallocEvent = 0 $powerOnHours = 0 $powerCycleCount = 0 $temperature = 0 $wearLeveling = 100 $udmaCrcErrors = 0 $spinRetry = 0 $loadCycleCount = 0 $totalWritten = 0 $totalRead = 0 $status = "ХОРОШО" $issues = @() # Парсим атрибуты foreach ($line in $attributesOutput) { if ($line -notmatch "^\s*(\d+)") { continue } $parts = $line.Trim() -split '\s+' if ($parts.Count -lt 10) { continue } try { $attrId = $parts[0] $attrValue = [int]$parts[3] $rawString = "" for ($i = 9; $i -lt $parts.Count; $i++) { $rawString += $parts[$i] + " " } $rawString = $rawString.Trim() -replace '[()]','' -replace '\s+',' ' $rawParts = $rawString -split ' ' if ($rawParts.Count -eq 0 -or $rawParts[0] -notmatch "^\d+$") { continue } $rawNum = [int]$rawParts[0] switch ($attrId) { "5" { $reallocated = $rawNum } "9" { $powerOnHours = $rawNum } "12" { $powerCycleCount = $rawNum } "194" { $temperature = $rawNum } "190" { if ($temperature -eq 0) { $temperature = $rawNum } } "197" { $pending = $rawNum } "198" { $uncorrectable = $rawNum } "199" { $udmaCrcErrors = $rawNum } "196" { $reallocEvent = $rawNum } "10" { $spinRetry = $rawNum } "225" { $loadCycleCount = $rawNum } "177" { if ($diskKind -eq "SSD") { $wearLeveling = $attrValue } } "202" { if ($diskKind -eq "SSD") { $wearLeveling = $attrValue } } "231" { if ($diskKind -eq "SSD") { $wearLeveling = $attrValue } } "241" { if ($diskKind -eq "SSD") { $totalWritten = $rawNum } } "242" { if ($diskKind -eq "SSD") { $totalRead = $rawNum } } } } catch { continue } } # Проверка проблем if ($diskKind -eq "HDD") { if ($reallocated -gt 0) { $issues += "Reallocated: $reallocated" } if ($pending -gt 0) { $issues += "Pending: $pending" } if ($uncorrectable -gt 0) { $issues += "Uncorrectable: $uncorrectable" } if ($udmaCrcErrors -gt 0) { $issues += "CRC: $udmaCrcErrors" } if ($reallocated -gt 100 -or $pending -gt 10) { $status = "ПЛОХО" } } else { if ($wearLeveling -lt 10) { $issues += "Износ: ${wearLeveling}%"; $status = "ПЛОХО" } elseif ($wearLeveling -lt 20) { $issues += "Низкий ресурс: ${wearLeveling}%" } } if ($smartStatus -eq "FAILED") { $status = "ПЛОХО"; $overallStatus = "ПЛОХО" } elseif ($status -eq "ПЛОХО") { $overallStatus = "ПЛОХО" } elseif ($issues.Count -gt 0 -and $overallStatus -eq "ХОРОШО") { $overallStatus = "НОРМАЛЬНО" } # Рассчитываем использованный ресурс для SSD $usedResource = if ($diskKind -eq "SSD") { 100 - $wearLeveling } else { $null } # Сохраняем все данные $diskData = [PSCustomObject]@{ Disk = $diskPath Model = $model Serial = $serial DriveLetter = $driveLetter Type = $diskKind Capacity = $capacity SmartStatus = $smartStatus Status = $status PowerOnHours = $powerOnHours PowerCycles = $powerCycleCount Temperature = $temperature Reallocated = $reallocated ReallocEvent = $reallocEvent Pending = $pending Uncorrectable = $uncorrectable UDMACrcErrors = $udmaCrcErrors SpinRetry = $spinRetry LoadCycleCount = $loadCycleCount WearLeveling = if ($diskKind -eq "SSD") { $wearLeveling } else { $null } UsedResource = $usedResource TotalWrittenGB = if ($diskKind -eq "SSD" -and $totalWritten -gt 0) { [math]::Round($totalWritten/1953125, 1) } else { $null } TotalReadGB = if ($diskKind -eq "SSD" -and $totalRead -gt 0) { [math]::Round($totalRead/1953125, 1) } else { $null } Issues = $issues } $diskResults += $diskData if ($status -ne "ХОРОШО" -or $issues.Count -gt 0) { $problemDisks += $diskData } # === ВЫВОД ИНФОРМАЦИИ ПО ДИСКУ === Write-Host "Модель: $model" -ForegroundColor White Write-Host "Серийный номер: $serial" -ForegroundColor Gray Write-Host "Буква тома: $driveLetter" -ForegroundColor Gray Write-Host "Тип: $diskKind" -ForegroundColor White Write-Host "Ёмкость: $capacity" -ForegroundColor Gray Write-Host "" Write-Host "SMART: $smartStatus" -ForegroundColor $(if($smartStatus -eq "PASSED"){"Green"}else{"Red"}) Write-Host "Статус: $status" -ForegroundColor $(if($status -eq "ХОРОШО"){"Green"}elseif($status -eq "НОРМАЛЬНО"){"Yellow"}else{"Red"}) Write-Host "" if ($diskKind -eq "HDD") { Write-Host "=== КРИТИЧЕСКИЕ АТРИБУТЫ ===" -ForegroundColor Cyan Write-Host "[05] Reallocated Sectors: $reallocated" -ForegroundColor $(if($reallocated -eq 0){"Green"}else{"Yellow"}) Write-Host "[C4] Realloc Events: $reallocEvent" -ForegroundColor $(if($reallocEvent -eq 0){"Green"}else{"Yellow"}) Write-Host "[C5] Pending Sectors: $pending" -ForegroundColor $(if($pending -eq 0){"Green"}else{"Yellow"}) Write-Host "[C6] Uncorrectable: $uncorrectable" -ForegroundColor $(if($uncorrectable -eq 0){"Green"}else{"Red"}) Write-Host "[C7] CRC Errors: $udmaCrcErrors" -ForegroundColor $(if($udmaCrcErrors -eq 0){"Green"}else{"Yellow"}) Write-Host "[0A] Spin Retry: $spinRetry" -ForegroundColor $(if($spinRetry -eq 0){"Green"}else{"Yellow"}) Write-Host "[E1] Load/Unload Cycles: $loadCycleCount" -ForegroundColor Gray } else { Write-Host "=== SSD АТРИБУТЫ ===" -ForegroundColor Cyan Write-Host "[CA/B1] Wear Leveling (осталось): ${wearLeveling}%" -ForegroundColor $(if($wearLeveling -gt 20){"Green"}else{"Red"}) Write-Host "[CA/B1] Used Resource (изношено): ${usedResource}%" -ForegroundColor $(if($usedResource -lt 80){"Green"}else{"Yellow"}) if ($totalWritten -gt 0) { $tbWritten = [math]::Round($totalWritten / 1953125, 2) Write-Host "[F1] Total Written: ~${tbWritten} TB" -ForegroundColor Gray } if ($totalRead -gt 0) { $tbRead = [math]::Round($totalRead / 1953125, 2) Write-Host "[F2] Total Read: ~${tbRead} TB" -ForegroundColor Gray } } Write-Host "" Write-Host "=== ОБЩАЯ ИНФОРМАЦИЯ ===" -ForegroundColor Cyan Write-Host "[09] Power-On Hours: $powerOnHours ч. ($([math]::Round($powerOnHours/24/365, 1)) лет)" -ForegroundColor White Write-Host "[0C] Power Cycles: $powerCycleCount" -ForegroundColor Gray Write-Host "[C2] Temperature: ${temperature}°C" -ForegroundColor $(if($temperature -lt 45){"Green"}elseif($temperature -lt 55){"Yellow"}else{"Red"}) if ($issues.Count -gt 0) { Write-Host "" Write-Host "⚠ ПРОБЛЕМЫ:" -ForegroundColor Red $issues | ForEach-Object { Write-Host " • $_" -ForegroundColor Yellow } } Write-Host "" } # Итоговый отчет Write-Host "============================================" -ForegroundColor Cyan Write-Host " ИТОГОВЫЙ ОТЧЕТ" -ForegroundColor Cyan Write-Host "============================================" -ForegroundColor Cyan Write-Host "" $statusColor = switch ($overallStatus) { "ХОРОШО" { "Green" } "НОРМАЛЬНО" { "Yellow" } "ПЛОХО" { "Red" } } Write-Host "Общий статус: $overallStatus" -ForegroundColor $statusColor Write-Host "Дисков проверено: $($diskResults.Count)" -ForegroundColor Cyan Write-Host "Проблемных дисков: $($problemDisks.Count)" -ForegroundColor $(if($problemDisks.Count -eq 0){"Green"}else{"Red"}) Write-Host "" # Экспорт $timestamp = Get-Date -Format "yyyyMMdd_HHmm" $csvFile = "disk_health_${timestamp}.csv" $diskResults | Select-Object Disk, Model, Serial, DriveLetter, Type, Capacity, SmartStatus, Status, PowerOnHours, Temperature, WearLeveling, UsedResource, Reallocated, Pending, Issues | Export-Csv -Path $csvFile -NoTypeInformation -Encoding UTF8 Write-Host "✓ Отчет сохранен: $csvFile" -ForegroundColor Green