Атрибуты SMART через запрос WMI на языке C#
Формулировка задачи:
Здравствуйте, передо мной возникла задача: написание программы, которая оценивает техническое состояние жёсткого диска. Я выяснил, что это можно сделать с помощью технологии S.M.A.R.T.
Здесь: Расшифровка параметров S.M.A.R.T, я прочитал о параметрах S.M.A.R.T.
При дальнейшем изучении вопроса стало понятно, что мне проще и удобнее всего получить доступ к параметрам S.M.A.R.T. с помощью технологии Windows Management Instrumentation (WMI), запросом на специальном языке WQL. В сети я нашёл статью, в которой описывается получение атрибутов S.M.A.R.T.:
http://www.i-programmer.info/projects/38/208.html?start=1
То есть параметры S.M.A.R.T. содержатся в структуре данных VendorSpecific, фактически являющейся массивом из байтов.
Вот код, приведённый там:
[Вот то, что вывела программа в моём случае:
Un___Un___ID___(?)___Un___Vale_Wrst Raw Unknw
10___0____1____15___0____100__253__0____0____0____0____0
0____0____3____3____0____99___99___0____0____0____0____0
0____0____4____50___0____98___98___64___10___0____0____0
0____0____5____51___0____100__100__0____0____0____0____0
0____0____7____15___0____87___60___229__122__192__28___1
0____0____9____50___0____94___94___151__21___0____0____0
0____0____10___19___0____100__100__0____0____0____0____0
0____0____12___50___0____98___98___66___10___0____0____0
0____0____187__50___0____100__100__0____0____0____0____0
Таким образом, программа вывела почти все значения атрибутов: ID, Value, Worst, и RAW, кроме Threshold. И ещё загадочный Status (?).
Вопрос: где взять Threshold, ведь он очень важен - позволяет оценить состояние атрибута.
Поле Status им точно не является, т.к. это значение не совпадает с тем, которое вывела другая программа SpeedFun.
Буду очень благодарен за помощь в поисках этого Threshold.
ManagementObjectSearcher WMISearch = new ManagementObjectSearcher(); WMISearch.Scope = new ManagementScope(@"\root\wmi"); WMISearch.Query = new ObjectQuery("Select * from MSStorageDriver_FailurePredictData"); ManagementObjectCollection FailDataSet = WMISearch.Get(); richTextBox1.Text = "Unknw\tUnknw\tAttribute\tStatus\tUnknw\tValue\tWorst\tRaw\t\tUnknw\n"; foreach ( ManagementObject FailData in FailDataSet ) { Byte[] data = (Byte[])FailData.Properties["VendorSpecific"].Value; for (int i = 0; i < data[0]-1; i++) { for (int j = 0; j < 12; j++) { richTextBox1.Text += data[i*12+j] + "\t"; } richTextBox1.Text += "\n"; } }
Решение задачи: «Атрибуты SMART через запрос WMI на языке C#»
textual
Листинг программы
using System; using System.Collections.Generic; using System.Management; public class HDD { public int Index { get; set; } public bool IsOK { get; set; } public string Model { get; set; } public string Type { get; set; } public string Serial { get; set; } public Dictionary<int, Smart> Attributes = new Dictionary<int, Smart>() { {0x00, new Smart("Invalid")}, {0x01, new Smart("Raw read error rate")}, {0x02, new Smart("Throughput performance")}, {0x03, new Smart("Spinup time")}, {0x04, new Smart("Start/Stop count")}, {0x05, new Smart("Reallocated sector count")}, {0x06, new Smart("Read channel margin")}, {0x07, new Smart("Seek error rate")}, {0x08, new Smart("Seek timer performance")}, {0x09, new Smart("Power-on hours count")}, {0x0A, new Smart("Spinup retry count")}, {0x0B, new Smart("Calibration retry count")}, {0x0C, new Smart("Power cycle count")}, {0x0D, new Smart("Soft read error rate")}, {0xB8, new Smart("End-to-End error")}, {0xBE, new Smart("Airflow Temperature")}, {0xBF, new Smart("G-sense error rate")}, {0xC0, new Smart("Power-off retract count")}, {0xC1, new Smart("Load/Unload cycle count")}, {0xC2, new Smart("HDD temperature")}, {0xC3, new Smart("Hardware ECC recovered")}, {0xC4, new Smart("Reallocation count")}, {0xC5, new Smart("Current pending sector count")}, {0xC6, new Smart("Offline scan uncorrectable count")}, {0xC7, new Smart("UDMA CRC error rate")}, {0xC8, new Smart("Write error rate")}, {0xC9, new Smart("Soft read error rate")}, {0xCA, new Smart("Data Address Mark errors")}, {0xCB, new Smart("Run out cancel")}, {0xCC, new Smart("Soft ECC correction")}, {0xCD, new Smart("Thermal asperity rate (TAR)")}, {0xCE, new Smart("Flying height")}, {0xCF, new Smart("Spin high current")}, {0xD0, new Smart("Spin buzz")}, {0xD1, new Smart("Offline seek performance")}, {0xDC, new Smart("Disk shift")}, {0xDD, new Smart("G-sense error rate")}, {0xDE, new Smart("Loaded hours")}, {0xDF, new Smart("Load/unload retry count")}, {0xE0, new Smart("Load friction")}, {0xE1, new Smart("Load/Unload cycle count")}, {0xE2, new Smart("Load-in time")}, {0xE3, new Smart("Torque amplification count")}, {0xE4, new Smart("Power-off retract count")}, {0xE6, new Smart("GMR head amplitude")}, {0xE7, new Smart("Temperature")}, {0xF0, new Smart("Head flying hours")}, {0xFA, new Smart("Read error retry rate")}, /* slot in any new codes you find in here */ }; } public class Smart { public bool HasData { get { if (Current == 0 && Worst == 0 && Threshold == 0 && Data == 0) return false; return true; } } public string Attribute { get; set; } public int Current { get; set; } public int Worst { get; set; } public int Threshold { get; set; } public int Data { get; set; } public bool IsOK { get; set; } public Smart() { } public Smart(string attributeName) { this.Attribute = attributeName; } } /// <summary> /// Tested against Crystal Disk Info 5.3.1 and HD Tune Pro 3.5 on 15 Feb 2013. /// Findings; I do not trust the individual smart register "OK" status reported back frm the drives. /// I have tested faulty drives and they return an OK status on nearly all applications except HD Tune. /// After further research I see HD Tune is checking specific attribute values against their thresholds /// and and making a determination of their own (which is good) for whether the disk is in good condition or not. /// I recommend whoever uses this code to do the same. For example --> /// "Reallocated sector count" - the general threshold is 36, but even if 1 sector is reallocated I want to know about it and it should be flagged. /// </summary> public class Program { public static void Main() { try { // retrieve list of drives on computer (this will return both HDD's and CDROM's and Virtual CDROM's) var dicDrives = new Dictionary<int, HDD>(); var wdSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive"); // extract model and interface information int iDriveIndex = 0; foreach (ManagementObject drive in wdSearcher.Get()) { var hdd = new HDD(); hdd.Model = drive["Model"].ToString().Trim(); hdd.Type = drive["InterfaceType"].ToString().Trim(); dicDrives.Add(iDriveIndex, hdd); iDriveIndex++; } var pmsearcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia"); // retrieve hdd serial number iDriveIndex = 0; foreach (ManagementObject drive in pmsearcher.Get()) { // because all physical media will be returned we need to exit // after the hard drives serial info is extracted if (iDriveIndex >= dicDrives.Count) break; dicDrives[iDriveIndex].Serial = drive["SerialNumber"] == null ? "None" : drive["SerialNumber"].ToString().Trim(); iDriveIndex++; } // get wmi access to hdd var searcher = new ManagementObjectSearcher("Select * from Win32_DiskDrive"); searcher.Scope = new ManagementScope(@"\root\wmi"); // check if SMART reports the drive is failing searcher.Query = new ObjectQuery("Select * from MSStorageDriver_FailurePredictStatus"); iDriveIndex = 0; foreach (ManagementObject drive in searcher.Get()) { dicDrives[iDriveIndex].IsOK = (bool)drive.Properties["PredictFailure"].Value == false; iDriveIndex++; } // retrive attribute flags, value worste and vendor data information searcher.Query = new ObjectQuery("Select * from MSStorageDriver_FailurePredictData"); iDriveIndex = 0; foreach (ManagementObject data in searcher.Get()) { Byte[] bytes = (Byte[])data.Properties["VendorSpecific"].Value; for (int i = 0; i < 30; ++i) { try { int id = bytes[i * 12 + 2]; int flags = bytes[i * 12 + 4]; // least significant status byte, +3 most significant byte, but not used so ignored. //bool advisory = (flags & 0x1) == 0x0; bool failureImminent = (flags & 0x1) == 0x1; //bool onlineDataCollection = (flags & 0x2) == 0x2; int value = bytes[i * 12 + 5]; int worst = bytes[i * 12 + 6]; int vendordata = BitConverter.ToInt32(bytes, i * 12 + 7); if (id == 0) continue; var attr = dicDrives[iDriveIndex].Attributes[id]; attr.Current = value; attr.Worst = worst; attr.Data = vendordata; attr.IsOK = failureImminent == false; } catch { // given key does not exist in attribute collection (attribute not in the dictionary of attributes) } } iDriveIndex++; } // retreive threshold values foreach attribute searcher.Query = new ObjectQuery("Select * from MSStorageDriver_FailurePredictThresholds"); iDriveIndex = 0; foreach (ManagementObject data in searcher.Get()) { Byte[] bytes = (Byte[])data.Properties["VendorSpecific"].Value; for (int i = 0; i < 30; ++i) { try { int id = bytes[i * 12 + 2]; int thresh = bytes[i * 12 + 3]; if (id == 0) continue; var attr = dicDrives[iDriveIndex].Attributes[id]; attr.Threshold = thresh; } catch { // given key does not exist in attribute collection (attribute not in the dictionary of attributes) } } iDriveIndex++; } // print foreach (var drive in dicDrives) { Console.WriteLine("-----------------------------------------------------"); Console.WriteLine(" DRIVE ({0}): " + drive.Value.Serial + " - " + drive.Value.Model + " - " + drive.Value.Type, ((drive.Value.IsOK) ? "OK" : "BAD")); Console.WriteLine("-----------------------------------------------------"); Console.WriteLine(""); Console.WriteLine("ID Current Worst Threshold Data Status"); foreach (var attr in drive.Value.Attributes) { if (attr.Value.HasData) Console.WriteLine("{0}\t {1}\t {2}\t {3}\t " + attr.Value.Data + " " + ((attr.Value.IsOK) ? "OK" : ""), attr.Value.Attribute, attr.Value.Current, attr.Value.Worst, attr.Value.Threshold); } Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); } Console.ReadLine(); } catch (ManagementException e) { Console.WriteLine("An error occurred while querying for WMI data: " + e.Message); } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д