转换WMI HDD序列号

我有一些代码从WMI获取硬盘序列号。

SelectQuery selectQuery = new SelectQuery("Win32_PhysicalMedia"); ManagementObjectSearcher searcher = new ManagementObjectSearcher(selectQuery); foreach (ManagementObject wmi_PM in searcher.Get()) { string str = wmi_PM["SerialNumber"]; } 

起初我以为它正在工作并检索到正确的序列号。 在尝试使用它进行比较之后,我发现WMI报告的数字并不完全正确。 WMI序列号用一堆空格填充,并且字符被转置。

贴纸上打印并由某些工具(可能使用DeviceIoControl)返回的实际驱动器序列号为“3RH8B1BG”,但WMI返回“R38H1BGB”。

Real Serial#:3RH8B1BG
WMI Serial#:R38H1BGB

一些工具,如SiSoftware Sandra,返回这个填充和转置的数字,但它不是实际的序列号。 如果您转换每个其他位置,WMI值是序列号。 这是正常的吗? 我应该只编码将其转换为正确的值吗?

我试图避免使用WMI,但似乎任何搜索如何在网上做某事现在带回WMI示例。

不同制造商的2个不同硬盘的WMI值序列号都被转置,因此它不是单个磁盘。

更新:使用DeviceIoControl找到一些代码

http://addressof.com/blog/archive/2004/02/14/392.aspx

令人惊讶的是,DeviceIoControl也返回转置的序列号。 在上面的CorySmith代码中,它有一个SwapChars函数

 Private Shared Function SwapChars(ByVal chars() As Char) As String For i As Integer = 0 To chars.Length - 2 Step 2 chars.Reverse(chars, i, 2) Next Return New String(chars).Trim End Function 

他提到的c ++代码有以下几点:

  // function to decode the serial numbers of IDE hard drives // using the IOCTL_STORAGE_QUERY_PROPERTY command char * flipAndCodeBytes (const char * str, int pos, int flip, char * buf) { ... } 

猜测这是DeviceIoControl和WMI的标准,不能相信我遇到的任何其他解决方案或示例都没有。

找到了解决真正的HD-Serials的工作解决方案。 以下链接包含即使没有管理员权限也要解码的代码: 解码源

但是如果你从Vista上面的Win32_PhysicalMedia WMI类中获得Serials,它可能无法在所有情况下使用。 然后你必须使用Win32_DiskDrive类(根据这个链接: Jiliang Ge的答案,从2009年10月27日星期二上午3:12

我添加了代码(在VB中,因为我通常在VB.NET中编写代码)。 我不想偷别人的代码。 我在代码中包含了尽可能多的信息,还有一些指向原始编码器的链接。 它现在还包括解码可移动驱动器中的Serialnumbers(在相同的例程中)。

希望能帮助到你。

  '''  ''' Decode Manufacuter Disk Serialnumbers (also for PNP USB-Drives) '''  ''' InterfaceType from Win32_DiskDrive WMI-Class ''' PNPDeviceID from Win32_DiskDrive WMI-Class ''' Raw Serialnumber to be decoded ''' Decoded Serialnumber '''  Public Shared Function Decode_HD_Serial(ByVal InterfaceType As String, ByVal PNPDeviceID As String, ByVal strVolumeSerial As String) As String 'HANDLE USB PNP Devices differently (Removable USB-Sticks) 'see: http://www.experts-exchange.com/Programming/Languages/.NET/Q_24574066.html If InterfaceType = "USB" Then Dim splitDeviceId As String() = PNPDeviceID.Split("\"c) Dim arrayLen As Integer = splitDeviceId.Length - 1 Dim serialArray As String() = splitDeviceId(arrayLen).Split("&"c) Return serialArray(0) Else 'Link:https://social.msdn.microsoft.com/Forums/vstudio/en-US/8523d7b9-0dc8-4d87-be69-a482aec9ee5e/wmi-win32physicalmedia-smart-id-in-vista-and-7-permissions?forum=netfxbcl 'After digging into the [Win32_PhysicalMedia] WMI class, I find that from Vista/Longhorn the 'class has been taken over by another class called [Win32_DiskDrive]. Thus, if all machines 'in your environment are Vista and above use the second class otherwise use the first one. 'Based on my tests, the class gives the unique form of serial number when you run the 'app as an admin or as a non-admin. ' ---> IF System.Environment.OSVersion.Version.Major > 5 then its Vista or higher. USE WIN32_DiskDrive Dim strVolumeSerialDecoded As String = String.Empty 'Remove all space characters ("20"). 'Example : 20202020205635424544434553 will be 5635424544434553. strVolumeSerial.Trim.Replace("20", "") 'IF THE USER IS ADMINISTRATOR, THE strVolumeSerial STRING WILL ALREADY CONTAIN THE SERIAL NUMBER IN ASCII, AND NO CONVERSION IS REQUIRED (Microsoft bug ?), 'BUT IF THE strVolumeSerial STRING IS A HEX STRING, CONVERT IT TO ASCII : If System.Text.RegularExpressions.Regex.IsMatch(strVolumeSerial, "^[a-fA-F0-9]+$") Then 'Convert to ASCII. Example : 5635424544434553 will be converted to V5BEDCES. strVolumeSerial = HexDecode(strVolumeSerial) 'Swap pairs of characters. 'Example : V5BEDCES will be converted to 5VEBCDSE. Dim serialNumber2 As String = "" For i As Integer = 0 To strVolumeSerial.Length - 1 Step 2 strVolumeSerialDecoded &= strVolumeSerial(i + 1) strVolumeSerialDecoded &= strVolumeSerial(i) Next 'Return the serialnumber as ASCII string. Return strVolumeSerialDecoded.Trim Else 'If strVolumeSerial is ASCII, remove spaces and return the serialnumber string. Return strVolumeSerial.Trim End If End If End Function ''' Decodes a HEX-string to an ASCII string. ''' The HEX-string to decode. ''' If succeeded, the decoded String, an empty String if failed. Private Shared Function HexDecode(ByVal strHEX As String) As String Try Dim sb As StringBuilder = New StringBuilder For i As Integer = 0 To strHEX.Length - 1 Step 2 sb.Append(Convert.ToChar(Convert.ToUInt32(strHEX.Substring(i, 2), 16)).ToString) Next Return sb.ToString Catch ex As Exception Return "" End Try End Function