You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过Python在Windows下从设备ID获取可移动驱动器盘符

Mapping a Removable Drive's Device ID to Its Drive Letter on Windows

Got it, let's break down how to connect a removable drive's device ID to its assigned drive letter on Windows—covering both Python-based solutions and quick non-Python methods you can use right from the command line.

Python Solutions

Using the wmi Library (Simplest Approach)

This is the most straightforward way, as the wmi library wraps Windows WMI calls into clean, readable Python code.

  1. First, install the library if you haven't already:

    pip install wmi
    
  2. Here's a script that takes your target device ID (like USBSTOR\DISK&VEN_SANDISK&PROD_CRUZER_GLIDE&REV_1.27\1234567890ABCDEF&0) and finds the matching drive letter:

    import wmi
    
    def get_drive_letter_from_device_id(target_device_id):
        c = wmi.WMI()
        # Iterate over all connected disk drives
        for disk in c.Win32_DiskDrive():
            # Match the device's PNPDeviceID (Windows' official hardware ID)
            if disk.PNPDeviceID == target_device_id:
                # Link the disk to its partitions, then to logical drives
                for partition in disk.associators("Win32_DiskDriveToDiskPartition"):
                    for logical_drive in partition.associators("Win32_LogicalDiskToPartition"):
                        return logical_drive.DeviceID
        return None
    
    # Replace this with your actual device ID (copy from Device Manager)
    target_id = "USBSTOR\\DISK&VEN_SANDISK&PROD_CRUZER_GLIDE&REV_1.27\\1234567890ABCDEF&0"
    drive_letter = get_drive_letter_from_device_id(target_id)
    
    if drive_letter:
        print(f"Found matching drive letter: {drive_letter}")
    else:
        print("No drive found with that device ID.")
    

    Note: The "device ID" here refers to Windows' PNPDeviceID. You can grab this exact string from Device Manager: right-click your drive > Properties > Details tab > select "Device instance path" from the dropdown.

Using ctypes (No External Libraries)

If you can't install third-party packages, you can call Windows' native SetupDi API directly with ctypes. This is more verbose but self-contained:

import ctypes
from ctypes import wintypes
import string

# Define Windows API constants and structures
SetupDiGetClassDevs = ctypes.windll.setupapi.SetupDiGetClassDevsW
SetupDiEnumDeviceInfo = ctypes.windll.setupapi.SetupDiEnumDeviceInfo
SetupDiGetDeviceRegistryProperty = ctypes.windll.setupapi.SetupDiGetDeviceRegistryPropertyW
SetupDiDestroyDeviceInfoList = ctypes.windll.setupapi.SetupDiDestroyDeviceInfoList
CreateFile = ctypes.windll.kernel32.CreateFileW
DeviceIoControl = ctypes.windll.kernel32.DeviceIoControl
CloseHandle = ctypes.windll.kernel32.CloseHandle

DIGCF_ALLCLASSES = 0x00000004
DIGCF_PRESENT = 0x00000002
SPDRP_DEVICE_ID = 0x00000001
IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080
GENERIC_READ = 0x80000000
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
OPEN_EXISTING = 3

class StorageDeviceNumber(ctypes.Structure):
    _fields_ = [("DeviceType", wintypes.DWORD), ("DeviceNumber", wintypes.DWORD), ("PartitionNumber", wintypes.DWORD)]

def get_drive_letter_from_device_id(target_device_id):
    hdevinfo = SetupDiGetClassDevs(None, None, None, DIGCF_ALLCLASSES | DIGCF_PRESENT)
    if hdevinfo == wintypes.HANDLE(-1).value:
        return None

    devinfo_data = wintypes.SP_DEVINFO_DATA()
    devinfo_data.cbSize = ctypes.sizeof(devinfo_data)
    index = 0

    while SetupDiEnumDeviceInfo(hdevinfo, index, ctypes.byref(devinfo_data)):
        index += 1
        # Fetch the device's ID
        device_id_buffer = ctypes.create_unicode_buffer(256)
        if not SetupDiGetDeviceRegistryProperty(hdevinfo, ctypes.byref(devinfo_data), SPDRP_DEVICE_ID, None, ctypes.byref(device_id_buffer), ctypes.sizeof(device_id_buffer), None):
            continue
        
        if device_id_buffer.value == target_device_id:
            # Get device path and open it
            device_path = f"\\\\?\\{device_id_buffer.value.replace('#', '#')}"
            hdevice = CreateFile(device_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None)
            if hdevice == wintypes.HANDLE(-1).value:
                continue
            
            # Get the device's storage number
            dev_num = StorageDeviceNumber()
            bytes_returned = wintypes.DWORD(0)
            if not DeviceIoControl(hdevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, None, 0, ctypes.byref(dev_num), ctypes.sizeof(dev_num), ctypes.byref(bytes_returned), None):
                CloseHandle(hdevice)
                continue
            
            # Check all drive letters for a match
            for letter in string.ascii_uppercase:
                drive_path = f"\\\\.\\{letter}:"
                hdrive = CreateFile(drive_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, None, OPEN_EXISTING, 0, None)
                if hdrive == wintypes.HANDLE(-1).value:
                    continue
                
                drive_dev_num = StorageDeviceNumber()
                if DeviceIoControl(hdrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, None, 0, ctypes.byref(drive_dev_num), ctypes.sizeof(drive_dev_num), ctypes.byref(bytes_returned), None):
                    if drive_dev_num.DeviceNumber == dev_num.DeviceNumber:
                        CloseHandle(hdrive)
                        CloseHandle(hdevice)
                        SetupDiDestroyDeviceInfoList(hdevinfo)
                        return f"{letter}:"
                CloseHandle(hdrive)
            CloseHandle(hdevice)
    
    SetupDiDestroyDeviceInfoList(hdevinfo)
    return None

# Usage
target_id = "USBSTOR\\DISK&VEN_SANDISK&PROD_CRUZER_GLIDE&REV_1.27\\1234567890ABCDEF&0"
drive_letter = get_drive_letter_from_device_id(target_id)
print(f"Drive letter: {drive_letter}" if drive_letter else "No matching drive found.")

Non-Python Solutions

Using PowerShell (Fastest Command-Line Method)

PowerShell makes this trivial with pipelined WMI calls. Open PowerShell (as Administrator if needed) and run:

# Replace with your device ID
$targetDeviceId = "USBSTOR\DISK&VEN_SANDISK&PROD_CRUZER_GLIDE&REV_1.27\1234567890ABCDEF&0"

Get-WmiObject Win32_DiskDrive | Where-Object { $_.PNPDeviceID -eq $targetDeviceId } |
    ForEach-Object { $_.GetRelated("Win32_DiskPartition") } |
    ForEach-Object { $_.GetRelated("Win32_LogicalDisk") } |
    Select-Object DeviceID, VolumeName

This will directly output the drive letter and volume name if a match is found.

Using wmic (Command Prompt)

  1. First, get your drive's PNPDeviceID:

    wmic diskdrive get deviceid, pnpdeviceid, model
    

    Locate your removable drive by its model, then copy its PNPDeviceID.

  2. Link the device ID to a drive letter with a chain of wmic queries:

    wmic path win32_diskdrive where "pnpdeviceid='YOUR_DEVICE_ID'" get deviceid
    wmic path win32_diskdrivetodiskpartition where "antecedent='\\\\.\\PHYSICALDRIVEX'" get dependent
    wmic path win32_logicaldisktopartition where "antecedent='Win32_DiskPartition.DeviceID=\"Disk #X, Partition #Y\"'" get dependent
    

    Replace YOUR_DEVICE_ID, PHYSICALDRIVEX, and the partition ID with values from the first query.

Using Diskpart

  1. Open Command Prompt as Administrator and run diskpart.
  2. List all disks: list disk
  3. Select your removable drive (look for the Removable tag): select disk X (replace X with the disk number)
  4. Show drive details: detail disk
    The drive letter will be listed under the "Volume ###" section of the output.

内容的提问来源于stack exchange,提问作者Pyroadrian

火山引擎 最新活动