如何通过Python在Windows下从设备ID获取可移动驱动器盘符
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.
First, install the library if you haven't already:
pip install wmiHere'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)
First, get your drive's PNPDeviceID:
wmic diskdrive get deviceid, pnpdeviceid, modelLocate your removable drive by its model, then copy its
PNPDeviceID.Link the device ID to a drive letter with a chain of
wmicqueries: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 dependentReplace
YOUR_DEVICE_ID,PHYSICALDRIVEX, and the partition ID with values from the first query.
Using Diskpart
- Open Command Prompt as Administrator and run
diskpart. - List all disks:
list disk - Select your removable drive (look for the
Removabletag):select disk X(replace X with the disk number) - Show drive details:
detail disk
The drive letter will be listed under the "Volume ###" section of the output.
内容的提问来源于stack exchange,提问作者Pyroadrian




