Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

S.M.A.R.T. Hard Drive Data in C#

Tags:

c#

wmi

disk-smart

Just trying to pull off some SMART info from connected Hard Drives on any computer my application will run on.

I'm using WMI for a lot of other stuff in the program, and every question about SMART I've looked at makes reference to Win32_DiskDrive. However, the data in here is really quite minimal and probably not SMART - I'm searching for information such as 'Spin Retry Count'. Any ideas?

like image 767
Chris Watts Avatar asked Feb 19 '12 18:02

Chris Watts


1 Answers

You are using the wrong class (you want MSStorageDriver_ATAPISmartData). To change what attribute you want change byte SpinRetryCount = 0x0A; to whatever value you wish (e.g. 0x02 for throughput performance)

[StructLayout(LayoutKind.Sequential)]
        public struct Attribute
        {
            public byte AttributeID;
            public ushort Flags;
            public byte Value;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] VendorData;
        }

        static void getSMARTAttr()
        {
            try
            {
                Attribute AtributeInfo;
                ManagementScope Scope = new ManagementScope(String.Format("\\\\{0}\\root\\WMI", "localhost"), null);
                Scope.Connect();
                ObjectQuery Query = new ObjectQuery("SELECT VendorSpecific FROM MSStorageDriver_ATAPISmartData");
                ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
                byte SpinRetryCount = 0x0A;
                int Delta = 12;
                foreach (ManagementObject WmiObject in Searcher.Get())
                {
                    byte[] VendorSpecific = (byte[])WmiObject["VendorSpecific"];
                    for (int offset = 2; offset < VendorSpecific.Length; )
                    {
                        if (VendorSpecific[offset] == SpinRetryCount)
                        {

                            IntPtr buffer = IntPtr.Zero;
                            try
                            {
                                buffer = Marshal.AllocHGlobal(Delta);
                                Marshal.Copy(VendorSpecific, offset, buffer, Delta);
                                AtributeInfo = (Attribute)Marshal.PtrToStructure(buffer, typeof(Attribute));
                                Console.WriteLine("AttributeID {0}", AtributeInfo.AttributeID);
                                Console.WriteLine("Flags {0}", AtributeInfo.Flags);
                                Console.WriteLine("Value {0}", AtributeInfo.Value);
                                //if you want HEX values use this line
                                //Console.WriteLine("Value {0}", BitConverter.ToString(AtributeInfo.VendorData));
                                //if you want INT values use this line
                                Console.WriteLine("Data {0}", BitConverter.ToInt32(AtributeInfo.VendorData, 0));
                            }
                            finally
                            {
                                if (buffer != IntPtr.Zero)
                                {
                                    Marshal.FreeHGlobal(buffer);
                                }
                            }
                        }
                        offset += Delta;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(String.Format("Exception {0} Trace {1}", e.Message, e.StackTrace));
            }
            Console.WriteLine("Press Enter to exit");
            Console.Read();
        }

And remember that if you get anything other than 0, you need to buy a new hard drive! Also this code requires UAC elevation, so you need to run the application as an administrator or you will get an exception.

like image 68
Lyuben Todorov Avatar answered Sep 19 '22 16:09

Lyuben Todorov