2013-02-04 77 views
6

我在尋找的代碼,這將使得一個硬盤的SMART註冊(使用WMI或其他),最好是在以下或類似格式:C#WMI HDD SMART

註冊名稱 - 當前值,最差值,閾值,數據(供應商)和SMART狀態。

到目前爲止,我發現的許多WMI實現都沒有提供閾值或缺少一個或多個標準SMART字段(即Current,Worst,Threshold)。

+0

也許http://stackoverflow.com/questions/9352017/smart-hard-drive-data-in-c-sharp – t3hn00b

+0

不幸的是,我測試了我在Stackoverflow.com上找到的所有「C#HDD SMART」解決方案。 – TheLegendaryCopyCoder

回答

13

經過一番努力,我已經將代碼返回給使用C#/ WMI的HDD的所有相關SMART信息的綜合報告。

由於從here繪製,這是代碼:

/* 
Copyright (c) 2013, Llewellyn Kruger 
All rights reserved. 
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 「AS IS」 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/ 
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); 
     } 
    } 
    } 

更新 - 2017年12月19日

我已經把一個類庫,它簡化了查詢所有的智能數據你需要。它包含一個演示項目。

GitHub庫:Smart.Net Library

用法:

var drives = Simplified.IO.Smart.GetDrives(); // Static Method 
+1

請注意,由於兩個原因,不鼓勵裸鏈接到您自己的網站/產品;首先,答案應作爲獨立答案發布,而不是僅僅連接到外部網站。其次,自我推銷往往會在這裏被忽視,並且經常被標記爲垃圾郵件(特別是如果沒有披露您將鏈接到您自己的網站/產品)。 –

+9

嗨,安德魯,我現在只有時間現在回覆。 看着stackoverflow我看到很多隻是簡單的鏈接的答案。我在這種情況下也做了同樣的事情,但沒有看到問題。其次,關於你對自我推銷的評論;我對別人不滿意的是什麼。事實是,沒有人提供解決我的問題。我花了我的時間和金錢把解決方案放在一起並與世界分享。 像你的影響的評論stackoverflow組跟隨套件和投票一個很好的答案。沒有人贏。 – TheLegendaryCopyCoder

+0

不再鏈接到博客,有關此代碼的鏈接中沒有任何信息。這就是爲什麼堆棧溢出更喜歡沒有一個線路鏈接的答案。 – VampyreSix