获取硬盘序列号

31

我想获取硬盘序列号,该怎么办?我试过两个代码但是没有得到结果。

StringCollection propNames = new StringCollection();
ManagementClass driveClass = new ManagementClass("Win32_DiskDrive");
PropertyDataCollection  props = driveClass.Properties;
foreach (PropertyData driveProperty in props) 
{
    propNames.Add(driveProperty.Name);
}
int idx = 0;
ManagementObjectCollection drives = driveClass.GetInstances();
foreach (ManagementObject drv in drives)
       {
          Label2.Text+=(idx + 1);
          foreach (string strProp in propNames)
           {
            //Label2.Text+=drv[strProp];
         Response.Write(strProp + "   =   " + drv[strProp] + "</br>");
          }
    }

在这个问题中,我没有得到任何唯一的序列号。
第二个问题是

string drive = "C";
ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"" + drive + ":\"");
disk.Get();
Label3.Text = "VolumeSerialNumber="+ disk["VolumeSerialNumber"].ToString();

在这里我正在获取 VolumeSerialNumber。 但它不是唯一的。如果我格式化硬盘,这将发生变化。我该如何获取它?

10个回答

40

看了一下你的第一段代码,我想你已经获取(或许是?)了硬盘型号。序列号来自于Win32_PhysicalMedia

获取硬盘型号

    ManagementObjectSearcher searcher = new
    ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");

   foreach(ManagementObject wmi_HD in searcher.Get())
   {
    HardDrive hd = new HardDrive();
    hd.Model = wmi_HD["Model"].ToString();
    hd.Type  = wmi_HD["InterfaceType"].ToString(); 
    hdCollection.Add(hd);
   }

获取串行号

 searcher = new
    ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia");

   int i = 0;
   foreach(ManagementObject wmi_HD in searcher.Get())
   {
    // get the hard drive from collection
    // using index
    HardDrive hd = (HardDrive)hdCollection[i];

    // get the hardware serial no.
    if (wmi_HD["SerialNumber"] == null)
     hd.SerialNo = "None";
    else
     hd.SerialNo = wmi_HD["SerialNumber"].ToString();

    ++i;
   }

来源

希望这会有所帮助 :)


1
你是不是想两次发布相同的源代码? - dotalchemy
2
我现在无法编译,但我注意到这篇文章是从2004年发布的,也许它在Vista/7上不起作用?当我使用已编译的exe文件时,在我的Win7x64上实际上只出现了一个错误"CLR20r3"。 - Sprunth
1
如果用户没有管理员权限,它能工作吗?我现有的代码可以在用户拥有管理员权限时获取信息。但是,如果我尝试使用同一应用程序来自不具备管理员权限的不同用户,则无法执行该操作。 - Sangram Nandkhile
我在WinXp SP3上尝试了这个.. wmi_HD ["SerialNumber"] 返回null.. 有什么解决办法吗? - Mullaly
1
为什么我的测试失败了!(win7_X64 sp1)“Win32_PhysicalMedia”集合的计数比“Win32_DiskDrive”集合的计数要大。您有解决方案吗? - huoxudong125
@Sprunth,我已经获取了所有连接的硬盘驱动器,但是如何获取可引导的硬盘呢? - Abdulsalam Elsharif

12

我在一个项目中使用了以下方法,它已经成功运行。

private string identifier(string wmiClass, string wmiProperty)
//Return a hardware identifier
{
    string result = "";
    System.Management.ManagementClass mc = new System.Management.ManagementClass(wmiClass);
    System.Management.ManagementObjectCollection moc = mc.GetInstances();
    foreach (System.Management.ManagementObject mo in moc)
    {
        //Only get the first one
        if (result == "")
        {
            try
            {
                result = mo[wmiProperty].ToString();
                break;
            }
            catch
            {
            }
        }
    }
    return result;
}

您可以按照以下方式调用上述方法:

string modelNo = identifier("Win32_DiskDrive", "Model");
string manufatureID = identifier("Win32_DiskDrive", "Manufacturer");
string signature = identifier("Win32_DiskDrive", "Signature");
string totalHeads = identifier("Win32_DiskDrive", "TotalHeads");
如果您需要一个唯一标识符,请使用这些ID的组合。

谢谢您的回复......在格式化硬盘后,这个值会重复吗? - Joby

8

@Sprunth的答案有一个简单的方法。

private void GetAllDiskDrives()
    {
        var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");

        foreach (ManagementObject wmi_HD in searcher.Get())
        {
            HardDrive hd = new HardDrive();
            hd.Model = wmi_HD["Model"].ToString();
            hd.InterfaceType = wmi_HD["InterfaceType"].ToString();
            hd.Caption = wmi_HD["Caption"].ToString();

            hd.SerialNo =wmi_HD.GetPropertyValue("SerialNumber").ToString();//get the serailNumber of diskdrive

            hdCollection.Add(hd);
        }

 }


public class HardDrive
{
    public string Model { get; set; }
    public string InterfaceType { get; set; }
    public string Caption { get; set; }
    public string SerialNo { get; set; }
}

3
这里有一些可能会有所帮助的代码:
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");

string serial_number="";

foreach (ManagementObject wmi_HD in searcher.Get())
{
    serial_number = wmi_HD["SerialNumber"].ToString();
}

MessageBox.Show(serial_number);

2
欢迎来到 Stack Overflow。显然这个答案付出了很多努力,如果仅仅是代码可能会难以理解。通常在解决方案中加上几句注释是非常有必要的。请编辑你的答案并添加一些解释说明。同时,在你提交答案之前记得格式化代码。 - Mika Sundland

3
使用"vol" shell命令并从其输出中解析串行号,就像这样。至少在Win7上有效。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CheckHD
{
        class HDSerial
        {
            const string MY_SERIAL = "F845-BB23";
            public static bool CheckSerial()
            {
                string res = ExecuteCommandSync("vol");
                const string search = "Number is";
                int startI = res.IndexOf(search, StringComparison.InvariantCultureIgnoreCase);

                if (startI > 0)
                {
                    string currentDiskID = res.Substring(startI + search.Length).Trim();
                    if (currentDiskID.Equals(MY_SERIAL))
                        return true;
                }
                return false;
            }

            public static string ExecuteCommandSync(object command)
            {
                try
                {
                    // create the ProcessStartInfo using "cmd" as the program to be run,
                    // and "/c " as the parameters.
                    // Incidentally, /c tells cmd that we want it to execute the command that follows,
                    // and then exit.
                    System.Diagnostics.ProcessStartInfo procStartInfo =
                        new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);

                    // The following commands are needed to redirect the standard output.
                    // This means that it will be redirected to the Process.StandardOutput StreamReader.
                    procStartInfo.RedirectStandardOutput = true;
                    procStartInfo.UseShellExecute = false;
                    // Do not create the black window.
                    procStartInfo.CreateNoWindow = true;
                    // Now we create a process, assign its ProcessStartInfo and start it
                    System.Diagnostics.Process proc = new System.Diagnostics.Process();
                    proc.StartInfo = procStartInfo;
                    proc.Start();
                    // Get the output into a string
                    string result = proc.StandardOutput.ReadToEnd();
                    // Display the command output.
                    return result;
                }
                catch (Exception)
                {
                    // Log the exception
                    return null;
                }
            }
        }
    }

啊,是的,在Windows的每个语言版本上都可以出色地工作。这并不意味着该命令的文本输出在俄语、日语或挪威语版本的Windows中与英语版本不同,对吧? - user
1
这个给出的是逻辑单元的串行号,而不是硬盘。 - Aferrercrafter

3

如果您的应用程序需要在没有CLR的操作系统上运行,可以使用win32 api和std字符串来解决问题。我在github上找到了这个解决方案。

#include "stdafx.h"
#include <windows.h>
#include <memory>
#include <string>

//returns the serial number of the first physical drive in a std::string or an empty std::string in case of failure
//based on http://codexpert.ro/blog/2013/10/26/get-physical-drive-serial-number-part-1/
std::string getFirstHddSerialNumber() {
    //get a handle to the first physical drive
    HANDLE h = CreateFileW(L"\\\\.\\PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if (h == INVALID_HANDLE_VALUE) return{};
    //an std::unique_ptr is used to perform cleanup automatically when returning (i.e. to avoid code duplication)
    std::unique_ptr<std::remove_pointer<HANDLE>::type, void(*)(HANDLE)> hDevice{ h, [](HANDLE handle){CloseHandle(handle); } };
    //initialize a STORAGE_PROPERTY_QUERY data structure (to be used as input to DeviceIoControl)
    STORAGE_PROPERTY_QUERY storagePropertyQuery{};
    storagePropertyQuery.PropertyId = StorageDeviceProperty;
    storagePropertyQuery.QueryType = PropertyStandardQuery;
    //initialize a STORAGE_DESCRIPTOR_HEADER data structure (to be used as output from DeviceIoControl)
    STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader{};
    //the next call to DeviceIoControl retrieves necessary size (in order to allocate a suitable buffer)
    //call DeviceIoControl and return an empty std::string on failure
    DWORD dwBytesReturned = 0;
    if (!DeviceIoControl(hDevice.get(), IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
        &storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER), &dwBytesReturned, NULL))
        return{};
    //allocate a suitable buffer
    const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
    std::unique_ptr<BYTE[]> pOutBuffer{ new BYTE[dwOutBufferSize]{} };
    //call DeviceIoControl with the allocated buffer
    if (!DeviceIoControl(hDevice.get(), IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY),
        pOutBuffer.get(), dwOutBufferSize, &dwBytesReturned, NULL))
        return{};
    //read and return the serial number out of the output buffer
    STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(pOutBuffer.get());
    const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
    if (dwSerialNumberOffset == 0) return{};
    const char* serialNumber = reinterpret_cast<const char*>(pOutBuffer.get() + dwSerialNumberOffset);
    return serialNumber;
}

#include <iostream>
int main() {
    std::string serialNumber = getFirstHddSerialNumber();
    if (serialNumber.empty())
        std::cout << "failed to retrieve serial number\n";
    else
        std::cout << "serial number: " << serialNumber << "\n";
    return 0;
}

感谢您发布一个非 WMI 解决方案。 - Randall Deetz

1

如果您想将其用于复制保护,并且需要在一台计算机上始终返回相同的序列号(当然,只要第一个硬盘驱动器或固态硬盘没有更改),我建议使用以下代码。对于ManagementClass,您需要添加对System.Management的引用。 P.S. 如果没有“InterfaceType”和“DeviceID”检查,则该方法可能会返回随机磁盘的序列号或连接到计算机的USB闪存驱动器的序列号。

    public static string GetSerial()
    {
        try
        {
            var mc = new ManagementClass("Win32_DiskDrive");
            var moc = mc.GetInstances();
            var res = string.Empty;
            var resList = new List<string>(moc.Count);

            foreach (ManagementObject mo in moc)
            {
                try
                {
                    if (mo["InterfaceType"].ToString().Replace(" ", string.Empty) == "USB")
                    {
                        continue;
                    }
                }
                catch
                {
                }

                try
                {
                    res = mo["SerialNumber"].ToString().Replace(" ", string.Empty);
                    resList.Add(res);
                    if (mo["DeviceID"].ToString().Replace(" ", string.Empty).Contains("0"))
                    {
                        if (!string.IsNullOrWhiteSpace(res))
                        {
                            return res;
                        }
                    }
                }
                catch
                {
                }
            }

            res = resList[0];
            if (!string.IsNullOrWhiteSpace(res))
            {
                return res;
            }
        }
        catch
        {
        }

        return string.Empty;
    }

0

以下是一个完全可用的方法,用于获取硬盘序列号:

public string GetHardDiskSerialNo()
    {
        ManagementClass mangnmt = new ManagementClass("Win32_LogicalDisk");
        ManagementObjectCollection mcol = mangnmt.GetInstances();
        string result = "";
        foreach (ManagementObject strt in mcol)
        {
            result += Convert.ToString(strt["VolumeSerialNumber"]);
        }
        return result;
    }

逻辑磁盘序列号与硬盘序列号不同,您可以尝试并查看它们的差异。 - Aferrercrafter

0

我正在使用这个:

<!-- language: c# -->
private static string wmiProperty(string wmiClass, string wmiProperty){
  using (var searcher = new ManagementObjectSearcher($"SELECT * FROM {wmiClass}")) {
   try {
                    IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
                    return objects.Select(x => x.GetPropertyValue(wmiProperty)).FirstOrDefault().ToString().Trim();
                } catch (NullReferenceException) {
                    return null;
                }
            }
        }

0

我发现最好的方法是从这里下载一个dll文件。

然后将该dll文件添加到您的项目中。

接着,加入以下代码:

[DllImportAttribute("HardwareIDExtractorC.dll")]
public static extern String GetIDESerialNumber(byte DriveNumber);

然后,从需要它的地方调用硬盘ID

GetIDESerialNumber(0).Replace(" ", string.Empty);

注意:在资源管理器中进入dll的属性,将“生成操作”设置为“嵌入的资源”。

你还有这个dll文件吗? - DreTaX
该dll文件可以在此处下载:http://www.soft.tahionic.com/download-hdd_id/free-download/free%20download.html - Amit Mittal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接