获取硬盘序列号

Posted

技术标签:

【中文标题】获取硬盘序列号【英文标题】:Get Hard disk serial Number 【发布时间】:2011-05-04 07:40:58 【问题描述】:

我想。我该怎么做? 我尝试了两个代码,但没有得到

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。但这不是唯一的。如果我格式化硬盘,这将改变。我怎样才能得到这个?

【问题讨论】:

【参考方案1】:

嗯,看看你的第一组代码,我想你已经检索到(也许?)硬盘模型。序列号来自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;
   

Source

希望这会有所帮助:)

【讨论】:

您的意思是两次发布相同的来源吗? 我现在无法编译,但我确实注意到这篇文章是 2004 年的,也许它不适用于 Vista/7?仅使用编译后的 exe,实际上我的 Win7x64 上出现错误“CLR20r3”。 如果用户没有管理员权限,它是否工作...如果他有管理员权限,我拥有的代码可以获取信息..但是如果我尝试使用来自没有管理员的不同用户的相同应用程序权利,没有做到这一点.. 我在 WinXp SP3 中试过这个.. wmi_HD["SerialNumber"] 返回 null.. 任何解决方案? 为什么我的测试失败了!(win7_X64 sp1) Win32_PhysicalMedia 的收藏数量大于Win32_DiskDrive 的收藏数量。您有解决方案吗? 【参考方案2】:

我在一个项目中使用了以下方法,并且效果很好。

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 的组合。

【讨论】:

感谢您的回复.....格式化HD后是否会重复相同的值?【参考方案3】:

@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; 

【讨论】:

【参考方案4】:

使用 "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 中该命令的文本输出并没有什么不同,是吗? 这里给出的是逻辑单元的序列号,而不是硬盘【参考方案5】:

这是一个使用 win32 api 和 std 字符串的解决方案,以防您需要您的应用程序在没有 CLR 的操作系统上运行。我在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 解决方案【参考方案6】:

这里有一些代码可能会有所帮助:

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);

【讨论】:

欢迎来到 SO。显然,这个答案已经付出了很多努力,如果它只是代码,可能很难掌握。通常用几句话来评论解决方案。请编辑您的答案并添加一些解释。另外,请记住在发布答案之前格式化代码。【参考方案7】:

如果您想将它用于复制保护并且您需要它在一台计算机上始终返回相同的序列号(当然,只要第一个 hdd 或 ssd 没有更改)我会推荐下面的代码。对于 ManagementClass,您需要添加对 System.Management 的引用。附:如果没有“InterfaceType”和“DeviceID”,则检查该方法是否可以返回当前连接到PC的随机磁盘序列或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;
    

【讨论】:

【参考方案8】:

我发现最好的方法是从here下载一个dll

然后,将 dll 添加到您的项目中。

然后,添加代码:

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

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

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

注意:在资源管理器中转到 dll 的属性并将“构建操作”设置为“嵌入式资源”

【讨论】:

你还有这个dll吗? DLL 在这里可用:soft.tahionic.com/download-hdd_id/free-download/…【参考方案9】:

下面是获取硬盘序列号的全功能方法:

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;
    

【讨论】:

LogicalDisk 序列号和 HardDisk 序列号不一样,你可以试试看有什么区别【参考方案10】:

我正在使用这个:

<!-- 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;
                
            
        

【讨论】:

以上是关于获取硬盘序列号的主要内容,如果未能解决你的问题,请参考以下文章

批处理 命令获取主板序列号 硬盘序列号 CPU ID?

VC++如何获取机器码?硬盘序列号、CPU编号、BIOS编号等~

获取其中所有硬盘和分区的序列号

如何使用 C# 获取硬盘序列号?

获取硬盘序列号

通过PHP获取厂商提供的硬盘序列号