На примере нескольких WMI-классов Win32_xxxx, показано, что как минимум некоторые из свойств объектов, возвращаемые указанными классами, совершенно не соответствуют реальным значениям этих свойств.
Ниже рассматриваются примеры выдач WMI-классами Win32_CDROMDrive, Win32_DiskDrive, Win32_DiskPartition, Win32_LogicalDisk, Win32_Volume и демонстрируется, что выдаваемая информация, мягко говоря, не соответствует действительности или выдается в очень неудобном формате или просто опускается. В качестве стенда для выполнения WQL-запросов к WMI-классам используется программа ScriptomaticV2.hta, разработанная группой разработчиков “Scripting Guy” фирмы Microsoft. ScriptomaticV2.hta поддерживает VBS, JS, Perl, Python. В силу отсутствия двух последних, использовались лишь выдачи JS и VBS. Поэтому заранее приношу извинения разработчикам упомянутых WMI-классов, если Perl и / или Python выдают корректную информацию. Кроме того, надеюсь, что использование тех же самых WMI-классов в программах на C#, C++ обеспечивает корректную выдачу результатов.
1. Неверная или опускаемая дата создания или монтирования объекта
Все перечисленные выше классы в списке свойств содержат свойство, именуемое “InstallDate”. Этому свойству в Windows Registry соответствует REG_QWORD. В среде Windows 8.1+ (8.1 и всех сборок Windows 10) CDROMDrive, DiskDrive, это значение хранится в InitialTimeStamp, адресуемом
HKLM\SYSTEM\CurrentControlSet\Enum\SCSI\\Device Parameters\StorPort
Значение InitialTimeStamp МОЖЕТ принимать значение NULL, но в большинстве случаев оно содержит вполне реальную дату в формате, прекрасно описанном в документации Microsoft:
“Unique value that indicates the time when an event is generated.
This is a 64-bit FILETIME value that represents the number of 100-nanosecond intervals after January 1, 1601. The information is in the Coordinated Universal Time (UTC) format. This property is inherited from __Event. To convert this value to other time formats, use the SWbemDateTime methods SetFileTime and GetFileTime.”
Видимо разработчики Win32-WMI-классов не захотели привлекать еще и методы SWbemDateTime и потому выдача JS-кода в поле InstallDate всегда подставляет null date, выдача VBS-кода — это поле скромно опускает. Но ведь никакие методы не нужны, для того, чтобы 64-битное QWORD число, описанного выше формата, преобразовать в число, представляющее дату в миллисекундах, на основе которого можно создать объект Date. Для этого потребуется элементарная арифметика.
2. Противоречивые данные, ошибка в поле InterfaceType, Win32_DiskDrive
Index: 0
InstallDate: null date должно быть Sun Jul 19 08:12:08 UTC+0300 2015
InterfaceType: IDE
…
Model: ST9320423AS
Name: \\.\PHYSICALDRIVE0
…
PNPDeviceID: SCSI\DISK&VEN_&PROD_ST9320423AS\4&3516B3B5&0&000000
Кто-нибудь может дать разумное объяснение значению поля InterfaceType, прямо противоречащее как указанному ниже PNPDeviceID так и тому факту, что начиная с Windows 8.1 в HKLM\SYSTEM\CurrentControlSet\Enum\ интерфейс IDE вообще отсутствует и последний раз он присутствовал лишь в среде Windows 7?
3. Отрицательные значения в полях SerialNumber, Signature классами Win32_DiskDrive, Win32_Volume
SerialNumber: Hitachi HT100219FCC400NEJTBU5G
Signature: -1498719820
…
Purpose: null
QuotasEnabled: false
QuotasIncomplete: false
QuotasRebuilding: false
SerialNumber: -1408044882
Это вообще любимая “фишка”, выдача очень важной информации в совершенно неудобоваримом формате. И SerialNumber и Signature все привыкли читать в 16-ном виде.
4. Неверная индексация разделов для Gpt-форматированных дисков, класс Win32_DiskPartition
Caption: Disk #3, Partition #0
…
Description: GPT: Basic Data
Ну как, объясните мне, Gpt-форматированный раздел типа “Basic Data” приобрел индекс 0, который по праву принадлежит MSR-разделу? Естественно, что MSR-раздел Win32_DiskPartition в списке разделов вообще холодно игнорирует.
5. Наличие полей, содержащих NULL для JS или пусто для VBS для всех объектов в WQL-запросе
В качестве примера могу привести значения свойств Access и Description для класса Win32_Volume. У меня на 9 смонтированных устройствах, включающих два внутренних диска, пару виртуальных DVD-ROM, несколько VHD с Gpt-форматированными разделами, USB-диском, SD-картой и флэшкой, расположены 16 томов и все они в указанных полях содержат или NULL для JS-выдачи или пусто для VBS-выдачи. Спрашивается каким же должен быть том, на каком устройстве располагаться для того, чтобы для него хоть одно из указанных свойств оказалось значимым? А если такого быть не может, то зачем вообще включать эти свойства в выдачи?
Решил проверить с помощью PS и “gwmi win32_volume” для всех томов выдала пустые значения свойств Access, Description.
Заключение
Основной смысл этой короткой, возможно излишне эмоциональной публикации состоит в том, чтобы привлечь внимание всех, кто использует WMI-классы в своем коде, критически оценивать извлекаемые данные, перепроверять их из других источников. Сразу же добавлю, что MSFT-классы, аналогичные описанным выше Win32-классам, выдают всегда корректную информацию, хотя и они грешат выдачей отрицательных чисел в полях Signature.
Ниже рассматриваются примеры выдач WMI-классами Win32_CDROMDrive, Win32_DiskDrive, Win32_DiskPartition, Win32_LogicalDisk, Win32_Volume и демонстрируется, что выдаваемая информация, мягко говоря, не соответствует действительности или выдается в очень неудобном формате или просто опускается. В качестве стенда для выполнения WQL-запросов к WMI-классам используется программа ScriptomaticV2.hta, разработанная группой разработчиков “Scripting Guy” фирмы Microsoft. ScriptomaticV2.hta поддерживает VBS, JS, Perl, Python. В силу отсутствия двух последних, использовались лишь выдачи JS и VBS. Поэтому заранее приношу извинения разработчикам упомянутых WMI-классов, если Perl и / или Python выдают корректную информацию. Кроме того, надеюсь, что использование тех же самых WMI-классов в программах на C#, C++ обеспечивает корректную выдачу результатов.
1. Неверная или опускаемая дата создания или монтирования объекта
Все перечисленные выше классы в списке свойств содержат свойство, именуемое “InstallDate”. Этому свойству в Windows Registry соответствует REG_QWORD. В среде Windows 8.1+ (8.1 и всех сборок Windows 10) CDROMDrive, DiskDrive, это значение хранится в InitialTimeStamp, адресуемом
HKLM\SYSTEM\CurrentControlSet\Enum\SCSI\\Device Parameters\StorPort
Значение InitialTimeStamp МОЖЕТ принимать значение NULL, но в большинстве случаев оно содержит вполне реальную дату в формате, прекрасно описанном в документации Microsoft:
“Unique value that indicates the time when an event is generated.
This is a 64-bit FILETIME value that represents the number of 100-nanosecond intervals after January 1, 1601. The information is in the Coordinated Universal Time (UTC) format. This property is inherited from __Event. To convert this value to other time formats, use the SWbemDateTime methods SetFileTime and GetFileTime.”
Видимо разработчики Win32-WMI-классов не захотели привлекать еще и методы SWbemDateTime и потому выдача JS-кода в поле InstallDate всегда подставляет null date, выдача VBS-кода — это поле скромно опускает. Но ведь никакие методы не нужны, для того, чтобы 64-битное QWORD число, описанного выше формата, преобразовать в число, представляющее дату в миллисекундах, на основе которого можно создать объект Date. Для этого потребуется элементарная арифметика.
2. Противоречивые данные, ошибка в поле InterfaceType, Win32_DiskDrive
Index: 0
InstallDate: null date должно быть Sun Jul 19 08:12:08 UTC+0300 2015
InterfaceType: IDE
…
Model: ST9320423AS
Name: \\.\PHYSICALDRIVE0
…
PNPDeviceID: SCSI\DISK&VEN_&PROD_ST9320423AS\4&3516B3B5&0&000000
Кто-нибудь может дать разумное объяснение значению поля InterfaceType, прямо противоречащее как указанному ниже PNPDeviceID так и тому факту, что начиная с Windows 8.1 в HKLM\SYSTEM\CurrentControlSet\Enum\ интерфейс IDE вообще отсутствует и последний раз он присутствовал лишь в среде Windows 7?
3. Отрицательные значения в полях SerialNumber, Signature классами Win32_DiskDrive, Win32_Volume
SerialNumber: Hitachi HT100219FCC400NEJTBU5G
Signature: -1498719820
…
Purpose: null
QuotasEnabled: false
QuotasIncomplete: false
QuotasRebuilding: false
SerialNumber: -1408044882
Это вообще любимая “фишка”, выдача очень важной информации в совершенно неудобоваримом формате. И SerialNumber и Signature все привыкли читать в 16-ном виде.
4. Неверная индексация разделов для Gpt-форматированных дисков, класс Win32_DiskPartition
Caption: Disk #3, Partition #0
…
Description: GPT: Basic Data
Ну как, объясните мне, Gpt-форматированный раздел типа “Basic Data” приобрел индекс 0, который по праву принадлежит MSR-разделу? Естественно, что MSR-раздел Win32_DiskPartition в списке разделов вообще холодно игнорирует.
5. Наличие полей, содержащих NULL для JS или пусто для VBS для всех объектов в WQL-запросе
В качестве примера могу привести значения свойств Access и Description для класса Win32_Volume. У меня на 9 смонтированных устройствах, включающих два внутренних диска, пару виртуальных DVD-ROM, несколько VHD с Gpt-форматированными разделами, USB-диском, SD-картой и флэшкой, расположены 16 томов и все они в указанных полях содержат или NULL для JS-выдачи или пусто для VBS-выдачи. Спрашивается каким же должен быть том, на каком устройстве располагаться для того, чтобы для него хоть одно из указанных свойств оказалось значимым? А если такого быть не может, то зачем вообще включать эти свойства в выдачи?
Решил проверить с помощью PS и “gwmi win32_volume” для всех томов выдала пустые значения свойств Access, Description.
Заключение
Основной смысл этой короткой, возможно излишне эмоциональной публикации состоит в том, чтобы привлечь внимание всех, кто использует WMI-классы в своем коде, критически оценивать извлекаемые данные, перепроверять их из других источников. Сразу же добавлю, что MSFT-классы, аналогичные описанным выше Win32-классам, выдают всегда корректную информацию, хотя и они грешат выдачей отрицательных чисел в полях Signature.
Комментарии (8)
xtraroman
14.08.2015 10:20А еще можно добавить нулевой пункт. WMI сервис может быть банально выключен у пользователя на компьютере :).
sysprg_46
14.08.2015 10:32For sure, как говорят у них или «естессно», как принято у нас. Но я ведь и начал свои публикации с описания алгоритма, который читает информацию непосредственно из ОСНОВНОГО ИСТОЧНИКА ЗНАНИЙ, а именно Windows Registry.
gotch
Подскажите, что имеется в виду под MSFT-классами, аналогичными описанным выше Win32-классам?
sysprg_46
msft_disk — отличная замена win32_DiskDrive:
SELECT * FROM MSFT_Disk", «WQL»,…
…
SerialNumber: 5VH4135F
Signature: 272024004
…
NumberOfPartitions: 5 < — учтен Extended Partition на Mbr, Extended присваивает индекс 0, в точности как и Diskpart.exe, Primary индексируются с 1, Logical внутри Extended индексируются начиная с 4.
BusType: 11
Location: PCIROOT(0)#PCI(1F02)#ATA(C00T00L00) — важная информация
MSFT_Partition, замена Win32_Partition. Здесь и корректная индексация и забавнейший
AccessPaths: \\?\Volume{2c654a1d-e045-11e4-826d-806e6f6e6963}\,\\?\Volume{1036c1c4-0000-0000-007e-000000000000}\
немного ЖУЛЬНИЧАЮТ, нет уже под Windows 10 RTM TH1 такого GUID:
{1036c1c4-0000-0000-007e-000000000000}, но в этом классе он появился еще под 8.1 и был ОЧЕНЬ ПОЛЕЗЕН тем, что содержал parent Disk Signatue в поле Field 1 GUID и смещение раздела в последних двух полях. Такой GUID просуществовал во всех сборках Windows 10 начиная с 9826 и заканчивая 10166, но в в 10240 изменилась логика генерации GUID и такой формат GUID в десятке уже отсутствует.
Забавно и то, что в этом классе они фактически объединили и РАЗДЕЛЫ и ТОМА, поскольку и БУКВЫ ТОМОВ также отображаются этим же классом
AccessPaths: B:\,\\?\Volume{f0fd3322-2d89-11e5-82e0-806e6f6e6963}\,\\?\Volume{1036c1c4-0000-0000-0000-261600000000}\
DiskId: \\?\scsi#disk&ven_&prod_st9320423as#4&3516b3b5&0&000000#{53f56307-b6bf-11d0-94f2-00a0c91efb8b}
DiskNumber: 0
DriveLetter: 66
GptType: null
ну просто море удовольствия, все что нужно, и индекс родителя, и буква тома и пометка Gpt/Mbr
MSFT_PartitionToVolume — снимает ВСЕ вопросы о связи разделов и томов
MSFT_PhysicalDisk — малость добавляет к тому, что уже известно с помощью msft_disk
MSFT_Volume -важные дополнения к тому, что уже известно из MSFT+Partition
gotch
Но это тоже WMI классы, из того же namespace? Тогда остается лишь еще раз вспомнить про фатальный недостаток.
sysprg_46
простите мою темноту, не въехал в «фатальный недостаток». А namespace наверное вот здесь затаился:
winmgmts:\\\\" + arrComputers[i] + "\\root\\Microsoft\\Windows\\Storage
Мне MSFT классы понравились лишь в сравнении с Win32 классами, но у них есть очень серьезный недостаток — под семеркой таких классов нет вообще.
gotch
Фатальный недостаток
sysprg_46
Думаю, что Вы правы и зависимость от DLL в WMI сильная. Но я уже давно стал считывать нужную информацию непосредственно из Registry, поскольку твердо убежден, что в Registry есть ВСЕ, что может выдать любой из WMI-классов.