You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从命令行获取Windows系统USB设备的准确电源状态?

USB设备电源状态不一致问题与命令行获取方案

状态差异原因

设备管理器与USBView的状态差异源于两者监控的设备对象层级不同:

  • 设备管理器显示的是**功能设备对象(FDO)**的电源状态,对应设备功能驱动栈的顶层,反映设备的功能层面工作状态。
  • USBView显示的是**USB总线驱动的物理设备对象(PDO)**的电源状态,对应总线层面的设备对象,USB总线驱动可能在设备空闲时将PDO切换到D2,而上层FDO仍保持D0,导致状态矛盾。

要获取Windows视角的准确状态,需明确目标是FDO还是PDO的状态,以下是几种命令行/代码实现方案:


方案一:PowerShell脚本(无需管理员权限,获取FDO状态)

1. 枚举所有USB设备的电源状态

Get-PnpDevice -Class USB | Where-Object { $_.Status -eq "OK" } | ForEach-Object {
    $powerStateProp = Get-PnpDeviceProperty -InstanceId $_.InstanceId -KeyName DEVPKEY_Device_PowerState
    [PSCustomObject]@{
        设备名称 = $_.FriendlyName
        实例ID = $_.InstanceId
        电源状态 = switch ($powerStateProp.Data) {
            0 { "D0 (工作状态)" }
            1 { "D1 (中间休眠)" }
            2 { "D2 (中间休眠)" }
            3 { "D3 (深度休眠)" }
            default { "未知状态" }
        }
    }
} | Format-Table -AutoSize

2. 按VID:PID查询单个设备

# 替换为目标设备的VID和PID(十六进制字符串,无需0x前缀)
$targetVid = "1234"
$targetPid = "5678"

Get-PnpDevice -Class USB | Where-Object {
    $_.InstanceId -match "VID_$targetVid&PID_$targetPid"
} | ForEach-Object {
    $powerStateProp = Get-PnpDeviceProperty -InstanceId $_.InstanceId -KeyName DEVPKEY_Device_PowerState
    [PSCustomObject]@{
        设备名称 = $_.FriendlyName
        VID_PID = "VID_$targetVid&PID_$targetPid"
        电源状态 = switch ($powerStateProp.Data) {
            0 { "D0 (工作状态)" }
            1 { "D1 (中间休眠)" }
            2 { "D2 (中间休眠)" }
            3 { "D3 (深度休眠)" }
            default { "未知状态" }
        }
    }
} | Format-List

方案二:C/C++程序(需管理员权限,获取PDO/FDO状态)

以下程序可直接枚举USB设备的PDO,获取与USBView一致的电源状态,支持枚举所有设备或按VID:PID查询:

#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <devpkey.h>
#include <iostream>
#include <vector>
#include <string>

#pragma comment(lib, "setupapi.lib")

const char* PowerStateToString(DWORD state) {
    switch (state) {
        case 0: return "D0 (工作状态)";
        case 1: return "D1 (中间休眠)";
        case 2: return "D2 (中间休眠)";
        case 3: return "D3 (深度休眠)";
        default: return "未知状态";
    }
}

void EnumerateAllUSBDevices() {
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        std::cerr << "SetupDiGetClassDevs 失败,错误码: " << GetLastError() << std::endl;
        return;
    }

    SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0};
    deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, i, &deviceInterfaceData); i++) {
        DWORD requiredSize = 0;
        SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL);
        std::vector<BYTE> detailData(requiredSize);
        PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(detailData.data());
        pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

        SP_DEVINFO_DATA devInfoData = {0};
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) {
            std::cerr << "SetupDiGetDeviceInterfaceDetail 失败,错误码: " << GetLastError() << std::endl;
            continue;
        }

        WCHAR friendlyName[256] = {0};
        SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, reinterpret_cast<PBYTE>(friendlyName), sizeof(friendlyName), NULL);

        DWORD powerState = 0;
        DEVPROPTYPE propType;
        if (SetupDiGetDeviceProperty(hDevInfo, &devInfoData, &DEVPKEY_Device_PowerState, &propType, reinterpret_cast<PBYTE>(&powerState), sizeof(powerState), NULL, 0)) {
            std::wcout << L"设备名称: " << friendlyName << std::endl;
            std::wcout << L"设备路径: " << pDetailData->DevicePath << std::endl;
            std::cout << "电源状态: " << PowerStateToString(powerState) << std::endl;
            std::cout << "-------------------------" << std::endl;
        } else {
            std::cerr << "SetupDiGetDeviceProperty 失败,错误码: " << GetLastError() << std::endl;
        }
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
}

void QueryUSBDeviceByVidPid(const std::wstring& vid, const std::wstring& pid) {
    HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if (hDevInfo == INVALID_HANDLE_VALUE) {
        std::cerr << "SetupDiGetClassDevs 失败,错误码: " << GetLastError() << std::endl;
        return;
    }

    SP_DEVICE_INTERFACE_DATA deviceInterfaceData = {0};
    deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    bool found = false;
    for (DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, i, &deviceInterfaceData); i++) {
        DWORD requiredSize = 0;
        SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, NULL, 0, &requiredSize, NULL);
        std::vector<BYTE> detailData(requiredSize);
        PSP_DEVICE_INTERFACE_DETAIL_DATA pDetailData = reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(detailData.data());
        pDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

        SP_DEVINFO_DATA devInfoData = {0};
        devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

        if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &deviceInterfaceData, pDetailData, requiredSize, NULL, &devInfoData)) {
            std::cerr << "SetupDiGetDeviceInterfaceDetail 失败,错误码: " << GetLastError() << std::endl;
            continue;
        }

        WCHAR hardwareId[256] = {0};
        SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_HARDWAREID, NULL, reinterpret_cast<PBYTE>(hardwareId), sizeof(hardwareId), NULL);
        std::wstring hwId(hardwareId);
        std::wstring targetId = L"USB\\VID_" + vid + L"&PID_" + pid;

        if (hwId.find(targetId) != std::wstring::npos) {
            WCHAR friendlyName[256] = {0};
            SetupDiGetDeviceRegistryProperty(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, reinterpret_cast<PBYTE>(friendlyName), sizeof(friendlyName), NULL);

            DWORD powerState = 0;
            DEVPROPTYPE propType;
            if (SetupDiGetDeviceProperty(hDevInfo, &devInfoData, &DEVPKEY_Device_PowerState, &propType, reinterpret_cast<PBYTE>(&powerState), sizeof(powerState), NULL, 0)) {
                std::wcout << L"找到目标设备:" << std::endl;
                std::wcout << L"设备名称: " << friendlyName << std::endl;
                std::wcout << L"硬件ID: " << hardwareId << std::endl;
                std::cout << "电源状态: " << PowerStateToString(powerState) << std::endl;
                found = true;
                break;
            } else {
                std::cerr << "SetupDiGetDeviceProperty 失败,错误码: " << GetLastError() << std::endl;
            }
        }
    }

    if (!found) {
        std::wcout << L"未找到VID:" << vid << L" PID:" << pid << L"的USB设备" << std::endl;
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
}

int wmain(int argc, wchar_t* argv[]) {
    if (argc == 1) {
        std::cout << "枚举所有USB设备电源状态:" << std::endl;
        std::cout << "-------------------------" << std::endl;
        EnumerateAllUSBDevices();
    } else if (argc == 3) {
        QueryUSBDeviceByVidPid(argv[1], argv[2]);
    } else {
        std::wcout << L"用法:" << std::endl;
        std::wcout << L"  USBPowerStatus.exe          - 枚举所有USB设备电源状态" << std::endl;
        std::wcout << L"  USBPowerStatus.exe <VID> <PID>  - 查询指定VID:PID的设备电源状态" << std::endl;
        std::wcout << L"示例: USBPowerStatus.exe 1234 5678" << std::endl;
        return 1;
    }

    return 0;
}

编译与运行

  • 用MSVC编译:cl USBPowerStatus.cpp /link setupapi.lib
  • 需以管理员权限运行程序,否则无法访问部分设备的电源状态信息

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 00:54:29