Sabyasachi Mukherjee Ответов: 3

Проблема с WMI в C#


Я пытаюсь использовать WMI в C# для запроса информации о подключенном жестком диске. В принципе, я пытаюсь преобразовать сценарий Powershell в C#. Однако я уперся в стену. В Powershell у меня есть строка:

$testdrv = Get-WmiObject -Class win32_volume -Filter "DriveLetter='$DriveLetter'"


Теперь, в C#, работает следующее:

var a = new ManagementObject("Win32_LogicalDisk.DeviceID='D:'");            
Console.WriteLine(a.GetPropertyValue("VolumeSerialNumber").ToString());


но это не так

var a = new ManagementObject("Win32_Volume.DriveLetter='D:'");            
Console.WriteLine(a.GetPropertyValue("DeviceID").ToString());


Я получаю
Unhandled Exception: System.Management.ManagementException: Invalid object path
ошибка.

Что я делаю не так?

Что я уже пробовал:

Я пробовал запускать Visual Studio в режиме администратора, но это не помогает. Является единственным способом запрос Win32_Volume путем построения строки запроса и с помощью ManagementObjectSearcher? Разве я не могу сделать это с помощью методов расширения в стиле LINQ, как это можно сделать с Win32_LogicalDisk?

Richard MacCutchan

Попробовал здесь и получил ту же ошибку.

Michael_Davies

Вы пробовали это в WMICodeCreator (скачать с MS), вы можете выбрать Win32_LogicalDisk и просмотреть все доступные данные, запустить код, чтобы увидеть вывод, а затем сгенерировать скрипт, VB или C# код.

3 Ответов

Рейтинг:
25

Dave Kreskowiak

Проблема в том, что вы должны использовать WQL-запрос, чтобы добраться до объекта, и это то, что я использовал в своих тестах.

Первый приведенный вами пример работает, потому что в классе Win32_LogicalDisk свойство DeviceID является ключом. См. документацию здесь[^].

В классе Win32_Volume DriveLetter не является ключевым полем, поэтому вы не можете использовать синтаксис пути, который вы используете для создания объекта ManagementObject, чтобы добраться до него. Вместо этого вы должны использовать WQL-запрос с помощью ManagementObjectSearcher.


Sabyasachi Mukherjee

Абсолютно правильный. Спасибо за ссылку на документацию. Это было очень поучительно.

Richard MacCutchan

Я потратил несколько часов, пытаясь понять документацию WMI, но без особого успеха.
Глядя на документацию для этих классов, оба свойства кажутся одинаковыми. Как определить, ключ это или нет?

Dave Kreskowiak

Вы должны искать строку "квалификаторы"чуть выше описания свойства.

Richard MacCutchan

Спасибо. Приятно, что Microsoft сделает это и так очевидно.

Sabyasachi Mukherjee

Это из документации:

Идентификатора устройства
Тип данных: строка
Тип доступа: только для чтения
Квалификаторы: Key, Override ("DeviceId"), MappingStrings ("WMI")
Уникальный идентификатор логического диска от других устройств в системе.
Это свойство наследуется от CIM_LogicalDevice.


Квалификатор "ключ" показывает, что он может быть запрошен с помощью этого квалификатора, и вместо ManagementObjectCollection он вернет один единственный объект ManagementObject.

"Уникальный идентификатор логического диска от других устройств в системе."

Ключевое слово здесь-слово "уникальный". Ни один из других атрибутов не уникален.

Michael_Davies

Спасибо за это, заполнил пробел в моем понимании WMI.

Рейтинг:
2

Dave Kreskowiak

Он отлично работает на моей машине. Проблема с WMI заключается в том, что не все должно быть заполнено любыми компонентами/драйверами, которые у вас есть в системе. Вполне возможно,что объект Volume не имеет заполненного DriveLetter.

Вы можете проверить это, загрузив WMI Explorer из WMI Explorer-Скачать файл выпуска[^] и поиск экземпляров класса Win32_Volume. Проверьте, чтобы увидеть, если объекты томной эту информацию заполнил. Простой.


Sabyasachi Mukherjee

Я действительно попробовал его на трех системах, все Windows 10 x64. Каждый раз получал одну и ту же ошибку.

Спасибо, что указали мне на инструмент WMI Explorer. Это могло бы помочь.

Michael_Davies

Дэйв, я попробовал это на своем компьютере и получаю те же ошибки, не знаю, что может быть по-другому, у меня есть D:, пробовал C: тоже.

Dave Kreskowiak

Как я уже сказал, Ничто не говорит о том, что эти случаи должны быть полностью заполнены. Если привод не заполнен системой, вы ничего не можете с этим поделать.

Формат на моем - "D:", без косых черт, в верхнем регистре. Если DriveLetter не заполнен, ваш запрос вернет null, и именно поэтому ваш код терпит неудачу. Это предполагает, что он всегда будет возвращать хороший объект. Вызов ToString на null-это плохо.

Dave Kreskowiak

Быстрый способ, чтобы увидеть объекты, чтобы открыть PowerShell и введите:
Get-WmiObject Win32_Volume
Прокрутите выходные данные назад, и вы увидите все в каждом объекте Win32_Volume, включая содержимое свойства DriveLetter в каждом экземпляре.

Michael_Davies

Уже сделал это, чтобы проверить и DriveLetter D: существует и заполняется правильно.

Рейтинг:
18

Michael_Davies

Вот код, сгенерированный с помощью WMICodeCreator, который работает для вашей проблемы, вы можете вынуть много материала цикла, как вы знаете, есть только одна запись;

using System;
using System.Management;
using System.Windows.Forms;

namespace WMISample
{
    public class MyWMIQuery
    {
        public static void Main()
        {
            try
            {
                ManagementObjectSearcher searcher = 
                    new ManagementObjectSearcher("root\\CIMV2", 
                    "SELECT * FROM Win32_Volume WHERE DriveLetter = 'D:'"); 

                foreach (ManagementObject queryObj in searcher.Get())
                {
                    Console.WriteLine("-----------------------------------");
                    Console.WriteLine("Win32_Volume instance");
                    Console.WriteLine("-----------------------------------");
                    Console.WriteLine("DeviceID: {0}", queryObj["DeviceID"]);
                }
            }
            catch (ManagementException e)
            {
                MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
            }
        }
    }
}


Sabyasachi Mukherjee

Это подход ManagementObjectSearcher с SQL-подобными запросами LINQ. Я надеялся решить ее с помощью запросов, подобных методу расширения.

Michael_Davies

Оцените это, я только что посмотрел примеры MS, скопировал их в VB и C# и попробовал оба из них, и они каждый раз терпят неудачу, попробовал варианты выражения D: как и в VB, он заключен в", C# с', ни один метод экранирования строки не изменяет результат, а изучение объекта управления показывает правильный путь.

Возможно, вам придется сделать это по-другому.