WMI 硬盘序列号已转置

本文关键字:转置 序列号 硬盘 WMI | 更新日期: 2023-09-27 18:37:02

我有一些代码可以从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"。

真实型号#: 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的标准,不敢相信我遇到的任何其他解决方案或示例都没有这个。

WMI 硬盘序列号已转置

找到了一个有效的解决方案来解码真正的高清连续剧。以下链接包含即使没有管理员权限也要解码的代码:解码源

但是,如果您从 Vista 上方的 Win32_PhysicalMedia WMI 类获取序列号,则可能无法在所有情况下都有效。然后你必须使用Win32_DiskDrive类(根据这个链接: 葛继良的回答 从 星期二, 十月 27, 2009 3:12 上午

我添加了代码(在 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