.Net Core 2.1中获取USB存储设备的序列号

Posted

技术标签:

【中文标题】.Net Core 2.1中获取USB存储设备的序列号【英文标题】:Get the serial number of USB storage devices in .Net Core 2.1 【发布时间】:2018-08-13 14:16:59 【问题描述】:

如何在 .Net Core 2.1 中获取 USB 存储设备的序列号

我找到了不同的解决方案,但遗憾的是,由于 .Net Core 中缺乏 Windows 注册表和 WMI 支持,它们无法正常工作。

在 Powershell 中它非常简单,但我无法在 Powershell Core 中找到实现。

PS C:\> Get-Disk | Select-Object SerialNumber

SerialNumber
------------
0008_0D02_0021_9852.

我更喜欢在客户端(Win、Linux、Mac)上没有额外安装要求的解决方案。

【问题讨论】:

这看起来很有用nuget.org/packages/CoreCompat.LibUsbDotNet @FLeX 这个包使用 WinUSB、LibUsb-Win32 和 libusb-1.0。我更喜欢没有这种依赖的方法。 投反对票且不发表评论?谢谢! .NET Core 可以将 WMI 与 System.Management 包一起使用 没有。但是尝试在 *nix 版本上使用 Windows 兼容包是没有意义的。它只是为了回填在 .NETCore 中省略的特定于 Windows 的类,因为它们不可移植。 System.Management 仅适用于硬核 Windows 【参考方案1】:

该类对 WMI Win32_DiskDrive 类及其关联者:Win32_DiskDriveToDiskPartition 和 CIM_LogicalDiskBasedOnPartition 执行一系列查询,以检索系统(本地或远程)上活动 USB 驱动器上的信息。

这似乎是多余的(可能是因为它是多余的),因为您只是要求提供 USB 驱动器序列号。但是,您永远不知道下一步需要什么,它可能对其他人有用。

.Net Core 2.1(NuGet 包)需要Microsoft .Net System.Management 4.5 可以使用 Visual Studio NuGet Package Manager 轻松找到和安装。 关于Linux的支持,请看这里:Windows Management Instrumentation Now A Formal Bus With Linux 4.13

另外,请留意Windows Compatibility Pack for .NET Core。 不断添加和更新新的跨平台程序集。

主类实现了所有必需的功能,并且结构非常简单。 WMI 查询使用关联语法,这是一种将 WMI 类对象相互关联的方法。 类属性的含义是不言自明的。

可以这样实例化:SystemUSBDrives systemUSBDrives = new SystemUSBDrives("[Computer Name]");

[Computer Name] 为空或为空时,它使用本地计算机名称。

要获取 USB 设备列表及其属性,请调用 GetUSBDrivesInfo() 方法:

var USBDrivesEnum = systemUSBDrives.GetUSBDrivesInfo([UserName], [Password], [Domain]);

[UserName], [Password], [Domain] 用于连接 NT 域。 这些参数如果不需要,可以为 null 或空字符串。

示例类实例化和函数调用 (Local Machine, no authentication):

SystemUSBDrives systemUSBDrives = new SystemUSBDrives(null);
var USBDrivesEnum = systemUSBDrives.GetUSBDrivesInfo(null, null, null);

测试于:Visual Studio Pro 15.7.6 - 15.9.35.Net Core 2.1 / .Net Framework 4.8C# 6.0 -> 7.3.Net System.Management 4.5

using System.Management;

public class SystemUSBDrives

    string m_ComputerName = string.Empty;
    public SystemUSBDrives(string ComputerName) 
        this.m_ComputerName = string.IsNullOrEmpty(ComputerName)
                            ? Environment.MachineName
                            : ComputerName;
    

    private static EnumerationOptions GetEnumerationOptions(bool DeepScan)
    
        var mOptions = new EnumerationOptions()
        
            Rewindable = false,        //Forward only query => no caching
            ReturnImmediately = true,  //Pseudo-async result
            DirectRead = true,
            EnumerateDeep = DeepScan
        ;
        return mOptions;
    

    private static ConnectionOptions GetConnectionOptions() => GetConnectionOptions("", "", "");

    private static ConnectionOptions GetConnectionOptions(string userName, string password, string domain)
    
        var connOptions = new ConnectionOptions()
        
            EnablePrivileges = true,
            Timeout = ManagementOptions.InfiniteTimeout,
            Authentication = AuthenticationLevel.PacketPrivacy,
            Impersonation = ImpersonationLevel.Impersonate,
            Username = userName,
            Password = password,
            Authority = !string.IsNullOrEmpty(Domain) ? $"NTLMDOMAIN:domain" : string.Empty  //Authority = "NTLMDOMAIN:[domain]"
        ;
        return connOptions;
    

    public List<USBDriveInfo> GetUSBDrivesInfo(string userName, string password, string domain)
    
        var wmiQueryResult = new List<USBDriveInfo>();
        ConnectionOptions connOptions = GetConnectionOptions(userName, password, domain);
        EnumerationOptions mOptions = GetEnumerationOptions(false);
        var mScope = new ManagementScope($@"\\this.m_ComputerName\root\CIMV2", connOptions);
        var selQuery = new SelectQuery("SELECT * FROM Win32_DiskDrive WHERE InterfaceType='USB'");
        mScope.Connect();

        using (var moSearcher = new ManagementObjectSearcher(mScope, selQuery, mOptions)) 
            foreach (ManagementObject moDiskDrive in moSearcher.Get()) 
                var usbInfo = new USBDriveInfo();
                usbInfo.GetDiskDriveInfo(moDiskDrive);

                var relQuery = new RelatedObjectQuery(
                    $"Associators of Win32_DiskDrive.DeviceID='moDiskDrive.Properties["DeviceID"].Value' " +
                    $"WHERE AssocClass = Win32_DiskDriveToDiskPartition");
                using (var moAssocPart = new ManagementObjectSearcher(mScope, relQuery, mOptions)) 
                    foreach (ManagementObject moAssocPartition in moAssocPart.Get()) 

                        usbInfo.GetDiskPartitionInfo(moAssocPartition);
                        relQuery = new RelatedObjectQuery(
                            $"Associators of Win32_DiskPartition.DeviceID='moAssocPartition.Properties["DeviceID"].Value' " +
                            $"WHERE AssocClass = CIM_LogicalDiskBasedOnPartition");

                        using (var moLogDisk = new ManagementObjectSearcher(mScope, relQuery, mOptions)) 
                            foreach (ManagementObject moLogDiskEnu in moLogDisk.Get()) 
                                usbInfo.GetLogicalDiskInfo(moLogDiskEnu);
                                moLogDiskEnu.Dispose();
                            
                        
                        moAssocPartition.Dispose();
                    
                    wmiQueryResult.Add(usbInfo);
                
                moDiskDrive.Dispose();
            
            return wmiQueryResult;
        
       //GetUSBDrivesInfo()

    public class USBDriveInfo
    
        private int m_PartionsCount = 0;
        public USBDriveInfo() => this.Partitions = new List<Partition>(1);
        public string Caption  get; private set; 
        public string DeviceID  get; private set; 
        public string FirmwareRevision  get; private set; 
        public ulong FreeSpace  get; private set; 
        public string InterfaceType  get; private set; 
        public bool MediaLoaded  get; private set; 
        public string MediaType  get; private set; 
        public string Model  get; private set; 
        public uint NumberOfPartitions  get; private set; 
        public List<Partition> Partitions  get; private set; 
        public string PNPDeviceID  get; private set; 
        public string SerialNumber  get; private set; 
        public ulong Size  get; private set; 
        public string Status  get; private set; 
        public ulong TotalCylinders  get; private set; 
        public uint TotalHeads  get; private set; 
        public ulong TotalSectors  get; private set; 
        public ulong TotalTracks  get; private set; 
        public uint TracksPerCylinder  get; private set; 

        public class Partition
        
            public Partition() => this.LogicalDisks = new List<LogicalDisk>();
            public bool Bootable  get; internal set; 
            public bool BootPartition  get; internal set; 
            public uint DiskIndex  get; internal set; 
            public List<LogicalDisk> LogicalDisks  get; internal set; 
            public ulong PartitionBlockSize  get; internal set; 
            public ulong PartitionNumberOfBlocks  get; internal set; 
            public ulong PartitionStartingOffset  get; internal set; 
            public bool PrimaryPartition  get; internal set; 
        

        public class LogicalDisk
        
            public ulong FreeSpace  get; internal set; 
            public string FileSystem  get; internal set; 
            public string LogicalDiskVolume  get; internal set; 
            public bool SupportsDiskQuotas  get; internal set; 
            public string VolumeName  get; internal set; 
            public string VolumeSerialNumber  get; internal set; 
        

        internal void GetDiskDriveInfo(ManagementObject DiskDrive)
        
            this.Caption = DiskDrive.GetPropertyValue("Caption")?.ToString();
            this.DeviceID = DiskDrive["DeviceID"]?.ToString();
            this.FirmwareRevision = DiskDrive["FirmwareRevision"]?.ToString();
            this.InterfaceType = DiskDrive["InterfaceType"]?.ToString();
            this.MediaLoaded = (bool?)DiskDrive["MediaLoaded"] ?? false;
            this.MediaType = DiskDrive["MediaType"]?.ToString();
            this.Model = DiskDrive["Model"]?.ToString();
            this.NumberOfPartitions = (uint?)DiskDrive["Partitions"] ?? 0;
            this.PNPDeviceID = DiskDrive["PNPDeviceID"]?.ToString();
            this.SerialNumber = DiskDrive["SerialNumber"]?.ToString();
            this.Size = (ulong?)DiskDrive["Size"] ?? 0L;
            this.Status = DiskDrive["Status"]?.ToString();
            this.TotalCylinders = (ulong?)DiskDrive["TotalCylinders"] ?? 0;
            this.TotalHeads = (uint?)DiskDrive["TotalHeads"] ?? 0U;
            this.TotalSectors = (ulong?)DiskDrive["TotalSectors"] ?? 0;
            this.TotalTracks = (ulong?)DiskDrive["TotalTracks"] ?? 0;
            this.TracksPerCylinder = (uint?)DiskDrive["TracksPerCylinder"] ?? 0;
        

        internal void GetDiskPartitionInfo(ManagementObject Partitions)
        
            m_PartionsCount += 1;
            this.Partitions.Add(new Partition()
            
                DiskIndex = (uint?)Partitions["DiskIndex"] ?? 0,
                PartitionBlockSize = (ulong?)Partitions["BlockSize"] ?? 0,
                Bootable = (bool?)Partitions["Bootable"] ?? false,
                BootPartition = (bool?)Partitions["BootPartition"] ?? false,
                PartitionNumberOfBlocks = (ulong?)Partitions["NumberOfBlocks"] ?? 0,
                PrimaryPartition = (bool?)Partitions["PrimaryPartition"] ?? false,
                PartitionStartingOffset = (ulong?)Partitions["StartingOffset"] ?? 0
            );
        

        internal void GetLogicalDiskInfo(ManagementObject LogicalDisk)
        
            if (m_PartionsCount == 0) return;
            this.Partitions[m_PartionsCount - 1].LogicalDisks.Add(new LogicalDisk()
            
                FileSystem = LogicalDisk["FileSystem"]?.ToString(),
                FreeSpace = (ulong?)LogicalDisk["FreeSpace"] ?? 0,
                LogicalDiskVolume = LogicalDisk["DeviceID"]?.ToString(),
                SupportsDiskQuotas = (bool?)LogicalDisk["SupportsDiskQuotas"] ?? false,
                VolumeName = LogicalDisk["VolumeName"]?.ToString(),
                VolumeSerialNumber = LogicalDisk["VolumeSerialNumber"]?.ToString()
            );
            //Linq's Sum() does not sum ulong(s)
            foreach(Partition p in this.Partitions)
            
                foreach (LogicalDisk ld in p.LogicalDisks) 
                    this.FreeSpace += ld.FreeSpace;
                
            
        
    
 // SystemUSBDrives

【讨论】:

在linux上你需要安装x86 platform driver并且不包括mac。我想我真的需要编写平台感知代码来获取特定驱动器的序列号。 你测试过Windows Compatibility Pack(我没有)吗?包括 WMI 并支持 MAC OS(在纸上)。请参阅:Using the Windows Compatibility Pack。 NuGet Package. @dh_cgn 很可能就是这样。我问汉斯关于“兼容性”包的问题,​​但当然不是“物理”兼容。如果我发现在这种情况下有用的东西(一些开源的东西或正在进行的项目),我会告诉你的。【参考方案2】:

不确定这是否正是您要查找的内容,但这是我过去使用过的一些代码。

using System.Management;

public class USBDeviceInfo

    public string Availability  get; set; 
    public string Caption  get; set; 
    public string ClassCode  get; set; 
    public uint ConfigManagerErrorCode  get; set; 
    public bool ConfigManagerUserConfig  get; set; 
    public string CreationClassName  get; set; 
    public string CurrentAlternateSettings  get; set; 
    public string CurrentConfigValue  get; set; 
    public string Description  get; set; 
    public string DeviceID  get; set; 
    public string ErrorCleared  get; set; 
    public string ErrorDescription  get; set; 
    public string GangSwitched  get; set; 
    public string InstallDate  get; set; 
    public string LastErrorCode  get; set; 
    public string Name  get; set; 
    public string NumberOfConfigs  get; set; 
    public string NumberOfPorts  get; set; 
    public string PNPDeviceID  get; set; 
    public string PowerManagementCapabilities  get; set; 
    public string PowerManagementSupported  get; set; 
    public string ProtocolCode  get; set; 
    public string Status  get; set; 
    public string StatusInfo  get; set; 
    public string SubclassCode  get; set; 
    public string SystemCreationClassName  get; set; 
    public string SystemName  get; set; 
    public string USBVersion  get; set; 


public static List<USBDeviceInfo> GetUSBDevices()

    ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"Select * From Win32_USBHub");
    ManagementObjectCollection collection = searcher.Get();

    List<USBDeviceInfo> devices = new List<USBDeviceInfo>();
    foreach (var device in collection)
    
        USBDeviceInfo deviceInfo = new USBDeviceInfo();
        deviceInfo.Availability = (string)device.GetPropertyValue("Availability");
        deviceInfo.Caption = (string)device.GetPropertyValue("Caption");
        deviceInfo.ClassCode = (string)device.GetPropertyValue("ClassCode");
        deviceInfo.ConfigManagerErrorCode = (uint)device.GetPropertyValue("ConfigManagerErrorCode");
        deviceInfo.ConfigManagerUserConfig = (bool)device.GetPropertyValue("ConfigManagerUserConfig");
        deviceInfo.CreationClassName = (string)device.GetPropertyValue("CreationClassName");
        deviceInfo.CurrentAlternateSettings = (string)device.GetPropertyValue("CurrentAlternateSettings");
        deviceInfo.CurrentConfigValue = (string)device.GetPropertyValue("CurrentConfigValue");
        deviceInfo.Description = (string)device.GetPropertyValue("Description");
        deviceInfo.DeviceID = (string)device.GetPropertyValue("DeviceID");
        deviceInfo.ErrorCleared = (string)device.GetPropertyValue("ErrorCleared");
        deviceInfo.ErrorDescription = (string)device.GetPropertyValue("ErrorDescription");
        deviceInfo.GangSwitched = (string)device.GetPropertyValue("GangSwitched");
        deviceInfo.InstallDate = (string)device.GetPropertyValue("InstallDate");
        deviceInfo.LastErrorCode = (string)device.GetPropertyValue("LastErrorCode");
        deviceInfo.Name = (string)device.GetPropertyValue("Name");
        deviceInfo.NumberOfConfigs = (string)device.GetPropertyValue("NumberOfConfigs");
        deviceInfo.NumberOfPorts = (string)device.GetPropertyValue("NumberOfPorts");
        deviceInfo.PNPDeviceID = (string)device.GetPropertyValue("PNPDeviceID");
        deviceInfo.PowerManagementCapabilities = (string)device.GetPropertyValue("PowerManagementCapabilities");
        deviceInfo.PowerManagementSupported = (string)device.GetPropertyValue("PowerManagementSupported");
        deviceInfo.ProtocolCode = (string)device.GetPropertyValue("ProtocolCode");
        deviceInfo.Status = (string)device.GetPropertyValue("Status");
        deviceInfo.StatusInfo = (string)device.GetPropertyValue("StatusInfo");
        deviceInfo.SubclassCode = (string)device.GetPropertyValue("SubclassCode");
        deviceInfo.SystemCreationClassName = (string)device.GetPropertyValue("SystemCreationClassName");
        deviceInfo.SystemName = (string)device.GetPropertyValue("SystemName");
        deviceInfo.USBVersion = (string)device.GetPropertyValue("USBVersion");
        devices.Add(deviceInfo);
    

    collection.Dispose();
    searcher.Dispose();
    return devices;

【讨论】:

这肯定不是问题所需要的,因为您打印的是关于集线器的信息,而不是大容量存储设备。但这可能是适应的良好开端。

以上是关于.Net Core 2.1中获取USB存储设备的序列号的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET Core 2.1 Web 客户端中存储不记名令牌的位置

在 Web Api Controller (.Net Core 2.1) 中获取声明和订阅

直接从令牌获取 JWT 声明,ASP Net Core 2.1

ASP.NET Core2.2 和2.1 版本中对cookie的设置和存储

.Net Core 2.1 过期的 JWT 令牌响应 [发布与获取]

如何从 VB.NET 中的 USB 端口获取数据