5

I know a bit of C++ and Java, but am wanting to learn c# on my own. To mess with, I'm trying to read the SMART data of my hard drive. I have this C# Code, but I do not know how to modify it to read an additional memory value: It apparently reads the 'Value' value but not the 'Worst' or 'Threshold' value. I want to add these two data values (Worst and Threshold) to the program. Figuring how to do this will help me learn C# a little.

C# Example: (What I want to use)

// (c) Microsoft Corporation
// Author: Clemens Vasters ([email protected])
// Code subject to MS-PL: http://opensource.org/licenses/ms-pl.html 
// SMART Attributes and Background: http://en.wikipedia.org/wiki/S.M.A.R.T.
// SMART Attributes Overview: http://www.t13.org/Documents/UploadedDocuments/docs2005/e05171r0-ACS-SMARTAttributes_Overview.pdf
namespace SmartDataApp
{
using System;
using System.Collections.Generic;
using System.Management;
using System.Runtime.InteropServices;
public enum SmartAttributeType : byte
{
 ReadErrorRate = 0x01,
 ThroughputPerformance = 0x02,
 SpinUpTime = 0x03,
 StartStopCount = 0x04,
 ReallocatedSectorsCount = 0x05,
 ReadChannelMargin = 0x06,
 SeekErrorRate = 0x07,
 SeekTimePerformance = 0x08,
 PowerOnHoursPOH = 0x09,
 SpinRetryCount = 0x0A,
 CalibrationRetryCount = 0x0B,
 PowerCycleCount = 0x0C,
 SoftReadErrorRate = 0x0D,
 SATADownshiftErrorCount = 0xB7,
 EndtoEnderror = 0xB8,
 HeadStability = 0xB9,
 InducedOpVibrationDetection = 0xBA,
 ReportedUncorrectableErrors = 0xBB,
 CommandTimeout = 0xBC,
 HighFlyWrites = 0xBD,
 AirflowTemperatureWDC = 0xBE,
 TemperatureDifferencefrom100 = 0xBE,
 GSenseErrorRate = 0xBF,
 PoweroffRetractCount = 0xC0,
 LoadCycleCount = 0xC1,
 Temperature = 0xC2,
 HardwareECCRecovered = 0xC3,
 ReallocationEventCount = 0xC4,
 CurrentPendingSectorCount = 0xC5,
 UncorrectableSectorCount = 0xC6,
 UltraDMACRCErrorCount = 0xC7,
 MultiZoneErrorRate = 0xC8,
 WriteErrorRateFujitsu = 0xC8,
 OffTrackSoftReadErrorRate = 0xC9,
 DataAddressMarkerrors = 0xCA,
 RunOutCancel = 0xCB,
 SoftECCCorrection = 0xCC,
 ThermalAsperityRateTAR = 0xCD,
 FlyingHeight = 0xCE,
 SpinHighCurrent = 0xCF,
 SpinBuzz = 0xD0,
 OfflineSeekPerformance = 0xD1,
 VibrationDuringWrite = 0xD3,
 ShockDuringWrite = 0xD4,
 DiskShift = 0xDC,
 GSenseErrorRateAlt = 0xDD,
 LoadedHours = 0xDE,
 LoadUnloadRetryCount = 0xDF,
 LoadFriction = 0xE0,
 LoadUnloadCycleCount = 0xE1,
 LoadInTime = 0xE2,
 TorqueAmplificationCount = 0xE3,
 PowerOffRetractCycle = 0xE4,
 GMRHeadAmplitude = 0xE6,
 DriveTemperature = 0xE7,
 HeadFlyingHours = 0xF0,
 TransferErrorRateFujitsu = 0xF0,
 TotalLBAsWritten = 0xF1,
 TotalLBAsRead = 0xF2,
 ReadErrorRetryRate = 0xFA,
 FreeFallProtection = 0xFE,
}
public class SmartData
{
 readonly Dictionary<SmartAttributeType, SmartAttribute> attributes;
 readonly ushort structureVersion;
 public SmartData(byte[] arrVendorSpecific)
 {
 attributes = new Dictionary<SmartAttributeType, SmartAttribute>();
 for (int offset = 2; offset < arrVendorSpecific.Length; )
 {
 var a = FromBytes<SmartAttribute>(arrVendorSpecific, ref offset, 12);
 // Attribute values 0x00, 0xfe, 0xff are invalid
 if (a.AttributeType != 0x00 && (byte)a.AttributeType != 0xfe && (byte)a.AttributeType != 0xff)
 {
 attributes[a.AttributeType] = a;
 }
 }
 structureVersion = (ushort)(arrVendorSpecific[0] * 256 + arrVendorSpecific[1]);
 }
 public ushort StructureVersion
 {
 get
 {
 return this.structureVersion;
 }
 }
 public SmartAttribute this[SmartAttributeType v]
 {
 get
 {
 return this.attributes[v];
 }
 }
 public IEnumerable<SmartAttribute> Attributes
 {
 get
 {
 return this.attributes.Values;
 }
 }
 static T FromBytes<T>(byte[] bytearray, ref int offset, int count)
 {
 IntPtr ptr = IntPtr.Zero;
 try
 {
 ptr = Marshal.AllocHGlobal(count);
 Marshal.Copy(bytearray, offset, ptr, count);
 offset += count;
 return (T)Marshal.PtrToStructure(ptr, typeof(T));
 }
 finally
 {
 if (ptr != IntPtr.Zero)
 {
 Marshal.FreeHGlobal(ptr);
 }
 }
 }
}
[StructLayout(LayoutKind.Sequential)]
public struct SmartAttribute
{
 public SmartAttributeType AttributeType;
 public ushort Flags;
 public byte Value;
 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
 public byte[] VendorData;
 public bool Advisory
 {
 get
 {
 return (Flags & 0x1) == 0x0; // Bit 0 unset?
 }
 }
 public bool FailureImminent
 {
 get
 {
 return (Flags & 0x1) == 0x1; // Bit 0 set?
 }
 }
 public bool OnlineDataCollection
 {
 get
 {
 return (Flags & 0x2) == 0x2; // Bit 0 set?
 }
 }
}
public class Program
{
 public static void Main()
 {
 try
 {
 var searcher = new ManagementObjectSearcher("root\\WMI", "SELECT * FROM MSStorageDriver_ATAPISmartData");
 foreach (ManagementObject queryObj in searcher.Get())
 {
 Console.WriteLine("-----------------------------------");
 Console.WriteLine("MSStorageDriver_ATAPISmartData instance");
 Console.WriteLine("-----------------------------------");
 var arrVendorSpecific = (byte[])queryObj.GetPropertyValue("VendorSpecific");
 // Create SMART data from 'vendor specific' array
 var d = new SmartData(arrVendorSpecific);
 foreach (var b in d.Attributes)
 {
 Console.Write("{0} :{1} : ", b.AttributeType, b.Value);
 foreach (byte vendorByte in b.VendorData)
 {
 Console.Write("{0:x} ", vendorByte);
 }
 Console.WriteLine();
 }
 }
 }
 catch (ManagementException e)
 {
 Console.WriteLine("An error occurred while querying for WMI data: " + e.Message);
 }
 }
}

}

The big problem is in figuring out what it all means as it really is "vendor specific". The data is organised into 12 byte blocks of attribute data. The first byte of the array gives the number of attribute blocks. Each attribute block has the format:

Item Data -0 and 1Unknown usually zero -2 Attribute -3 Status -4 Unknown usually zero -5 Value -6 Worst -7,8 Raw Value -9,10,11 Unknown usually zero

I found these here: http://www.i-programmer.info/projects/38-windows/208-disk-drive-dangers.html?start=2

Mat
208k41 gold badges409 silver badges423 bronze badges
asked Dec 29, 2011 at 4:24
1
  • All this needs (And what is not understood) is how to asign the next byte after Value to a variable and save it. Should be in "public struct SmartAttribute" I believe... Commented Dec 29, 2011 at 6:58

1 Answer 1

6

Note that not all SMART HDD (excluding USB & NVME drives) info can be obtained from a single WMI query.

You need to query all the following to determine the current value, worst value, threshold, drive status and attribute status:

  • Win32_DiskDrive
  • MSStorageDriver_FailurePredictStatus
  • MSStorageDriver_FailurePredictData
  • MSStorageDriver_FailurePredictThresholds

(削除) For a comprehensive solution in C#/WMI detailing all relevant SMART HDD info see this solution http://www.know24.net/blog/C+WMI+HDD+SMART+Information.aspx (please note: I own this development blog) (削除ここまで)

Update 2023年10月24日

GitHub: https://github.com/krugertech/Krugertech.IO.Smart

Nuget: https://www.nuget.org/packages/Krugertech.IO.Smart

Feel free to contribute.

answered Feb 15, 2013 at 11:51
Sign up to request clarification or add additional context in comments.

4 Comments

Note that the assumption of the disks always returned in the same order is wrong in this original code. Here I found an improved version: derekwilson.net/blog/2017/08/26/smart
Yes, there was a bug in the original script. I've since created a class library for simpler querying of SMART data. Its on GitHub: github.com/krugertech/SMART.Net
The link is dead (oct 2023)
Thanks for letting me know. I have added the GitHub and NuGet links at the bottom of my answer. NOTE that the SMART.NET link I shared in 2019 is no longer available, as the project was renamed.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.