暑くなってきたので Windows PC の Disk の温度を windows_exporter で取得して監視したい
免責・ご注意
- 当方あまり Windows に詳しくありません(他にもやりようはあるかと...)
- Administrator ユーザーを有効にし、タスクスケジューラーにて PowerShell スクリプトを Administrator ユーザーで実行しています
- Get-StorageReliabilityCounter コマンドで必要という理解
Get-StorageReliabilityCounter : Access to a CIM resource was not available to the client. At line:1 char:15 + $gsrc=($gpd | Get-StorageReliabilityCounter) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : PermissionDenied: (PS_StorageCmdlets:ROOT/Microsoft/..._StorageCmdlets) [Get-StorageReliabilityCounter], CimException + FullyQualifiedErrorId : MI RESULT 2,Get-StorageReliabilityCounter
作成の経緯
- 昨年の夏以降に作業PC(Windows11Pro)の C ドライブのディスクを PCIe® Gen3 x4 にリプレイス
- 春辺りまでは気にならなかったものの、昨今(2024/05)の温かさもあって CrystalDiskInfo をインストールして見てみると結構高温に...70度とか、これは対処しないとまずいなと。
- 急いでファン付きの大きめの m.2 SSD 用ヒートシンクを付けて対応するも、このあと本格的な夏を迎えるにあたってディスクの温度を計測・収集しておきたい
- そこで、もともと動かしていた Prometheus を活用すべく windows_exporter を導入してみるもディスクの温度は取れず
- ただ windows_exporter には textfile collector という機能があり prom 形式でテキストファイルに書き出せば読み込んでくれるらしい
- PowerShell あまり得意じゃないけどやってみるか...
参考にしたサイト
- https://belial6.hateblo.jp/entry/2020/04/28/234205
- Stackoverflow Site
- MS Site
- windows_exporter Site
現状の制約
- ドライブレター(C とか D とか)を振れていない
- Get-PSDrive コマンドでドライブレターを取れるのは分かったが、後述の 2 PowerShell コマンドと明確に関連付けられる値が見つからず...内蔵ディスクなら Number, DeviceId 順な気もするが...
- ハードコードすればドライブレターを表示することも可能だろうが、今のところはデバイスのモデル名になっています
システム
- クライアント
- Windows 11 Pro (Lenovo ThinkCentre M80t Mini-Tower Gen 3)
- windows_exporter-0.25.1-amd64.exe
- Windows 11 Pro (Lenovo ThinkCentre M80t Mini-Tower Gen 3)
- 監視サーバー
- ubuntu 22.04.3 LTS
- grafana/stable 11.0.0 amd64
- prometheus-2.49.1.linux-amd64
- ubuntu 22.04.3 LTS
処理概要
- Get-PhysicalDisk でディスクの名前(FriendlyName)を取得
- Get-StorageReliabilityCounter でディスクの温度(Temperature)を取得
- デバイスIDで 1. 2. の値を JOIN
- prom 形式でフラットファイルに書き出す PowerShell スクリプトをタスクスケジューラーで 5 分毎に実行
- Get-StorageReliabilityCounter の実行に少し時間を要するようなので極端に短くはせず
まずは結果から
PowerShellスクリプト
disktemp.ps1
$prom_location1 = "C:\Temp\textfile_inputs\disktemp.prom"
$gpd=Get-PhysicalDisk
$gsrc=($gpd | Get-StorageReliabilityCounter)
$out_values = (Join-Object -LeftObject $gpd -RightObject $gsrc -Where {$args[0].DeviceId -eq $args[1].DeviceId} | select-object -Property FriendlyName,Temperature)
Set-Content -Path $prom_location1 -Encoding Ascii -Value ""
Add-Content -Path $prom_location1 -Encoding Ascii -Value "# HELP Disk Temperature from Get-StorageReliabilityCounter."
Add-Content -Path $prom_location1 -Encoding Ascii -Value "# TYPE win_disktemp gauge"
foreach ( $v in $out_values) {
Add-Content -Path $prom_location1 -Encoding Ascii -Value "win_disktemp{name=""$($v.FriendlyName)""} $($v.Temperature)"
}
prom ファイル
windows_exporter 実行時引数
C:\Windows\System32>C:\Prometheus\windows_exporter-0.25.1-amd64.exe --collector.textfile.directories="C:\Temp\textfile_inputs"
Prometheus Query
- 温度情報が得られなかったりなどで USB 外付け Disk を除外して内蔵 SSD のみにしています
win_disktemp{name!="SP PD60",name!="SanDisk Extreme SSD",name!="Realtek RTL9210 NVME"}
Grafana
説明パート
1. Get-PhysicalDisk の出力結果
PS C:\temp\textfile_inputs> Get-PhysicalDisk | select-object -Property DeviceId,FriendlyName,MediaType,HealthStatus,Size | Format-Table
DeviceId FriendlyName MediaType HealthStatus Size
-------- ------------ --------- ------------ ----
0 KIOXIA-EXCERIA G2 SSD SSD Healthy 1000204886016
1 SPCC M.2 PCIe SSD SSD Healthy 1024209543168
2. Get-StorageReliabilityCounter の出力結果
PS C:\temp\textfile_inputs> Get-PhysicalDisk | Get-StorageReliabilityCounter | select-object -Property DeviceId,Temperature
DeviceId Temperature
-------- -----------
0 47
1 41
DeviceId で JOIN すれば FriendlyName と Temperature を組み合わせた情報を取得できそうです
3. 実際に JOIN してみる
$gpd=Get-PhysicalDisk
$gsrc=($gpd | Get-StorageReliabilityCounter)
Join-Object -LeftObject $gpd -RightObject $gsrc -Where {$args[0].Number -eq $args[1].DeviceId} | select-object -Property FriendlyName,Temperature
FriendlyName Temperature
------------ -----------
KIOXIA-EXCERIA G2 SSD 45
SPCC M.2 PCIe SSD 34
4. タスクスケジューラーに設定して単体実行し prom ファイルが書き出されていることを確認する
5. Prometheus にて値が取得できていることを確認する
6. Grafana でよしなにパネルを作る
今後の課題、拡張など
Get-PhysicalDisk と Get-StorageReliabilityCounter で取得可能なその他のメトリックの収集
- Get-PhysicalDisk で取得可能なメトリック一覧 (NULL あり)
ObjectId
PassThroughClass
PassThroughIds
PassThroughNamespace
PassThroughServer
UniqueId
Description
FriendlyName
HealthStatus
Manufacturer
Model
OperationalDetails
OperationalStatus
PhysicalLocation
SerialNumber
AdapterSerialNumber
AllocatedSize
BusType
CannotPoolReason
CanPool
DeviceId
EnclosureNumber
FirmwareVersion
FruId
IsIndicationEnabled
IsPartial
LogicalSectorSize
MediaType
OtherCannotPoolReasonDescription
PartNumber
PhysicalSectorSize
Size
SlotNumber
SoftwareVersion
SpindleSpeed
StoragePoolUniqueId
SupportedUsages
UniqueIdFormat
Usage
VirtualDiskFootprint
PSComputerName
ClassName
- Get-PhysicalDisk | Get-StorageReliabilityCounter で取得可能なメトリック一覧 (NULL あり)
ObjectId
PassThroughClass
PassThroughIds
PassThroughNamespace
PassThroughServer
UniqueId
DeviceId
FlushLatencyMax
LoadUnloadCycleCount
LoadUnloadCycleCountMax
ManufactureDate
PowerOnHours
ReadErrorsCorrected
ReadErrorsTotal
ReadErrorsUncorrected
ReadLatencyMax
StartStopCycleCount
StartStopCycleCountMax
Temperature
TemperatureMax
Wear
WriteErrorsCorrected
WriteErrorsTotal
WriteErrorsUncorrected
WriteLatencyMax
PSComputerName
変数追加
- BusType, MediaType を追加
- NVMe, USB 等でフィルター可能に
Join-Object -LeftObject $gpd -RightObject $gsrc -Where {$args[0].DeviceId -eq $args[1].DeviceId} | select-object -Property FriendlyName,BusType,MediaType,Temperature
FriendlyName BusType MediaType Temperature
------------ ------- --------- -----------
KIOXIA-EXCERIA G2 SSD NVMe SSD 48
SPCC M.2 PCIe SSD NVMe SSD 39
Realtek RTL9210 NVME USB SSD 39
KIOXIA TransMemory USB Unspecified 0
SP PD60 USB SSD 0
SanDisk Extreme SSD USB SSD 0
disktemp.ps1
$prom_location1 = "C:\Temp\textfile_inputs\disktemp.prom"
$gpd=Get-PhysicalDisk
$gsrc=($gpd | Get-StorageReliabilityCounter)
$out_values = (Join-Object -LeftObject $gpd -RightObject $gsrc -Where {$args[0].DeviceId -eq $args[1].DeviceId} | select-object -Property FriendlyName,BusType,MediaType,Temperature)
Set-Content -Path $prom_location1 -Encoding Ascii -Value ""
Add-Content -Path $prom_location1 -Encoding Ascii -Value "# HELP Disk Temperature from Get-StorageReliabilityCounter."
Add-Content -Path $prom_location1 -Encoding Ascii -Value "# TYPE win_disktemp gauge"
foreach ( $v in $out_values) {
Add-Content -Path $prom_location1 -Encoding Ascii -Value "win_disktemp{name=""$($v.FriendlyName)"",bustype=""$($v.BusType)"",mediatype=""$($v.MediaType)""} $($v.Temperature)"
}
disktemp.prom
# HELP Disk Temperature from Get-StorageReliabilityCounter.
# TYPE win_disktemp gauge
win_disktemp{name="KIOXIA-EXCERIA G2 SSD",bustype="NVMe",mediatype="SSD"} 50
win_disktemp{name="SPCC M.2 PCIe SSD",bustype="NVMe",mediatype="SSD"} 39
win_disktemp{name="Realtek RTL9210 NVME",bustype="USB",mediatype="SSD"} 39
win_disktemp{name="KIOXIA TransMemory",bustype="USB",mediatype="Unspecified"} 0
win_disktemp{name="SP PD60",bustype="USB",mediatype="SSD"} 0
win_disktemp{name="SanDisk Extreme SSD",bustype="USB",mediatype="SSD"} 0
Prometheus
# HELP win_disktemp Metric read from C:\\Temp\\textfile_inputs\\disktemp.prom
# TYPE win_disktemp gauge
win_disktemp{bustype="NVMe",mediatype="SSD",name="KIOXIA-EXCERIA G2 SSD"} 50
win_disktemp{bustype="NVMe",mediatype="SSD",name="SPCC M.2 PCIe SSD"} 39
win_disktemp{bustype="USB",mediatype="SSD",name="Realtek RTL9210 NVME"} 39
win_disktemp{bustype="USB",mediatype="SSD",name="SP PD60"} 0
win_disktemp{bustype="USB",mediatype="SSD",name="SanDisk Extreme SSD"} 0
win_disktemp{bustype="USB",mediatype="Unspecified",name="KIOXIA TransMemory"} 0
Prometheus Query
win_disktemp{bustype="NVMe"}
Health も追加
$prom_location1 = "C:\Temp\textfile_inputs\disktemp.prom"
$prom_location2 = "C:\Temp\textfile_inputs\diskhealth.prom"
$gpd=Get-PhysicalDisk
$gsrc=($gpd | Get-StorageReliabilityCounter)
$out_values = (Join-Object -LeftObject $gpd -RightObject $gsrc -Where {$args[0].DeviceId -eq $args[1].DeviceId} | select-object -Property FriendlyName,BusType,MediaType,Temperature,HealthStatus)
Set-Content -Path $prom_location1 -Encoding Ascii -Value ""
Add-Content -Path $prom_location1 -Encoding Ascii -Value "# HELP Disk Temperature from Get-StorageReliabilityCounter."
Add-Content -Path $prom_location1 -Encoding Ascii -Value "# TYPE win_disktemp gauge"
foreach ( $v1 in $out_values) {
Add-Content -Path $prom_location1 -Encoding Ascii -Value "win_disktemp{name=""$($v1.FriendlyName)"",bustype=""$($v1.BusType)"",mediatype=""$($v1.MediaType)""} $($v1.Temperature)"
}
Set-Content -Path $prom_location2 -Encoding Ascii -Value ""
Add-Content -Path $prom_location2 -Encoding Ascii -Value "# HELP Disk Health from Get-StorageReliabilityCounter."
Add-Content -Path $prom_location2 -Encoding Ascii -Value "# TYPE win_diskhealth gauge"
foreach ( $v2 in $out_values) {
if ($v2.HealthStatus -eq "Healthy") {
$healthvalue = 0
Add-Content -Path $prom_location2 -Encoding Ascii -Value "win_diskhealth{name=""$($v2.FriendlyName)"",bustype=""$($v2.BusType)"",mediatype=""$($v2.MediaType)"",diskhealth=""$($v2.HealthStatus)""} $healthvalue"
}
else {
$healthvalue = 1
}
}