Now to display each set of FailData we need a foreach loop:
foreach ( ManagementObject FailData in FailDataSet ) {
The data is returned as an object type but we know it’s really a byte array and the simplest way of working with it is to retrieve it and cast it to a byte array:
Byte[] data = (Byte[])FailData. Properties["VendorSpecific"].Value;
Finally we can add each attribute to the RichTextBox making use of the fact that each block of 12 bytes corresponds to an attribute:
for (int i = 0; i < data[0]-1; i++) { for (int j = 0; j < 12; j++) { richTextBox2.Text = richTextBox2.Text + data[i*12+j] + "\t"; } richTextBox2.Text = richTextBox2.Text + "\n"; }
If you now run the program you will see the raw SMART data displayed as a table. Your next task is to process it and build it into a useful reporting tool that will warn you if anything is going wrong.
The raw SMART data
If you want to work with the data in a more object-oriented way then you probably need to create a SMART class but a SMART struct also works well. For example, a struct that holds values for the most important failure indicators would be:
public struct SMARTAttribute { public int status; public int value; public int rawvalue; } public struct SMART { public SMARTAttribute RawReadErrorRate; public SMARTAttribute ReallocatedSectorCount; public SMARTAttribute ReallocationEventCount; public SMARTAttribute CurrentPendingSectorCount; public SMARTAttribute OfflineScanUncorrectableSectorCount; }
Packing the data into the struct is just a matter of detecting which attribute the current 12 bytes of data represents and the best way to do this is with a switch:
SMART smartdata; foreach (ManagementObject FailData2 in FailDataSet) { Byte[] data2 = (Byte[])FailData2. Properties["VendorSpecific"].Value; for (int i = 0; i < data2[0] - 1; i++) { int start=i*12; switch(data2[start+2]) { case 1: smartdata.RawReadErrorRate.value = data2[start + 5]; smartdata.RawReadErrorRate.rawvalue= data2[start+7]+256*data2[start+8]; break; case 5: smartdata.ReallocatedSectorCount. value =data2[start + 5]; smartdata.ReallocatedSectorCount. rawvalue = data2[start + 7] + 256 * data2[start + 8]; break; case 196: smartdata.ReallocationEventCount. value =data2[start + 5]; smartdata.ReallocationEventCount. rawvalue =data2[start + 7] + 256 * data2[start + 8]; break; case 197: smartdata.CurrentPendingSectorCount. value = data2[start + 5]; smartdata.CurrentPendingSectorCount. rawvalue = data2[start + 7] + 256 * data2[start + 8]; break; case 198: smartdata. OfflineScanUncorrectableSectorCount. value = data2[start + 5]; smartdata. OfflineScanUncorrectableSectorCount. rawvalue = data2[start + 7] + 256 * data2[start + 8]; break; } }
You can add extra code to initialise the other data values and retrieve other attributes if you need them. Once you have seen how it’s done it’s not so difficult.
It is also possible to run such WMI queries remotely once you have worked out how to set the system up to allow it. See Getting remote DCOM (WMI) to work.
If you would like the code for this article register with I Programmer and visit the codebin.