搜索了一下WMI对象内的Class发现确实有比较方便的类
命名空间root/wmi下MSStorageDriver_ATAPISmartData类的子集VendorSpecific内存放了硬盘内部芯片存储的所有SMART讯息大小为512Bytes。直接提取出来如下:
一堆乱麻。查询了一下SMART讯息相关资料,没有找到直接的spec。但是了解到第1,2个Byte位置代表SMART版本号(如图为10,0)。第3Byte开始往后全部为SMART attributes,每12个Bytes为一组代表一个分类Item,假定如下结构体便于厘清。
struct
{
char attrib;
char flags;
char worst;
char normal;
char current;
char current1;
char current2;
char current3;
char current4;
char current5;
char current6;
char current7;
} Attriubtes
维基百科上(http://en.wikipedia.org/wiki/S.M.A.R.T.)有各分类Item的详细定义。
找到我们想要的温度和POH所在的Item ID,如下:
可知第一Byte分别为4,9,194的三个分类Item内存储着Start/Stop Count(硬盘开关机次数),POH(硬盘持续使用时间),Temperature(硬盘内部温度)的资讯。我们按照上述结构体定义就可将温度和POH等想要的讯息解析出来。如果以16进制表示,每12Bytes的分类Item内第7个Bytes代表当前值的高位,第6个Bytes代表当前值的低位。
这里要说明的是S.M.A.R.T定义的所有Item不是每块硬盘都支持的,可能只支持SMART标准内部分Item功能。所以流程上如要严谨化需用到另外一个WMI类MSStorageDriver_FailurePredictThresholds --- 其可以枚举出本地硬盘所有可用分类Item的首字节ID值。
流程思路已经很清晰,使用脚本实现温度和POH的自动提取方法自然也就很容易,附上当时写的代码如下(vbs):
'Verison: WSH 5.8
'Platform: WinXP/Vista/WIN7
'Author: Ken Hua (hua.ken@inventec.com.cn)
'
' Script Function:
' Get Hard Disk S.M.A.R.T information
'
'On Error Resume Next
'Option Explicit
Const Start_Stop_Count = 4 'A tally of spindle start/stop cycles.
Const Power_On_Hours = 9 'Count of hours in power-on state.
Const Temperature = 194 'Current internal temperature.
Dim i,j,k,items(100),threshold(100),smartdata(2,11)
Dim Description(2),Limit(2),Normal(2),Bad(2),Data(2),getInfo(2)
Dim strComputer,objWMIService,colItems,objItem
strComputer = "."
getInfo(0) = Start_Stop_Count
getInfo(1) = Power_On_Hours
getInfo(2) = Temperature
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\WMI")
Set colItems = objWMIService.ExecQuery("SELECT * FROM MSStorageDriver_FailurePredictThresholds",,48)
For Each objItem In colItems
j = 0
For i = 2 To UBound(objItem.VendorSpecific, 1) Step 12
items(j) = objItem.VendorSpecific(i)
threshold(j) = objItem.VendorSpecific(i+1)
j = j + 1
Next
Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\WMI")
Set colItems = objWMIService.ExecQuery("SELECT * FROM MSStorageDriver_ATAPISmartData",,48)
For Each objItem In colItems
For i = 2 To UBound(objItem.VendorSpecific, 1) Step 12
If objItem.VendorSpecific(i) = getInfo(0) Then
k = i
For j = 0 To 11
smartdata(0,j) = objItem.VendorSpecific(k)
k = k + 1
Next
End If
If objItem.VendorSpecific(i) = getInfo(1) Then
k = i
For j = 0 To 11
smartdata(1,j) = objItem.VendorSpecific(k)
k = k + 1
Next
End If
If objItem.VendorSpecific(i) = getInfo(2) Then
k = i
For j = 0 To 11
smartdata(2,j) = objItem.VendorSpecific(k)
k = k + 1
Next
End If
Next
Next
For i = 0 To 100
If items(i) = getInfo(0) Then
Limit(0) = threshold(i)
End If
If items(i) = getInfo(1) Then
Limit(1) = threshold(i)
End If
If items(i) = getInfo(2) Then
Limit(2) = threshold(i)
End If
Next
Description(0) = "Start/Stop Count"
Description(1) = "Power On Hours"
Description(2) = "Temperature"
Normal(0) = smartdata(0,3)
Normal(1) = smartdata(1,3)
Normal(2) = smartdata(2,3)
Bad(0) = smartdata(0,4)
Bad(1) = smartdata(1,4)
Bad(2) = smartdata(2,4)
Data(0) = (Int(smartdata(0,7))*16*16*16)+(Int(smartdata(0,6))*16*16)+Int(smartdata(0,5))
Data(1) = (Int(smartdata(1,7))*16*16*16)+(Int(smartdata(1,6))*16*16)+Int(smartdata(1,5))
Data(2) = (Int(smartdata(2,7))*16*16*16)+(Int(smartdata(2,6))*16*16)+Int(smartdata(2,5))
Wscript.echo "Hard Disk S.M.A.R.T -- Hua.ken@Inventec.com.cn " & vbCrLf _
&"----------------------------------------------------------------------------------" & vbCrLf _
&" Description(ID) Threshold_Limit Normal Bad Data " & vbCrLf _
&"----------------------------------------------------------------------------------" & vbCrLf _
& Description(0) & "(" & getInfo(0) & ")" & Space(7) & Limit(0) & Space(16) & Normal(0) & Space(12) & Bad(0) & Space(12) & Data(0) & vbCrLf _
& Description(1) & "(" & getInfo(1) & ")" & Space(7) & Limit(1) & Space(17) & Normal(1) & Space(13) & Bad(1) & Space(13) & Data(1) & vbCrLf _
& Description(2) & "(" & getInfo(2) & ")" & Space(9) & Limit(2) & Space(17) & Normal(2) & Space(13) & Bad(2) & Space(13) & Data(2)
Wscript.Quit