Атрибуты 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, фактически являющейся массивом из байтов. Вот код, приведённый там: [
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";
    }
}
Вот то, что вывела программа в моём случае: 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.

Решение задачи: «Атрибуты 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);
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

15   голосов , оценка 4 из 5