2012-06-12 93 views
6

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

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” 返回。

真正的连环#:3RH8B1BG
WMI序列号: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,斜面标准认为任何其他的我遇到的解决方案或例子没有这个。

+2

哇,看起来你正在[PDP-11]上运行(http://en.wikipedia.org/wiki/Endianness#Middle-endian)! – sarnold

+3

实际上,他在一台计算机上运行,​​其PDP-11的字节顺序相同。我也是。如果你正在运行Windows(不是Windows CE而不是Windows Phone),那么你也是。唯一可行的解​​决方案是调用DeviceIoControl并自己翻转字节,如找到原始海报。如果您调用WMI,那么您不知道WMI是否为您翻转了字节。 –

回答

1

找到一个工作解决方案来解码真正的HD系列。以下链接包含即使没有管理员权限也要解码的代码:Decoding Source

但是,如果您从Win32_PhysicalMedia WMI类的Vista上获得序列号,则它可能无法在所有情况下工作。然后你必须使用Win32_DiskDrive类(根据这个链接:Jiliang Ge's Answer from Tuesday, October 27, 2009 3:12 AM

我添加了代码(在VB中,因为我通常在VB.NET中编写代码)我不想窃取别人的代码。尽可能多的信息以及代码中原始编码器的一些链接,现在还包括从可移动驱动器中解码序列号(在同一例程中)。

希望它有帮助。

''' <summary> 
''' Decode Manufacuter Disk Serialnumbers (also for PNP USB-Drives) 
''' </summary> 
''' <param name="InterfaceType">InterfaceType from Win32_DiskDrive WMI-Class</param> 
''' <param name="PNPDeviceID">PNPDeviceID from Win32_DiskDrive WMI-Class</param> 
''' <param name="strVolumeSerial">Raw Serialnumber to be decoded</param> 
''' <returns>Decoded Serialnumber</returns> 
''' <remarks></remarks> 
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 

''' <summary>Decodes a HEX-string to an ASCII string.</summary> 
''' <param name="strHEX">The HEX-string to decode.</param> 
''' <returns>If succeeded, the decoded String, an empty String if failed.</returns> 
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 
+1

只是发布链接不会对任何人有任何好处。你需要在你的答案中包含相关信息。 –

+0

对不起。我只是不想窃取别人的代码。 – dragonfly