WMI-обозреватель

Небольшая обработка для отладки WQL запросов WMI.

WMI-обозреватель

Что такое WMI?

Windows Management Instrumentation (WMI) в дословном переводе — это инструментарий управления Windows. Если говорить более развернуто, то WMI — это одна из базовых технологий для централизованного управления и слежения за работой различных частей компьютерной инфраструктуры под управлением платформы Windows. Звучит страшно, а на самом деле это достаточно богатый набор инструментов, основные функции которого:

  • Получать данные о системах (диски, процессоры, процессы, журналы событий и многое-другое)
  • Выполнять широкий спектр административные задачи: от завершения процесса, до управления DHCP и DNS
  • Создавать скрипты, срабатывающие при наступлении каких-либо событий в системе
  • Получать данные счетчиков производительности 

В WMI есть иерархическая адресация всех ресурсов — что-нибудь типа WinMgmts:{impersonationLevel=impersonate}!//myServer/root/cimv2:Win32_LogicalDisk), но вместе с иерархическим доступом к ресурсам есть и SQL-подобный язык получения данных. Этот язык обычно называется WQL и в сети есть множество примеров его использования. На инфостарте можно обратить внимание на следующие статьи:

В MSDN можно ознакомиться начиная со следующих статей:

Типичный запрос WQL выглядит так:

SELECT CommandLine, Handle, Name FROM Win32_Process

Результатом этого запроса будет табличка, начинающаяся примерно так:

CommandLine Handle Name
  0 System Idle Process
  4 System
  224 smss.exe
  320 csrss.exe
  372 csrss.exe
  380 wininit.exe
  412 winlogon.exe
  476 services.exe
  484 lsass.exe
  492 lsm.exe
  588 svchost.exe
  656 svchost.exe
  744 svchost.exe
  792 svchost.exe
  840 svchost.exe
  880 svchost.exe
  920 svchost.exe
  508 svchost.exe
  1096 spoolsv.exe
  1156 hasplms.exe
  1236 svchost.exe
  1316 vmtoolsd.exe
  1680 TPAutoConnSvc.exe
  1900 dllhost.exe
  1980 msdtc.exe
taskhost.exe 1724 taskhost.exe
TPAutoConnect.exe -q -i vmware -a COM1 -F 30 616 TPAutoConnect.exe

Зачем нужен WMI-обозреватель?

WMI документирована хорошо, но отлаживать WQL запросы непосредственно в 1С не было возможности, а пользоваться внешними утилитами ради пары строк запроса вовсе не хочется. Для этой цели я сделал простенький WMI-обозреватель.

Пользовательский интерфейс WMI-обозревателя

Интерфейс состоит из 2 закладок: Запрос и Настройки. На закладке Запрос есть только поле для ввода запроса. По умолчанию запрос выполняется на текущем ПК в файловой версии и на сервере предприятия (от имени rphost) в клиент-серверной версии. По кнопке «Выполнить запрос» появляется таблица с результатами.

Если настройки по умолчанию не устраивают, переходим на вторую закладку. Там можно настроить:

  • Имя сервера с которого снимаются данные
  • Если установлен флажок «Собирать системные свойства», то в таблице будут выданы внутренние свойства каждой записи. Обычно это не требуется.
  • Если установлен флажок «Получать путь», то в таблице будут выдана колонка с иерархическим путём записи. Имеет смысл, если этот путь нужен для отладки запроса.
  • Если установлен флажок «Собирать методы», то в таблице первой колонкой будет поле «Methods». Если два раза кликнуть мышкой или нажать Enter на этой колонке, то будет выдан табличный документ с методами, которые можно применять в программном коде к значению WMI данной строки

Картинки:

 

Как можно использовать WMI-обозреватель?

Здесь я приведу просто набор запросов и пояснение, что можно получить этим запросом. Проверяйте, экспериментируйте.

Запрос Пояснение
SELECT Handle, Name, VirtualSize FROM Win32_Process WHERE VirtualSize>100000000 AND CreationDate > «20130604000000.000000+420» Выводится ID процесса, название процесса, размер адресуемого пространства для процессов, созданных позднее 4 июня 2013 года (в моём часовом поясе)
SELECT * FROM Win32_Service WHERE PathName LIKE «%ragent%» Все службы 1С со всеми данными по ним
SELECT Name, Capacity, FreeSpace FROM Win32_Volume Диски, их размер и свободное место
SELECT PercentProcessorTime FROM Win32_PerfFormattedData_PerfOS_Processor Текущая загрузка процессора
SELECT PercentDiskTime, AvgDiskQueueLength, DiskReadBytesPerSec, DiskWriteBytesPerSec FROM Win32_PerfFormattedData_PerfDisk_PhysicalDisk Текущая загрузка диска
Select * From meta_class Выполняется долго, содержит очень много колонок! Выводит все классы WMI

 

Как устроен WMI-обозреватель?

Весь WMI обозреватель благополучно поместился в одну управляемую форму (прямо скажу — не сильно сложную). Если по каким-то причинам Вы не можете скачать решение, то программный код этой формы приведен ниже.

&НаКлиенте
Процедура РезультатЗапросаВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
   
// При двойном клике на медоды, выводим их в табличный документ
   
Если Поле.Имя = «РезультатЗапросаMethods» Тогда
       
Методы = Элемент.ТекущиеДанные.Methods;
        Если
Методы.Количество()>0 Тогда
           
ТабличныйДокумент = Новый ТабличныйДокумент;
           
СчСтрок = 1;
            Для каждого
Метод Из Методы Цикл
               
ТабличныйДокумент.Область(СчСтрок, 1, СчСтрок, 1).Текст = Метод;
               
СчСтрок = СчСтрок + 1;
            КонецЦикла;
           
ТабличныйДокумент.Показать();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьЗапрос(Команда)
   
ВыполнитьЗапросНаСервере();
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Серверные методы формы

&НаСервере
Процедура ВыполнитьЗапросНаСервере()

    WMIЗапрос = ПолучитьCOMОбъектWMI(Объект.ИмяСервера);

    // «*» желательно заменить для ускорения на конкретный список полей
   
WMIРезультаты = WMIЗапрос.ExecQuery(Объект.ТекстЗапроса);

    РезультатЗапроса = ПреобразоватьРезультатыWMIвТаблицуЗначений(WMIРезультаты,
       
Объект.СобиратьСистемныеСвойства,
       
Объект.СобиратьМетоды,
       
Объект.ПолучатьПуть,
        Ложь);
   
//РезультатЗапроса.Колонки.Удалить(«Значение»); // В ней содержатся «COMОбъект», которые не выводятся

    ВывестиТаблицуЗначений(«РезультатЗапроса», РезультатЗапроса);

КонецПроцедуры

// Перезаполняет реквизит формы из таблицы значений.
// Предполагается, что реквизит уже есть на форме. Перезаполнение происходит
// полностью вместе с пересозданием колонок. Так медленнее, зато проще.
//
// Параметры:
//  ИмяРеквизита — Строка — Имя заполняемого реквизита формы
//  ЗначениеРеквизита —  ТаблицаЗначений — чем заполнять реквизит
//
&НаСервере
Процедура ВывестиТаблицуЗначений(ИмяРеквизита, ЗначениеРеквизита)

    ЭлементФормы = Элементы[ИмяРеквизита];
   
ПутьКДанным = ЭлементФормы.ПутьКДанным;

    МассивДобавляемыхРеквизитов = Новый Массив;
   
МассивУдаляемыхРеквизитов = Новый Массив;

    Для каждого ТекРеквизит из ПолучитьРеквизиты(ПутьКДанным) Цикл
       
МассивУдаляемыхРеквизитов.Добавить(ТекРеквизит.Путь + «.» + ТекРеквизит.Имя);
       
ИмяЭлементаВТаблице = ИмяРеквизита + ТекРеквизит.Имя;
       
Элемент = Элементы.Найти(ИмяЭлементаВТаблице);
        Если не
Элемент = Неопределено Тогда
           
Элементы.Удалить(Элемент);
        КонецЕсли;
    КонецЦикла;

    Для Каждого Колонка Из ЗначениеРеквизита.Колонки Цикл
       
ДобавляемыйРеквизит = Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ПутьКДанным, Колонка.Имя);
       
МассивДобавляемыхРеквизитов.Добавить(ДобавляемыйРеквизит);
    КонецЦикла;

    ИзменитьРеквизиты(МассивДобавляемыхРеквизитов,МассивУдаляемыхРеквизитов);
   
ЗначениеВРеквизитФормы(ЗначениеРеквизита, ПутьКДанным);

    Для Каждого ТекРеквизит Из МассивДобавляемыхРеквизитов Цикл

        ИмяЭлементаВТаблице = ИмяРеквизита + ТекРеквизит.Имя;
       
Элемент = Элементы.Добавить(ИмяЭлементаВТаблице, Тип(«ПолеФормы»), ЭлементФормы);
       
Элемент.Вид = ВидПоляФормы.ПолеВвода;
       
Элемент.ПутьКДанным = ПутьКДанным + «.» + ТекРеквизит.Имя;
       
Элемент.ТолькоПросмотр = Истина;

    КонецЦикла;

КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Блок функций WMI, если хотите использовать их в своих программах, то лучше
// вынести в отдельный модуль. Модуль лучше сделать серверным, потому что
// используются таблицы значений. Не забудьте удалить директивы компиляции.

// Возвращает настроенный COM-объект WMI
//
// Параметры:
//  ИмяСервера — Строка, имя или IP-адрес компьютера с которого будут получаться
//              значения счетчиков производительности. Можно не указывать, если
//              значения получаются со своего компьютера
//  ИмяСервераИсполнителя —  Строка, имя или IP-адрес компьютера на котором создаётся
//              COM объект. Обычно можно не указывать
//  ТочкаПодключения — Строка — по умолчанию «rootcimv2», но можно указать и своё
//
// Возвращаемое значение:
//  COMОбъект — objWMIService
//
&НаСервереБезКонтекста
Функция ПолучитьCOMОбъектWMI(Знач ИмяСервера = Неопределено, Знач ИмяСервераИсполнителя = Неопределено, Знач ТочкаПодключения = Неопределено) Экспорт

    //http://msdn.microsoft.com/en-us/library/windows/desktop/aa389763(v=vs.85).aspx
   
Если Не ЗначениеЗаполнено(ИмяСервераИсполнителя) Тогда
       
Locator = Новый COMОбъект(«WbemScripting.SWbemLocator»);
    Иначе
       
Locator = Новый COMОбъект(«WbemScripting.SWbemLocator», ИмяСервераИсполнителя);
    КонецЕсли;

    Если Не ЗначениеЗаполнено(ИмяСервера) Тогда
       
ИмяСервера = «.»;
    КонецЕсли;

    Если Не ЗначениеЗаполнено(ТочкаПодключения) Тогда
       
ТочкаПодключения = «rootcimv2»;
    КонецЕсли;

    objWMIService = Locator.ConnectServer(ИмяСервера, ТочкаПодключения);
    Возврат
objWMIService;

КонецФункции

// Преобразует результаты WMI-запроса в таблицу значений
//
// Параметры:
//  РезультатыWMI — COMОбъект — «сырые» результаты WMI-запроса
//  СобиратьСистемныеСвойства — Булево — признак необходимости сбора системных свойств, необязательный, по умолчанию Ложь
//  СобиратьМетоды — Булево — признак необходимости доступных методов, необязательный, по умолчанию Ложь
//  ПолучатьПуть — Булево — получать или не получать колонку с полным путем к значению в терминах WMI, по умолчанию Истина.
//  ПолучатьЗначениеWMI — Булево — получать или не получать колонку с самим значением WMI строки, по умолчанию Истина
//
// Возвращаемое значение:
//  ТаблицаЗначений — Преобразованная таблица значений (нетипизированная, потому что добывать типы сложно)
//
// Примечание:
// 1. ПолучатьЗначение следует устанавливать в Ложь, если планируется вывод на форму (COM-объект,
// содержащийся в колонке нормально не выводится), в Истина, если планируется вызов методов или другая доп. логика
// 2. ПолучатьПуть можно установить в Ложь, если нужно минимизировать передачу данных
&НаСервереБезКонтекста
Функция ПреобразоватьРезультатыWMIвТаблицуЗначений(РезультатыWMI,
        Знач
СобиратьСистемныеСвойства = Ложь,
        Знач
СобиратьМетоды = Ложь,
        Знач
ПолучатьПуть = Истина,
        Знач
ПолучатьЗначениеWMI = Истина) Экспорт

    ТаблицаWMI = Новый ТаблицаЗначений;
    Если
ПолучатьЗначениеWMI Тогда
       
ТаблицаWMI.Колонки.Добавить(«Значение»);
    КонецЕсли;
    Если
ПолучатьПуть Тогда
       
ТаблицаWMI.Колонки.Добавить(«Path»);
    КонецЕсли;
    Если
СобиратьМетоды Тогда
       
ТаблицаWMI.Колонки.Добавить(«Methods»);
    КонецЕсли;

    Для Каждого ЗначениеWMI Из РезультатыWMI Цикл
       
СтрокаТаблицыWMI = ТаблицаWMI.Добавить();
        Если
ПолучатьЗначениеWMI Тогда
           
СтрокаТаблицыWMI.Значение = ЗначениеWMI;
        КонецЕсли;
       
Свойства = ПолучитьСтруктуруИзЗначенияWMI(ЗначениеWMI.Properties_);

        ДобавитьСтруктуруВСтрокуТаблицаЗначений(СтрокаТаблицыWMI, Свойства);
        Если
СобиратьСистемныеСвойства Тогда
           
СистемныеСвойства = ПолучитьСтруктуруИзЗначенияWMI(ЗначениеWMI.SystemProperties_);
           
ДобавитьСтруктуруВСтрокуТаблицаЗначений(СтрокаТаблицыWMI, СистемныеСвойства);
        КонецЕсли;
        Если
ПолучатьПуть Тогда
           
СтрокаТаблицыWMI.Path = ЗначениеWMI.Path_.Path;
        КонецЕсли;

        Если СобиратьМетоды Тогда

            СтрокаТаблицыWMI.Methods = Новый Массив;

            // Описания методов возвращаем для людей, поэтому описание «человеколюбивое»
           
Для Каждого МетодWMI из ЗначениеWMI.Methods_ Цикл

                ОписаниеМетода = «Метод: » + МетодWMI.Name;
                Если
МетодWMI.InParameters <> Неопределено Тогда
                    Для Каждого
ПараметрWMI из МетодWMI.InParameters.Properties_ Цикл
                       
КвалификаторыПраметра = ПолучитьСтруктуруИзЗначенияWMI(ПараметрWMI.Qualifiers_);
                       
ОписаниеМетода = ОписаниеМетода + Символы.ПС + «Входной параметр: » + ПараметрWMI.Name;
                    КонецЦикла;
                КонецЕсли;

                Если МетодWMI.OutParameters <> Неопределено Тогда
                    Для Каждого
ПараметрWMI из МетодWMI.OutParameters.Properties_ Цикл
                       
КвалификаторыПраметра = ПолучитьСтруктуруИзЗначенияWMI(ПараметрWMI.Qualifiers_);
                       
ОписаниеМетода = ОписаниеМетода + Символы.ПС + «Выходной параметр: » + ПараметрWMI.Name;
                    КонецЦикла;
                КонецЕсли;

                СтрокаТаблицыWMI.Methods.Добавить(ОписаниеМетода);

            КонецЦикла;

        КонецЕсли;

    КонецЦикла;

    Возврат ТаблицаWMI;

КонецФункции

// Преобразует строку результатов WMI в структуру
//
// Параметры:
//  ЗначениеWMI — COMОбъект — строка результатов WMI-запроса
//
// Возвращаемое значение:
//  Структура — Коллекция значнний строки результатов WMI-запроса
//
&НаСервереБезКонтекста
Функция ПолучитьСтруктуруИзЗначенияWMI(ЗначениеWMI)

    Рез = Новый Структура;
    Для каждого
СвойствоWMI из ЗначениеWMI Цикл
        Если
ТипЗнч(СвойствоWMI.Value) = Тип(«COMSafeArray») Тогда
           
Рез.Вставить(СвойствоWMI.Name, СвойствоWMI.Value.Выгрузить());// возможно массив надо будет переделать
       
Иначе
           
Рез.Вставить(СвойствоWMI.Name, СвойствоWMI.Value);
        КонецЕсли
    КонецЦикла;

    Возврат Рез;

КонецФункции

// Добавляет все значения структуры в строку ТЗ. Если не хватает колонок — добавляет нетипизированную
//
// Параметры:
//  ТекущаяСтрокаТаблицы — СтрокаТаблицыЗначений — Строка в которую записываются данные
//  ДобавляемаяСтруктура — Структура — структура с значениями
//
// Возвращаемое значение:
//  Структура — Коллекция значнний строки результатов WMI-запроса
//
&НаСервереБезКонтекста
Процедура ДобавитьСтруктуруВСтрокуТаблицаЗначений(ТекущаяСтрокаТаблицы, ДобавляемаяСтруктура)

    ТаблицаЗначений = ТекущаяСтрокаТаблицы.Владелец();
   
Колонки = ТаблицаЗначений.Колонки;
    Для Каждого
ЭлементСтруктуры Из ДобавляемаяСтруктура Цикл
        Если Неопределено =
Колонки.Найти(ЭлементСтруктуры.Ключ) Тогда
           
Колонки.Добавить(ЭлементСтруктуры.Ключ);
        КонецЕсли;
       
ТекущаяСтрокаТаблицы[ЭлементСтруктуры.Ключ] = ЭлементСтруктуры.Значение;
    КонецЦикла

КонецПроцедуры

Напоследок

  • Это не супер-пупер инструмент, а скорее наколеночная демонстрация работы с WMI, просто, к сожалению, я не нашёл аналога в существующих разработках.
  • Проверено в 1С 8.2 и 1С 8.3 в управляемых формах.
  • Очевидно, что при правильно настроенном rphost могут возникнуть проблемы с правами (rphost должен быть почти бесправен).
  • Код этой обработки можете свободно использовать в своих разработках.
  • Замечания и предложения принимаются 🙂

 

12 Comments

  1. tormozit

    Поддержка WQL (WMI) реализована в консоли запросов (ИР) с конструктором запроса и отображением справочной информации по классам/свойствам. https://www.youtube.com/watch?v=bFDDJqToPTM

    Reply
  2. speshuric

    (1) tormozit, Я очень рад, что эта возможность появилась в ИР. Всем заинтересованным рекомендую для ознакомления/использования

    Reply
  3. CaSH_2004

    Из пожеланий: явно нужен обычный режим, не все работают в УФ.

    Reply
  4. speshuric

    (3) Ну так, вон, Сергей утянул в свои тулзы, они не в УФ. Я дальше и не стал ничего делать, у Сергея всё отлично работает, меня устраивает.

    Reply
  5. veterskv

    Замечательная статья, но вопрос. Можно ли с помощью WMI повлиять на настройки принтера? Не на параметры страницы табличного документа, а именно на настройки принтера.

    Необходимо: выводить документ с настройками:

    2 копии

    разобрать на копии = Истина

    2 страницы на лист (страницы — портрет, лист — ландшафт)

    двусторонняя печать

    Сложность в том, что когда задаешь параметры для ТабДок средствами 1С, то упорно получается: (страницы — портрет, лист — портрет) или (страницы — ландшафт, лист — портрет), т.е. лист всегда портрет.

    А если устанавливать параметры через настройки принтера, то все получается как надо.

    Reply
  6. zekrus

    Добрый день!

    Тема весьма актуальная.

    Было бы еще замечательно добавить дерево запросов, с возможностью сохранения в файл (по аналогии с консолью запросов).

    П.С. никто не в курсе какой запрос нужен для получения сеансов пользователей — нужны логины (пытаюсь учитывать перекуры за день)?

    С уважением

    Reply
  7. tormozit

    (6) А (1) Чем не устраивает?

    Reply
  8. zekrus

    (7) Прокси-сервер отказывается принимать соединения — https://www.youtube.com/watch?v=bFDDJqToPTM

    Reply
  9. tormozit

    (8) А в (0) он соглашается принимать соединения?

    Reply
  10. tormozit

    (8) Если возникла проблема с этим инструментом то рекомендую описать ее подробно на форуме основного сайта ИР.

    Reply
  11. zekrus

    (9) Да

    Reply
  12. zekrus

    (10) Дело не в инструменте (а в ссылке на него, слово ИР для меня не знакомо). Ютюб на работе закрыт. Попробовал поиском найти «инструмент разработчика» так в публикации нет упоминатий в описании об работе с WMI. И сюда то я пришел по этому же поиску «WMI» с яндекса (правьте и к вам придут с яндекса).

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *