-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGet_Disk_Info.ps1
More file actions
204 lines (177 loc) · 8.42 KB
/
Get_Disk_Info.ps1
File metadata and controls
204 lines (177 loc) · 8.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# Get_Disk_Info.ps1
# ---------------------------------------------
# This script gathers detailed disk information using PowerShell and smartctl (smartmontools).
# Compatible with PowerShell 5+
# Information collected includes:
# - Disk Info: Number, Model, Serial, Size, Partition Style (MBR/GPT), Bus Type
# - Physical Disk Health via smartctl (SMART data)
# - Partition Info: Number, Drive Letter, Type
# - Volume Info: Label, File System, Total Size, Used Space, Free Space, % Free
# Usage:
# - Run this script with administrative privileges.
# - Requires 'smartmontools' to be installed and 'smartctl' to be in the system PATH.
# ---------------------------------------------
# Check for admin privs
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host "This script must be run as Administrator!" -ForegroundColor Red
Write-Host "Right-click the script and select 'Run with PowerShell (Admin)' or run from an elevated PowerShell window." -ForegroundColor Yellow
pause
exit
}
# Check for smartctl
$SmartCtlPath = Get-Command "smartctl" -ErrorAction SilentlyContinue
if (-not $SmartCtlPath) {
Write-Warning "smartctl.exe (smartmontools) not found in PATH."
Write-Warning "SMART data will be unavailable. Please install smartmontools."
Write-Warning "Install from: https://github.com/smartmontools/smartmontools/releases"
}
try {
# Get all physical disks
$Disks = Get-Disk | Sort-Object Number
}
catch {
Write-Error "Failed to retrieve disk information. Ensure the Storage module is available."
exit
}
$VolumeReport = @()
$DriveHealthReport = @()
foreach ($Disk in $Disks) {
# 1. Volume & Partition Information
$Partitions = Get-Partition -DiskNumber $Disk.Number -ErrorAction SilentlyContinue
if ($Partitions) {
foreach ($Partition in $Partitions) {
$Volume = $null
try { $Volume = $Partition | Get-Volume -ErrorAction Stop } catch {}
$VolSizeGB = $null; $VolFreeGB = $null; $VolPercentFree = $null
if ($Volume) {
$VolSizeGB = [math]::Round($Volume.Size / 1GB, 2)
$VolFreeGB = [math]::Round($Volume.SizeRemaining / 1GB, 2)
if ($Volume.Size -gt 0) {
$VolPercentFree = [math]::Round(($Volume.SizeRemaining / $Volume.Size) * 100, 1)
}
}
$VolumeReport += [PSCustomObject]@{
DiskNum = $Disk.Number
Drive = if ($Partition.DriveLetter) { $Partition.DriveLetter } else { "" }
Label = if ($Volume) { $Volume.FileSystemLabel } else { "" }
FileSystem = if ($Volume) { $Volume.FileSystem } else { "" }
SizeGB = $VolSizeGB
FreeGB = $VolFreeGB
PercentFree = $VolPercentFree
PartStyle = $Disk.PartitionStyle
Model = $Disk.Model
}
}
}
else {
# Unpartitioned Disk
$VolumeReport += [PSCustomObject]@{
DiskNum = $Disk.Number
Drive = ""
Label = "(Unpartitioned)"
FileSystem = ""
SizeGB = [math]::Round($Disk.Size / 1GB, 2)
FreeGB = $null
PercentFree = $null
PartStyle = $Disk.PartitionStyle
Model = $Disk.Model
}
}
# 2. SMART Health (smartctl)
# Default values
$SmartStatus = "Unknown"
$TempC = $null
$PowerHours = $null
$Reallocated = $null
$WearLevel = $null
$WrittenData = $null
$Serial = $Disk.SerialNumber
$Model = $Disk.Model
$Family = ""
$DeviceType = "Unknown"
if ($SmartCtlPath) {
# Windows Disk Number to smartctl device path: /dev/pd<N>
$DevicePath = "/dev/pd$($Disk.Number)"
try {
# Run smartctl JSON output (-j) all info (-a)
# 2>&1 catch output even if exit code is non zero
$SmartJson = & smartctl -j -a $DevicePath 2>&1 | Out-String | ConvertFrom-Json
if ($SmartJson) {
# Basic Info
if ($SmartJson.device.protocol) { $DeviceType = $SmartJson.device.protocol }
elseif ($SmartJson.device.type) { $DeviceType = $SmartJson.device.type }
if ($SmartJson.model_name) { $Model = $SmartJson.model_name }
if ($SmartJson.serial_number) { $Serial = $SmartJson.serial_number }
if ($SmartJson.model_family) { $Family = $SmartJson.model_family }
# Health Status
if ($SmartJson.smart_status.passed -eq $true) {
$SmartStatus = "PASSED"
} elseif ($SmartJson.smart_status.passed -eq $false) {
$SmartStatus = "FAILED"
}
# Temperature
if ($SmartJson.temperature.current) { $TempC = $SmartJson.temperature.current }
# Power On Hours
if ($SmartJson.power_on_time.hours) { $PowerHours = $SmartJson.power_on_time.hours }
# --- Vendor Specific / Critical Attributes ---
# Check for ATA Attributes
if ($SmartJson.ata_smart_attributes.table) {
# ID 5: Reallocated Sector Count
$AttRealloc = $SmartJson.ata_smart_attributes.table | Where-Object { $_.id -eq 5 }
if ($AttRealloc) { $Reallocated = $AttRealloc.raw.value }
# ID 241: Total LBAs Written (Common for SATA SSDs)
$AttWritten = $SmartJson.ata_smart_attributes.table | Where-Object { $_.id -eq 241 }
if ($AttWritten) {
# Assume 512b sectors for Total_LBAs_Written
$Bytes = [math]::BigMul($AttWritten.raw.value, 512)
$WrittenData = if ($Bytes -gt 1TB) { "{0:N1} TB" -f ($Bytes / 1TB) } else { "{0:N1} GB" -f ($Bytes / 1GB) }
}
# SSD Wear (Various IDs: 177, 233, etc.)
$AttWear = $SmartJson.ata_smart_attributes.table | Where-Object { $_.id -in 177, 230, 231, 233, 241 } # Common SSD life attributes
if ($AttWear) { $WearLevel = "Raw: " + ($AttWear | Select-Object -First 1).raw.string }
}
# Check for NVMe Log
if ($SmartJson.nvme_smart_health_information_log) {
$NvmeLog = $SmartJson.nvme_smart_health_information_log
# Percentage Used
if ($NvmeLog.percentage_used -ne $null) {
$WearLevel = "$($NvmeLog.percentage_used)% Used"
}
# Data Units Written (1 unit = 1000 * 512 bytes = 512,000 bytes)
if ($NvmeLog.data_units_written -ne $null) {
$Bytes = [decimal]$NvmeLog.data_units_written * 512000
$WrittenData = if ($Bytes -gt 1TB) { "{0:N2} TB" -f ($Bytes / 1TB) } else { "{0:N2} GB" -f ($Bytes / 1GB) }
}
if ($NvmeLog.critical_warning -gt 0) {
$SmartStatus = "WARNING (NVMe Crit)"
}
}
}
}
catch {
$SmartStatus = "Error/No Data"
}
}
$DriveHealthReport += [PSCustomObject]@{
DiskNum = $Disk.Number
SmartStatus = $SmartStatus
Model = $Model
Type = $DeviceType
SerialNumber = $Serial
TempC = $TempC
PowerHours = $PowerHours
Reallocated = $Reallocated
WearLevel = $WearLevel
Written = $WrittenData
}
}
# OUTPUT
Write-Host "`n=== VOLUME INFORMATION (Partitions & Usage) ===" -ForegroundColor Cyan
$VolumeReport | Format-Table -AutoSize -Property DiskNum, Drive, Label, FileSystem, SizeGB, FreeGB, PercentFree, PartStyle
Write-Host "`n=== PHYSICAL DRIVE HEALTH (Via smartctl) ===" -ForegroundColor Cyan
if ($SmartCtlPath) {
$DriveHealthReport | Format-Table -AutoSize -Property DiskNum, SmartStatus, TempC, Reallocated, WearLevel, Written, PowerHours, Type, Model, SerialNumber
} else {
Write-Warning "Smartctl not available. Install smartmontools to view Health/SMART data table."
}
pause