如何在Windows系统中获取NVMe设备的S.M.A.R.T.数据
可行获取方案汇总
方案1:PowerShell原生方案(无需额外依赖)
Windows 10 1903及以上版本可直接使用内置存储类获取NVMe SMART数据,需管理员权限运行PowerShell:
- 获取基础健康信息命令:
# 获取所有NVMe磁盘的SMART统计数据 Get-PhysicalDisk | Where-Object {$_.MediaType -eq 'SSD' -and $_.BusType -eq 'NVMe'} | Get-StorageReliabilityCounter
- 导出完整结构化属性的进阶脚本:
$nvmeDisks = Get-CimInstance -Namespace root\Microsoft\Windows\Storage -ClassName MSFT_PhysicalDisk | Where-Object {$_.BusType -eq 17} # 17为NVMe总线类型对应编号 foreach ($disk in $nvmeDisks) { $reliability = Get-CimAssociatedInstance -InputObject $disk -ResultClassName MSFT_StorageReliabilityCounter [PSCustomObject]@{ 磁盘型号 = $disk.FriendlyName 序列号 = $disk.SerialNumber 健康状态 = $disk.HealthStatus 当前温度 = $reliability.Temperature 累计写入字节 = $reliability.TotalBytesWritten 累计读取字节 = $reliability.TotalBytesRead 通电总时长 = $reliability.PowerOnHours 不安全关机次数 = $reliability.UnsafeShutdownCount } }
方案2:免开发工具方案
无需自行编码的场景可直接使用smartctl工具,安装对应Windows版本后运行以下命令即可输出全量SMART数据:
smartctl -a /dev/nvme0
其中nvme0对应系统识别的第一块NVMe磁盘,多磁盘可依次替换为nvme1、nvme2等。
方案3:可直接运行的C#代码方案(对应Windows官方API实现)
以下代码兼容Windows 10及以上版本,需以管理员权限运行,.NET Framework 4.5+、.NET Core 3.0+均可直接编译:
using System; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; public class NvmeSmartReader { private const uint IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400; private const uint StorageAdapterProtocolSpecificProperty = 0x15; private const uint PropertyStandardQuery = 0; private const byte NVME_PROTOCOL_TYPE = 0x1E; private const uint NVME_LOG_PAGE_SMART = 0x2; [StructLayout(LayoutKind.Sequential)] private struct STORAGE_PROPERTY_QUERY { public uint PropertyId; public uint QueryType; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public byte[] AdditionalParameters; } [StructLayout(LayoutKind.Sequential)] private struct STORAGE_PROTOCOL_SPECIFIC_DATA { public uint ProtocolType; public uint DataType; public uint ProtocolDataRequestValue; public uint ProtocolDataRequestSubValue; public uint ProtocolDataOffset; public uint ProtocolDataLength; public uint FixedProtocolReturnData; public uint Reserved; } [StructLayout(LayoutKind.Sequential)] private struct NVME_SMART_INFO { public byte CriticalWarning; public ushort CompositeTemperature; public byte AvailableSpare; public byte AvailableSpareThreshold; public byte PercentageUsed; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] public byte[] Reserved1; public ulong DataUnitsRead; public ulong DataUnitsWritten; public ulong HostReadCommands; public ulong HostWriteCommands; public ulong ControllerBusyTime; public ulong PowerCycles; public ulong PowerOnHours; public ulong UnsafeShutdowns; public ulong MediaErrors; public ulong NumErrLogEntries; } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool DeviceIoControl(SafeFileHandle hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped); [DllImport("kernel32.dll")] private static extern void ZeroMemory(IntPtr dst, int length); public static NVME_SMART_INFO ReadNvmeSmart(int diskNumber) { string path = $"\\\\.\\PhysicalDrive{diskNumber}"; var handle = CreateFile(path, 0x80000000 | 0x40000000, 0x1 | 0x2, IntPtr.Zero, 3, 0, IntPtr.Zero); if (handle.IsInvalid) throw new System.ComponentModel.Win32Exception(); int querySize = Marshal.SizeOf(typeof(STORAGE_PROPERTY_QUERY)) + Marshal.SizeOf(typeof(STORAGE_PROTOCOL_SPECIFIC_DATA)); IntPtr queryBuffer = Marshal.AllocHGlobal(querySize); ZeroMemory(queryBuffer, querySize); STORAGE_PROPERTY_QUERY query = new STORAGE_PROPERTY_QUERY(); query.PropertyId = StorageAdapterProtocolSpecificProperty; query.QueryType = PropertyStandardQuery; Marshal.StructureToPtr(query, queryBuffer, false); STORAGE_PROTOCOL_SPECIFIC_DATA protocolData = new STORAGE_PROTOCOL_SPECIFIC_DATA(); protocolData.ProtocolType = NVME_PROTOCOL_TYPE; protocolData.DataType = NVME_LOG_PAGE_SMART; protocolData.ProtocolDataRequestValue = NVME_LOG_PAGE_SMART; protocolData.ProtocolDataOffset = (uint)Marshal.SizeOf(typeof(STORAGE_PROPERTY_QUERY)) + (uint)Marshal.SizeOf(typeof(STORAGE_PROTOCOL_SPECIFIC_DATA)); protocolData.ProtocolDataLength = (uint)Marshal.SizeOf(typeof(NVME_SMART_INFO)); Marshal.StructureToPtr(protocolData, queryBuffer + Marshal.SizeOf(typeof(STORAGE_PROPERTY_QUERY)), false); uint outputSize = (uint)(querySize + Marshal.SizeOf(typeof(NVME_SMART_INFO))); IntPtr outputBuffer = Marshal.AllocHGlobal((int)outputSize); ZeroMemory(outputBuffer, (int)outputSize); bool success = DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, queryBuffer, (uint)querySize, outputBuffer, outputSize, out uint bytesReturned, IntPtr.Zero); if (!success) throw new System.ComponentModel.Win32Exception(); NVME_SMART_INFO smartInfo = Marshal.PtrToStructure<NVME_SMART_INFO>(outputBuffer + querySize); Marshal.FreeHGlobal(queryBuffer); Marshal.FreeHGlobal(outputBuffer); handle.Close(); return smartInfo; } // 调用示例 public static void Main() { // 磁盘编号可在系统磁盘管理中查看,0为第一块物理磁盘 var smartData = ReadNvmeSmart(0); Console.WriteLine($"当前温度:{smartData.CompositeTemperature - 273}℃"); Console.WriteLine($"通电总时长:{smartData.PowerOnHours} 小时"); Console.WriteLine($"累计写入量:{smartData.DataUnitsWritten * 512 / 1024 / 1024 / 1024} GB"); } }
内容的提问来源于stack exchange,提问作者Evtim Kostadinov
相关产品推荐
相关产品推荐

