Блог компании RUVDS.com, Системное администрирование, Разработка под Windows, Системное программирование, PowerShell
Рекомендация: подборка платных и бесплатных курсов таргетированной рекламе — https://katalog-kursov.ru/
В операционных системах Windows поддерживаются различные объектные инфраструктуры. Для доступа к ним можно использовать интерфейсы прикладного программирования (API), но разработка полноценных приложений не всегда оправдана. В PowerShell существуют специальные командлеты, позволяющие обращаться к объектам .NET, COM, WMI (CIM) и ADSI в интерактивном режиме. В четвертой части цикла мы изучили основы с упором на классы .NET Core, а сейчас хотим углубить тему и разобрать особенности взаимодействия PowerShell с внешними объектами.
Оглавление:
Работа с JSON, XML и CSV
Работа с WMI и CIM
Работа с COM-объектами
Работа со службой каталогов ADSI
Форматирование вывода
Работа с JSON, XML и CSV
В сценариях PowerShell довольно часто приходится разбирать данные в форматах JSON, XML и CSV. Обычно такая необходимость возникает при работе с интернет-сервисами или с конфигурационными файлами. Некоторые администраторы пытаются парсить данные с помощью регулярных выражений, но идти на такие жертвы необязательно: в PowerShell есть специальные командлеты для конвертации, притом в обе стороны.
Формат JSON позволяет описывать разнообразные объекты и по сути представляет собой допускающую вложенность хэш-таблицу. Соответственно преобразовать объект JSON в объект .NET при помощи PowerShell несложно. Поскольку интернет-сервисы обычно отдают вместо красиво отформатированного файла очень длинную строку, это преобразование может пригодиться и для работы в интерактивном режиме. В примере ниже для описания объекта JSON мы использовали многострочную текстовую переменную:
$user = @"
{
"firstName": "Ivan",
"lastName": "Danko",
"address": {
"streetAddress": "Kremlin",
"city": "Moscow"
},
"phoneNumbers": [
"+7 495 1234567",
"+7 499 1234567"
]
}
"@ | ConvertFrom-Json
Обратная задача решается сходным образом:
$file = Get-ChildItem C:WindowsSystem32notepad.exe
$file.VersionInfo | ConvertTo-Json
Полученную строку в формате JSON нетрудно отправить другому приложению по сети. Это может быть, например, некий RESTful сервис. Работа с командлетами ConvertFrom-Csv, ConvertTo-Csv и ConvertTo-Xml строится примерно так же, предлагаем читателям изучить ее самостоятельно.
Для работы с XML и CSV нам потребуются и другие командлеты:
Используя эти инструменты нужно понимать, что преобразование бинарного объекта в текстовый формат сохраняет только значение его свойств, но не методы. Преобразование данных в формате JSON, XML или CSV в объект .NET с помощью PowerShell возможно, только если они валидны.
Работа с WMI и CIM
Windows Management Instrumentation (WMI) — это разработанная в Microsoft и адаптированная под Windows реализация стандарта WBEM (Web-Based Enterprise Management). В его основе лежит идея создания универсального решения для мониторинга распределенной информационной среды предприятия и управления ее компонентами. Структура данных WBEM в свою очередь основана на Common Information Model (CIM), реализующей объектно-ориентированный подход к представлению компьютерных систем. Дальнейшая разработка и поддержка WMI в Windows прекращена, Microsoft рекомендует использовать для управления инфраструктурой сходный механизм — объекты CIM. Для работы ними в PowerShell 3.0 появились специальные командлеты, которые мы будем рассматривать параллельно с аналогами для WMI. Если в коде есть вызовы командлетов для работы с WMI, его по возможности стоит переписать.
В рамках модели CIM (она же используется в WMI) данные операционной системы представлены в виде классов со свойствами и методами. Классы группируются в иерархически упорядоченные и логически связанные по технологии или области управления пространства имен. Существует корневое пространство имен Root, в котором имеются подпространства: CIMv2, Default, Secutiry и WMI. Для однозначной идентификации экземпляра класса (объекта) и описания состояния соответствующего ему ресурса используются свойства класса, которые обычно доступны только для чтения. Для управления ресурсом используются методы.
К экземпляру класса можно обратиться по полному пути, который имеет следующий вид:
[\ComputerNameNameSpace][:ClassName][.KeyProperty1=Value1][,KeyProperty2=Value2]…]
где
ComputerName — имя компьютера;
NameSpace — пространство имен;
ClassName — имя класса;
KeyProperty1=Value1, KeyProperty2=Value2 — свойства объекта и значения, по которым он идентифицируется.
До появления PowerShell простого инструмента работы с WMI не существовало. Для доступа к объектам приходилось писать довольно сложные программы на высокоуровневых языках (C++, Visual Basic, Java Script) либо изучать оболочку WMIC (WMI Command Line, поддержка которой также прекращена) с собственным языком. Через PowerShell объекты WMI доступны рядовому пользователю из командной строки или в сценариях. Для начала подключимся к подсистеме WMI и получим список доступных классов с помощью командлета Get-WmiObject (псевдоним gwmi). Чтобы получить список классов CIM, используйте командлет Get-CimClass.
Get-CimClass
Get-WmiObject -List
Мы вывели список классов на локальном компьютере, но можно подключиться и к удаленному:
Get-CimClass -ComputerName IP-адрес
Get-CimClass -ComputerName Имя_компьютера
или
Get-WmiObject -ComputerName IP-адрес -List
Get-WmiObject -ComputerName Имя_компьютера -List
По умолчанию командлеты Get-CimClass и Get-WmiObject подключаются к пространству имен RootCIMV2, в котором хранится большое количество классов для управления системой. Для смены пространства имен применяется параметр -Namespace:
Get-CimClass -Namespace Root
Get-WmiObject -Namespace Root -List
Зная имя класса, нетрудно получить его экземпляры. Следующая команда возвращает все экземпляры Win32_Service, т.е. зарегистрированные на локальной машине службы:
Get-WmiObject Win32_Service
Как и в случае с объектами других типов, список свойств и методов выводится при помощи Get-Member. К методам объекта WMI можно обращаться напрямую или с помощью командлета Invoke-WmiMethod. Также к объектам WMI можно применять командлеты для сортировки, фильтрации, группировки и т.д.
Get-WmiObject Win32_Service | Get-Member
Для получения объектов (экземпляров классов) CIM используется командлет Get-CimInstance. В отличие от WMI, результирующие CIM-объекты (resultant object или экземпляры класса) не содержат методов класса. Поскольку извлечь метод непосредственно невозможно, придется вызывать командлет Invoke-CimMethod. Рассмотрим класс Win32_Service — запущенные в системе службы) и его экземпляр для службы spooler на локальной машине:
Get-CimInstance Win32_service -filter "Name='spooler'"
Посмотрим на структуру результирующего объекта:
Get-CimInstance Win32_service -filter "Name='spooler'" | Get-Member
На этом этапе преимущества командлетов для работы с объектами CIM неочевидны. Они в первую очередь касаются удаленной работы в распределенной среде и будут подробно рассмотрены в последней статье цикла, посвященной решению практических задач администрирования.
Есть и специфичный для WMI инструментарий: язык запросов WMI Query Language (WQL), напоминающий SQL. WQL-запрос для поиска всех стартующих при запуске системы служб выглядит так:
select * from win32_service where startmode="Auto"
Из PowerShell они выполняется следующим образом:
Get-WmiObject -Query 'select * from win32_service where startmode="Auto"'
Работа с COM-объектами
Для обеспечения взаимодействия между приложениями в Windows была разработана технология связывания и внедрения объектов (Object Linking and Embedding или OLE). Позже появилась технология OLE Automation, с помощью которой приложения клиенты автоматизации могли вызывать функции других приложений — серверов автоматизации. OLE и OLE Automation были основаны на базовой технологии Component Object Model (COM), которая предлагает единый двоичный стандарт для программных компонентов. Созданные по нему и зарегистрированные в операционной системе объекты могут использоваться в других приложениях с помощью исполняемых файлов или динамических библиотек.
Примерно с середины девяностых годов вместо OLE стал использоваться другой термин — ActiveX. До появления платформы .NET технология ActiveX считалась ключевой, а объекты COM до сих пор активно используются для интеграции приложений в Windows — многие продукты Microsoft и сторонних разработчиков являются серверами автоматизации и предоставляют через них доступ к своим сервисам. Для обращения к объектам используется ProgID — символьный идентификатор, который присваивается им при регистрации в реестре Windows. Он имеет следующий вид:
Библиотека_типов.Класс.Версия
Версия обычно не указывается:
Библиотека_типов.Класс
Несколько примеров доступных ProgID: InternetExplorer.Application (приложение Internet Explorer), Word.Application (приложение Microsoft Word), WScript.Shell (класс Shell из объектной модели сервера сценариев Windows Script Host или WSH).
Создать экземпляр объекта можно с помощью рассмотренного в предыдущей статье командлета New-Object, а посмотреть его структуру — с помощью Get-Member:
$myshell = New-Object -ComObject WScript.Shell
$myshell | Get-Member
Для работы с объектами используются свойства и методы. Скажем, чтобы создать на рабочем столе пользователя ярлык, нужно вызвать метод CreateShortcut():
$link = $myshell.CreateShortcut("$HomeDesktopHome.lnk")
Обратите внимание, что ярлык — это тоже объект COM:
$link | Get-Member
Нам остается заполнить его свойства и сохранить:
$link.TargetPath = $Home
$link.Save()
Таким способом мы создали ярлык на рабочем столе активного пользователя, а теперь разберем работу с внешними сервисами автоматизации на примере COM-объекта Shell.Application. С его помощью можно автоматизировать некоторые действия в проводнике Windows:
$myshell=New-Object -ComObject Shell.Application
или для краткости:
$myshell=New-Object -com Shell.Application
$myshell | Get-Member
У объекта Shell.Application есть довольно много различных методов управления окнами. К примеру, для отображения содержимого заданного каталога используется Explore():
$myshell.Explore("c:")
Справочная система вызывается с помощью метода Help():
$myshell.Help()
Есть также три метода для вызова диалоговых окон поиска: FindFiles(), FindComputer() и FindPrinter().
$myshell.FindFiles()
$myshell.FindComputer()
$myshell.FindPrinter()
Открыть диалоговое окно запуска программ можно с помощью метода FileRun(), а для вызова окна установки даты/времени нужен метод SetTime(). Есть, к примеру, методы для вызова окна настройки панели задач, элементов панели управления с указанием одного из доступных файлов cpl, для управления открытыми окнами:
$myshell.MinimizeAll()
$myshell.UndoMinimizeAll()
$myshell.TileHorizontally()
$myshell.TileVertically()
Метод Windows() позволяет получить доступ к коллекции открытых в проводнике или в браузере Internet Explorer окон. Посмотрим доступные для этой коллекции свойства и методы:
$myshell.Windows() | Get-Member
Существуют и другие полезные COM-объекты, количество которых зависит от установленного в системе ПО. Когда-то основным средством автоматизации в Windows считался сервер сценариев WSH, объектная модель которого включает и COM-объекты: предназначенный для работы с сетевыми функциями WScript.Network и уже упомянутый нами WScript.Shell. Последний не только создает ярлыки на рабочем столе, с его помощью можно, например, выводить информационные окна с сообщениями и кнопками, переключаться между приложениями, запускать программы или имитировать нажатия клавиш.
Работа со службой каталогов ADSI
Под каталогом в общем случае подразумевается источник информации, в котором хранятся данные о некоторых объектах. Под службой каталога мы понимаем часть распределенной компьютерной системы, позволяющий обращаться к хранящимся объектам и манипулировать ими. Служба каталога может объединять данные об объектах сети и осуществляющих манипуляцию ими сервисов — она представляет собой единую точку входа для взаимодействия с сетевыми ресурсами. В гетерогенной компьютерной сети таких служб может быть множество: локальный диспетчер SAM (Security Account Manager) для не входящих в домен компьютеров, Active Directory и т.д.
Для взаимодействия с разными службами каталогов требуются различные инструменты, что создает определенные неудобства. Начиная с Windows 2000 корпорация Microsoft внедрила в операционные системы унифицированную технологию ADSI (Active Directory Service Interface) для не зависящего от конкретного сетевого протокола доступа. Чтобы находить объекты, для каталога определяется пространство имен. Поскольку разные службы каталогов используют различные способы именования, ADSI определяет позволяющее однозначно идентифицировать любой объект соглашение. Вводится понятие состоящих из двух частей строк связывания (binding string) или ADsPath. Первая часть имени определяет службу каталогов (провайдера ADSI), а вторая — расположение объекта в каталоге. Приведем примеры обозначения разных провайдеров ADSI:
LDAP:// используется для основанной на LDAP службы каталогов, в т.ч. для Active Directory;
WinNT:// используется для локальных компьютеров.
Специальных командлетов для работы с ADSI в PowerShell нет. Вместо них применяется оператор приведения типов [ADSI] после которого указывается строка связывания. Например, для подключения к пользователю Ivanov из домена test.ru нужна следующая конструкция:
$user = [ADSI]"LDAP://CN=Ivanov,DC=TEST,DC=RU"
Чтобы работать с локальными учетными записями, придется подключиться к компьютеру с соответствующим именем (для подключения к локальному компьютеру вместо имени достаточно использовать точку):
$computer = [ADSI]"WinNT://."
Для примера создадим на локальной машине нового пользователя Ivanov:
$user = $computer.Create("user","Ivanov")
$user.Put("Description","Создан из PowerShell")
$user.SetInfo()
Теперь подключимся к нему:
$user1 = [ADSI]"WinNT://./Ivanov,user"
$user1.Description
Форматирование вывода
Интерактивная работа часто требует выводить данные на экран. В других оболочках команды и утилиты сами занимаются форматированием вывода, но возвращаемые функциями и командлетами бинарные объекты обычно не умеют этого делать. В PowerShell вывод форматируют четыре специальных командлета, которым объекты «скармливаются» через конвейер. Более подробные сведения них можно получить с помощью Get-Help:
Format-Table форматирует вывод в виде таблицы, столбцы которой содержат значения свойств объекта или вычисляемые значения. Поддерживается возможность группировки данных;
Format-List выводит объект как список свойств, каждое из которых отображается на новой строке. Поддерживается возможность группировки данных;
Format-Custom форматирует вывод с использованием пользовательского представления;
Format-Wide форматирует объекты в виде широкой таблицы, в которой отображается только одно свойство каждого объекта.
Если ни один из перечисленных командлетов не вызван, применяется соответствующий типу отображаемых данных модуль форматирования. Правила отображения хранятся в конфигурационных файлах в формате XML с расширением .ps1xml, которые находятся в каталоге $PSHome. Их список можно получить с помощью следующей команды:
dir $pshome*format*.ps1xm
Редактировать конфигурационные файлы вручную не рекомендуется, лучше создать собственные и включить их в список загружаемых с помощью командлета Update-FormatData. Если модуль форматирования по умолчанию для нужного типа не определен, PowerShell отображает на экране свойства объекта в виде списка.
На этом мы завершим описание работы с объектами в PowerShell, а заключительная статья цикла будет посвящена решению практических задач управления распределенной информационной средой предприятия. В ней нам пригодится весь описанный инструментарий. Основной упор будет сделан на объекты CIM и сравнение их с WMI. Прошлые части можно найти по ссылкам ниже.
Часть 1: Основные возможности Windows PowerShell
Часть 2: Введение в язык программирования Windows PowerShell
Часть 3: Передача параметров в скрипты и функции, создание командлетов
Часть 4: Работа с объектами, собственные классы
WMI (Windows Management Instrumentation) — это технология, с помощью которой можно получить и изменить достаточно широкий перечень параметров Windows.
Для примера мы хотим узнать информацию о процессоре. Мы можем использовать команду CMD sysinfo или Powershell Get-ComputerInfo, но увидеть только часть информации. С помощью WMI мы можем получить почти всю информацию.
Для получения всех классов WMI в Powershell мы можем использовать:
Get-WmiObject -List
Мы получим все классы для пространства имен rootcimv2 т.к. оно стоит по умолчанию. Если мы хотим использовать другое, то его нужно указать с ключом -Namespace.
Одной из особенностей этого командлета является, что мы можем получить все классы и свойства и исполнить методы на удаленном компьютере:
Get-WmiObject -List -ComputerName CL1
Где:
-ComputerName — имя компьютера
WMI работает на 135 порту, а так же привилегированная учетная запись с правами на WMI и DCOM.
Либо у нас должен работать PSRemoting (тогда мы будем использовать Ivoke-Command). Весь процесс описан тут.
Получение свойств класса через Powershell WMI
Если мы еще не знаем какой класс нам нужен, а вывод очень большой, то мы можем немного отфильтровать результат. На примере я искал классы где в имени есть BIOS:
Get-WmiObject -List | where {$_.name -like "*BIOS*"}
Если мы выведем свойства класса операционной системы, то не увидим названия:
Get-WmiObject -Class Win32_OperatingSystem
Часть свойств можно получить и так:
[wmiclass]"Win32_OperatingSystem" | Get-Member
Для того что бы отобразить все свойства нужно выполнить:
Get-WmiObject -Class Win32_OperatingSystem | Select-Object -Property *
Либо можно объявить результат в переменную:
$result = Get-WmiObject -Class Win32_OperatingSystem
Получить все значения переменной:
$result | Get-Member
И затем вызывать через переменную. Так я получу название:
$result.Caption
Поиск свойств в Powershell WMI
У нас два способа поиска нужных свойств. Первый через ключ -Filter:
Get-WmiObject -List | where {$_.Name -Like "*share*"}
Get-WmiObject -Class Win32_Share -Filter "Status = 'OK'"
Но если мы напишем что-то не так, то увидим язык WQL (WMI Query Language):
Get-WmiObject : Invalid query «select * from Win32_Share where Status1 = ‘OK'»
Т.е. мы можем писать и запрос WQL:
Get-WmiObject -Query "SELECT * FROM Win32_share WHERE Status='OK'"
Вызов методов WMI через Powershell
Этот метод запустит Notepad.exe на удаленном компьютере AD. В $cred будут храниться учетные данные, если мы будем запускать процесс под другим пользователем.
$cred = Get-Credential
$process = Get-WmiObject -Query "SELECT * FROM Meta_Class WHERE __Class = 'Win32_Process'" `
-Namespace "rootcimv2" -Computername 'AD' -Credential $cred
$process.Create( "notepad.exe" )
Есть другой подход, с другой командой:
Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe
Отмечу, что вызвать процесс в графической оболочке нельзя, он будет запущен в бэкграунде. Связано это с тем, что Microsoft против что бы вторгались в интерактивный сеанс пользователя кому-либо (не моя цитата). Один из вариантов решения этого помещать задачи в планировщике.
Для того что бы увидеть остальные команды по работе с WMI в Powershell можно запустить:
Get-Command -Noun *WMI*
Что бы увидеть примеры использования или получить справку:
Get-help Invoke-WmiMethod -Examples
…
Теги:
#powershell
#wmi
WMI (Windows Management Instrumentation) is part of Windows since Windows 2000. It is a service that can query almost every detail about a computer system. PowerShell ships with full WMI support.
These are the most important CIM (Common Information Model) cmdlets:
Cmdlet | Purpose |
---|---|
Get-CimInstance | Gets instances of WMI classes. This is the most important cmdlet. |
Get-CimClass | Gets a WMI class. Use it to access static WMI methods. |
Invoke-CimMethod | Runs a WMI method, and returns results. |
Set-CimInstance | Writes back changed properties. |
New-CimSession | Creates a new remoting session to one or more remote systems |
New-CimSessionOption | Defines special options for remoting connections. |
Remove-CimSession | Closes and removes a remoting session that is no longer used. |
New-CimInstance | Creates a new instances of a WMI class, i.e. for temporary use. |
All of these ship in the module CimCmdlets that was introduced in PowerShell 3. To get a full list of CIM cmdlets, run the command below:
Get-Command -Module CimCmdlets
Getting Information
To get useful information from WMI, you need to know where the information resides. WMI uses namespaces and classes to organize its content:
- Namespace: a namespace works like a folder. WMI uses a namespace tree to organize its classes. The top of this tree is always called root. The namespace root/cimv2 is the default namespace. If you want to use a different namespace, you need to explicitly use the parameter -Namespace.
- Class: a class consists of properties (information) and methods (commands). Most properties are read-only.
The default namespace root/cimv2 contains most of the WMI classes used in scripting. So unless you need to access more exotic WMI classes in other namespaces, you don’t need to care much about namespaces.
If you do care, and would like to investigate the available namespaces (and classes), please refer to this sample code, or peek a bit down this article.
Querying Information
To get information from WMI, you ask for instances of a given class. The PowerShell code for this is always the same, so the hardest part in WMI is to figure out the name of the class that describes what you are after.
You can either use the reference and browse through the classes available in a given namespace. Or you can simply guess: most WMI classes start with “Win32_”, followed by an English word (singular) describing what you are after.
So to get information about your computer BIOS, the appropriate class name would be Win32_BIOS.
There are two cmdlets you can use to query information: Get-WmiObject
and Get-CimInstance
:
# original cmdlet, discontinued in PowerShell 6:
Get-WmiObject -Class Win32_BIOS
# new cmdlet, introduced in PowerShell 3:
Get-CimInstance -ClassName Win32_BIOS
Get-WmiObject
was introduced in PowerShell 1 and is available in all version of Windows PowerShell.
The cmdlet was replaced by the more sophisticated Get-CimInstance
in PowerShell 3. Today, Get-WmiObject
is considered obsolete and should be replaced by Get-CimInstance
. In *PowerShell 6 and better, Get-WmiObject
was removed.
Filtering Information
WMI can filter results and return only instances where a given condition exists. For example, the WMI class Win32_LogicalDisk represents all logical drives:
Get-CimInstance -ClassName Win32_LogicalDisk
These can be all kinds of drives, and the result may look like this:
DeviceID DriveType ProviderName VolumeName Size FreeSpace
-------- --------- ------------ ---------- ---- ---------
C: 3 OS 1007210721280 517862002688
D: 2 64421232640 64418349056
Z: 4 \127.0.0.1c$ OS 1007210721280 517862002688
The property DriveType apparently identifies the type of drive, and from looking at the data, the number 3 seems to identify fixed disks.
If you want the exact meaning for WMI codes, you can always look up the class in our reference and get a precise listing of friendly names for code numbers.
In order to get back only fixed disks, you can filter the results. Either use -Filter and specify the condition that must be met, or replace -ClassName by -Query and submit a SQL-like query:
Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3'
Get-CimInstance -Query 'Select * From Win32_LogicalDisk Where DriveType=3'
The result is the same in both cases.
Try and avoid using Where-Object
to filter WMI results. Where-Object
does client-side filtering and is inefficient: all data needs to be retrieved, and Where-Object
is discarding unwanted data in a second step. WMI filtering in contrast produces only the information required which is much more efficient, especially across a network.
Listing Namespaces
Remember? WMI namespaces work like folders, and each namespace can contain a number of WMI classes. The default namespace root/cimv2 is the most important, but there are many more. In fact, every vendor and software producer can add their own.
There is no cmdlet to list all WMI namespaces. To examine the available namespaces, use Get-CimInstance
from above: each child namespace is represented by an instance of the WMI class __Namespace inside the parent namespace.
To find all available namespaces, start with the top namespace root, and use a queue or recursive calls to examine all child namespaces:
# create a new queue
$namespaces = [System.Collections.Queue]::new()
# add an initial namespace to the queue
# any namespace in the queue will later be processed
$namespaces.Enqueue('root')
# process all elements on the queue until all are taken
While ($namespaces.Count -gt 0 -and ($current = $namespaces.Dequeue()))
{
# find child namespaces
Get-CimInstance -Namespace $current -ClassName __Namespace -ErrorAction Ignore |
# ignore localization namespaces
Where-Object Name -NotMatch '^ms_d{2}' |
ForEach-Object {
# construct the full namespace name
$childnamespace = '{0}{1}' -f $current, $_.Name
# add namespace to queue
$namespaces.Enqueue($childnamespace)
}
# output current namespace
$current
}
For more information about namespaces and a list of typical namespaces, please refer to this article.
Listing WMI Classes
Remember? WMI classes are where the beef is. Each class represents something specific, i.e. the class Win32_Processor represents CPUs, whereas the class Win32_NetworkAdapter represents network cards. To work with WMI, you need to know the exact class name that is representing what you’d like examine.
Get-CimClass
returns all classes in a given namespace. Since root/cimv2 is the default namespace, this will create a sorted list of all class names living in namespace root/cimv2:
Get-CimClass | Select-Object -ExpandProperty CimClassName | Sort-Object
For more information about classes, and how to identify useful classes for scripting, please refer to this article.
Changing Information
WMI is primarily a way to describe the computer and its settings and to retrieve information. The vast majority of properties are read-only. WMI is not widely used to configure and change settings.
In some scenarios, WMI can actually change things and settings. Let’s take a look at the class Win32_Environment. This class represents Windows Environment variables, so to list all of them, ask WMI to return all instances of this class:
Get-CimInstance -ClassName Win32_Environment
Adding New Instances
When you create a new Windows Environment variable, regardless of how you do this, as a result of this, WMI adds a new instance of Win32_Environment.
As you may know, Windows Environment variables can be defined per User and per Machine. Both of these are supported by WMI. When you launch a program, it receives a copy of them (called the process set). These copied (and temporary) environment variables are not represented by Win32_Environment.
So when you create a new environment variable in PowerShell using the drive env:, this will not change the instances of Win32_Environment:
$before = Get-CimInstance -ClassName Win32_Environment # create a temporary environment variable $env:myNewEnv = 1 $after = Get-CimInstance -ClassName Win32_Environment $new = $after.Count - $before.Count "Detected $new new environment variables"
However, when you create a permanent new environment variable, i.e. via an API call, this does add a new instance to Win32_Environment:
$before = Get-CimInstance -ClassName Win32_Environment # create a permanent environment variable [Environment]::SetEnvironmentVariable('myNewVar', 124, 'User') $after = Get-CimInstance -ClassName Win32_Environment $new = $after.Count - $before.Count "Detected $new new environment variables"
You can reverse this: by using New-CimInstance
to manually add a new instance of Win32_Environment, you can actually create a new Windows Environment variable. The code below creates a new environment variable named SomeInfo in the context of the current user.
Warning: you cannot create new instances from just about any WMI class this way. In fact, most WMI classes do not support creating new instances manually. Instead, they use methods to add new instances, or don’t support adding new instances at all.
# create username for current user
$username = '{0}{1}' -f $env:USERDOMAIN, $env:USERNAME
# define initial values to create a new instance of
# Win32_Environment (new environment variable)
$initialValues = @{
Name = 'SomeInfo'
VariableValue = '123'
UserName = $username
}
# create new instance
$newEnv = New-CimInstance -ClassName Win32_Environment -Property $initialValues
$newEnv
This is a permanent change, and from now on, you can access this variable via WMI like so:
$variable = Get-CimInstance -ClassName Win32_Environment -Filter 'Name="SomeInfo"'
$variable.VariableValue
Changing Properties
Information returned by WMI objects are read-only. So when you followed the example above and created and retrieved the environment variable SomeInfo, you can read its value. When you change its value, though, the environment variable will not change.
Even though the WMI object happily accepts any change to its properties, and even stores them, they are not permanent:
# get the environment variable "SomeInfo"
# NOTE: this variable must exist! Use previous example to create it.
$variable = Get-CimInstance -ClassName Win32_Environment -Filter 'Name="SomeInfo"'
$variable.VariableValue
# properties can be changed:
$variable.VariableValue = 'NEW!'
$variable.VariableValue
# however these changes are not permanent and do not affect the
# underlying environment variable
Once you retrieve the original object again, the old value is restored:
$variable = Get-CimInstance -ClassName Win32_Environment -Filter 'Name="SomeInfo"'
# old value is restored:
$variable.VariableValue
To permanently change the property, use Set-CimInstance
:
# get the environment variable "SomeInfo"
# NOTE: this variable must exist! Use previous example to create it.
$variable = Get-CimInstance -ClassName Win32_Environment -Filter 'Name="SomeInfo"'
$variable.VariableValue
# assign a new property value:
$variable.VariableValue = "NEW"
# Update the change:
$variable | Set-CimInstance
# retrieve the object again
$variable = Get-CimInstance -ClassName Win32_Environment -Filter 'Name="SomeInfo"'
# change is permanent:
$variable.VariableValue
Warning: most properties won’t allow you to change their values. Instead, they use methods to change and manage settings (if supported at all).
Calling WMI Methods
Some WMI classes can contain methods. Methods can either be implemented in specific instances that you received from Get-CimInstance
, or directly in WMI classes that you received from Get-CimClass
.
Use the code below to figure out more about implemented methods.
# figure out the methods supported by Win32_Process:
$className = 'Win32_Process'
# get the underlying WMI class:
$class = Get-CimClass -ClassName $className
# define a calculated property named "Implemented":
$implemented = @{
Name = 'Implemented'
Expression = {
# read the method qualifiers:
$qualifiers = $_.Qualifiers.Name
# check to see who implements this method:
if ($qualifiers -notcontains 'Implemented')
{
# this method is not implemented by anyone
# it cannot be used:
'Not implemented'
}
elseif ($qualifiers -contains 'Static')
{
# this is a static methods implemented by
# the WMI class itself:
'Class'
}
else
{
# this is a dynamic method implemented by
# every instance of this class:
'Instance'
}
}
}
# find out who implements the methods
# get all methods from this class:
$class.CimClassMethods |
# output method details and implementation:
Select-Object -Property Name, $implemented, ReturnType, Parameters
The result looks similar to this:
Name Implemented ReturnType Parameters
---- ----------- ---------- ----------
Create Class UInt32 {CommandLine, CurrentDirector...
Terminate Instance UInt32 {Reason}
GetOwner Instance UInt32 {Domain, User}
GetOwnerSid Instance UInt32 {Sid}
SetPriority Instance UInt32 {Priority}
AttachDebugger Instance UInt32 {}
GetAvailableVirtualSize Instance UInt32 {AvailableVirtualSize}
Calling Instance Method
If a method is implemented on class instances, use Get-CimInstance
to get the WMI instance(s) you need. The example below retrieves the process that is currently running your PowerShell code:
# get the process where property "ProcessID" equals the process id
# of the current PowerShell process (always available in $pid):
$me = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$Pid"
$me
Once you have the instances, use Invoke-CimMethod
to call the method. For example, to find out the process owner, call the method GetOwner():
$me = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$Pid"
Invoke-CimMethod -InputObject $me -MethodName GetOwner
You can combine both calls, too:
# get owner of current powershell process
Invoke-CimMethod -Query "Select * From Win32_Process Where ProcessId=$Pid" -MethodName GetOwner
GetOwner() is a method that does not take any arguments. See the next section for an example on how to call methods with arguments.
Calling Class Methods
Methods implemented by the class are not related to specific instances. For Win32_Process and processes, these methods are not related to existing processes. The method Create() creates a new process.
Before you can call Create(), you need to know more about the arguments it requires. Unlike GetOwner() in the previous example, Create() does require specific information from you so it knows which process to launch.
# figure out the arguments required by the method "Create"
# exposed by the WMI class "Win32_Process":
$className = 'Win32_Process'
$methodName = 'Create'
# list all parameters
$class.CimClassMethods.Item($methodName).Parameters |
# take only input arguments:
Where-Object { $_.Qualifiers.Name -contains 'In' } |
# return name and data type:
Select-Object -Property Name, CimType
The result looks like this:
Name CimType
---- -------
CommandLine String
CurrentDirectory String
ProcessStartupInformation Instance
As you can see, you can submit up to three arguments to the method. Arguments are submitted to the method using a hashtable (so order does not matter). This example launches a new instance of a notepad process:
# add your arguments to a hashtable and use the
# parameter names as keys:
$arguments = @{
CommandLine = 'notepad.exe'
}
# call the method on the WMI class, and submit the arguments:
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments $arguments
Using Data Type “Instance”
When you look at the arguments supported by Create(), the argument ProcessStartupInformation is marked as using the data type Instance: this argument can be an instance of an object of type ProcessStartupInformation.
When you look up this method in our reference, you learn that this object is an instance of the WMI class Win32_ProcessStartup.
The code below creates a new PowerShell process, changes the console title, background and foreground colors, and positions the console window on the desktop:
# using a new instance of Win32_ProcessStartup to create a
# new powershell process and manipulate the console window:
# create a new instance of Win32_ProcessStartup:
# (use -ClientOnly to create a temporary in-memory instance)
$class = Get-CimClass -ClassName Win32_ProcessStartup
$instance = New-CimInstance -CimClass $class -ClientOnly
# fill properties:
$instance.Title = 'My Console Window'
$instance.X = 100
$instance.Y = 200
$instance.FillAttribute = 20
# add your arguments to a hashtable and use the
# parameter names as keys:
$arguments = @{
CommandLine = 'powershell.exe'
ProcessStartupInformation = $instance
}
# call the method on the WMI class, and submit the arguments:
Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments $arguments
Accessing Remote Computers
WMI comes with powerful remoting techniques built-in.
If you are working in a modern Windows environment, and your current user account has sufficient privileges on the target system, you may be able to successfully connect to and run WMI code on a remote machine simply by adding -ComputerName:
# get information from local machine
Get-CimInstance -ClassName Win32_BIOS
# get information from remote machine
Get-CimInstance -ClassName Win32_BIOS -ComputerName server123
Get-CimInstance -ClassName Win32_BIOS -ComputerName 10.12.131.156
If calls fail, these are typical issues:
- Access Denied: your current user account is not authorized to access the remote system. See below on how to use a different user account to log on
- RPC Unavailable: a firewall blocks the call, or the target machine is turned off
- Other: the target machine may not be set up for remoting calls (see below)
Using Different User Accounts
Get-CimInstance
and all the other WMI CIM cmdlets provide no -Credential parameter to use a different user account. Instead, they all work with reusable CIM Sessions.
Whenever the default connection does not work for you, create your own CIM Session, and use this session instead. Here is code that connects to a remote machine using a different user account:
# one or more computer names or IP addresses:
$computers = 'server1', 'server2'
# authenticate with a different identity:
$cred = Get-Credential -Message 'Authenticate to retrieve WMI information:'
# create a CIM session
$session = New-CimSession -ComputerName $computers -Credential $cred
# use the CIM cmdlets with the session you previously created:
$result = Get-CimInstance Win32_Bus -CimSession $session
# when done, remove the CIM session (it can be reused with multiple
# calls until you remove it)
Remove-CimSession -CimSession $session
$result
The user account you specify needs to have Administrator privileges on the target side. Typically, on servers, built-in remoting is enabled by default. On clients, it is disabled by default and can be manually enabled using this command:
Enable-PSRemoting -SkipNetworkProfileCheck -Force
Using WinRM or DCOM Protocol
One of the fundamental differences between the old Get-WmiObject
and the new Get-CimInstance
is the way how machines connect. Get-WmiObject
uses the old-fashioned DCOM protocol (and cannot use anything else). Some old servers may only be able to use DCOM.
Get-CimInstance
uses the much more modern and safer WinRM protocol by default. So if the target machine is relatively old, or if the use of WinRM wasn’t approved in your enterprise and your servers are still connecting over DCOM, then you may experience a situation where Get-WmiObject
works on remote machines whereas Get-CimInstance
fails.
CIM Session uses WinRM by default but can be configured to fall back to DCOM instead. So for troubleshooting, or to access very old servers, use code like this:
$computername = '127.0.0.1'
# use old DCOM protocol:
$options = New-CimSessionOption -Protocol Dcom
# create CIM session
$session = New-CimSession -SessionOption $option -ComputerName $computername
# use session
Get-CimInstance -ClassName Win32_BIOS -CimSession $session
# remove session
Remove-CimSession -CimSession $session
Next Steps
Now that you know how to use the built-in WMI cmdlets and fundamental PowerShell principles, take a look at the hundreds of classes in the default namespace, and adapt the code samples found here to these classes.
Windows Management Instrumentation
Windows Management Instrumentation или WMI – это технология управления, являющаяся частью операционной системы Microsoft® Windows. Впервые она появилась еще в Windows NT® 4.0, и обеспечивала более стабильный и постоянный доступ к настройкам конфигурации как локального, так и удаленных компьютеров.
Долгие годы WMI была одним из самых мощных и доступных инструментов администратора для получения управленческой информации и осуществления тех или иных изменений в конфигурации, особенно на удаленных компьютерах. Однако практическое использование WMI не всегда было простым – более ранние технологии, такие как Microsoft Visual Basic® Scripting Edition (VBScript), требовали программного подхода к использованию WMI, и далеко не все администраторы могли справиться с этой задачей. Windows PowerShell предлагает администраторам самый легкий и доступный во многих отношениях способ работы с WMI.
Важно понимать, что WMI может служить совершенно разным целям для разных групп пользователей. Например, разработчики программного обеспечения взаимодействуют с WMI при создании приложений, таких как Microsoft System Center Configuration Manager. В этом модуле мы будем рассматривать WMI как административный инструмент, и будем говорить только о тех элементах WMI, которые имеют отношение к повседневной работе администратора.
Обзор WMI
WMI – это технология управления, которая внедряется в операционную систему Windows со времен Windows NT 4.0. Каждая новая версия Windows, так же, как и каждая новая версия многих других продуктов Microsoft, обновляет WMI, придавая ей новые черты и наделяя новыми возможностями.
WMI предоставляет информацию в соответствии с моделью Common Information Model или CIM, которая была разработана промышленной группой Distributed Management Task Force или DMTF при участии Microsoft и других поставщиков. Но несмотря на то, что WMI стремится отобразить информацию стандартизированным способом, она почти не устанавливает жестких правил для разработчиков программного обеспечения. В результате WMI зачастую воплощается совершенно по-разному в разных продуктах Microsoft и сторонних продуктах. К сожалению, это делает изучение WMI очень сложным, причем проблема усугубляется тем фактом, что многие варианты реализации WMI нигде не задокументированы. Windows PowerShell может упростить доступ к WMI в случае, если вы будете знать, какой именно элемент WMI вам нужен, но не может полностью решить проблему отсутствия документации или отсутствия жестких стандартов внедрения WMI.
Отчасти сложность WMI объясняется тем фактом, что она отвечает нуждам различных групп пользователей, включая разработчиков ПО, которым часто требуется более детальное и менее качественное отображение управленческой информации. В будущем, вы, возможно, будете замечать, что все больше командлетов Windows PowerShell создается в виде оболочек вокруг технологии WMI. Такие оболочки будут обеспечивать более простые и узкоспециализированные способы работы с WMI, и в то же время скрывать многие из существующих «сложностей». Возможно, что некоторые из командлетов, которыми вы уже пользуетесь, в действительности используют WMI. Но даже полный переход на WMI не представляет собой никакой опасности. Это ценная технология, и, несмотря на некоторые противоречие и прочие недостатки, она дает довольно мощные возможности.
В качестве администратора вы, вероятно, будете сталкиваться с WMI в основном для извлечения информации о Windows, аппаратном обеспечении компьютера и продуктах, запущенных в Windows. В отдельных случаях вам также может потребоваться WMI для произведения изменений в конфигурации.
Взаимодействие WMI
Когда вы используете WMI для установления соединения с удаленным компьютером, вы, по сути, используете подсистему WMI на своем локальном компьютере для поключения к WMI сервису на удаленном компьютере. Взаимодействие двух компьютеров происходит с использованием протокола Remote Procedure Call или RPC. RPC – это старый, проверенный временем протокол, который используется в Windows более десяти лет. Однако по мере того, как локальные брандмауэры получали большее распространение, RPC становился все сложнее в использовании и управлении.
Как правило, первое RPC соединение компьютера происходит с распределителем конечной точки удаленного компьютера. Этот распределитель конечной точки является частью сервиса RPC на удаленном компьютере и занимает собой хорошо известный TCP порт. Вы можете представить, что вы просто открываете порт в локальном брандмауэре, но в действительности на порт не ложится вся нагрузка по осуществлению RPC взаимодействия. Вместо этого распределитель конечной точки выбирает новый произвольный TCP порт для всего оставшегося взаимодействия. Так как порт выбирается произвольно, сложно создать статичные правила брандмауэра, разрешающие RPC трафик.
Windows Firewall поддерживает в качестве исключения сервис Remote Management, который может разрешить RPC, необходимый для WMI. Прочие брандмауэры могут иметь аналогичные возможности – уточнить это можно у их поставщиков. Другие настройки конфигурации, включая User Account Control (UAC) и Distributed Component Object Model (DCOM) могут также задействовать WMI-коммуникации; веб-страницы, расположенные по посещенным ранее URL адресам, выдают информацию при конфигурировании этих настроек.
Структура WMI
Между тем, WMI – это не просто цельная программа. Она включает в себя несколько провайдеров, каждый из которых соединяет WMI-сервис с конкретным продуктом, технологией, функцией и.т.д. WMI провайдер действует почти как драйвер устройства, обеспечивая WMI сервису доступ к различным продуктам Windows. Например, на компьютерах с операционной системой Windows Server, на которых установлен сервис Windows DNS, WMI провайдер позволяет WMI сервису запрашивать и создавать ресурсные записи DNS, а также настройки конфигурации DNS.
Вся информация, которую извлекает WMI-провайдер, регистрируется в WMI-хранилище, централизованной конфигурационной базе данных, которая указывает WMI, что информация доступна на том или ином конкретном компьютере. Важно понимать, что информация, которую вы получаете с помощью WMI, в действительности не находится в хранилище: хранилище содержит лишь перечень доступной информации, и WMI извлекает ее динамически, по запросу. Хранилище состоит из пространств имен, которые приблизительно соответствуют отдельным продуктам и технологиям. Пространства имен расположены иерархически, а значит, они могут включать в себя подпространства.
Пространство имени верхнего уровня является корневым. Другие пространства могут содержать:
• RootCimv2
• RootMicrosoftDNS
• RootMicrosoftActiveDirectory
• RootSecurityCenter
Не все компьютеры Windows содержат одни и те же пространства имен. Например, клиентский компьютер не будет содержать RootMicrosoftActiveDirectory, а серверный компьютер не будет содержать RootSecurityCenter.
Для того, чтобы работать с пространством имен на удаленном компьютере, это пространство не обязательно нужно устанавливать на свой компьютер. Например, если вы используете компьютер под управлением Windows 7 и хотите работать с Windows DNS на удаленном сервере, вы можете сделать это через пространство имен RootMicrosoftDNS, установленное на этом удаленном компьютере, несмотря на то, что на вашем компьютере его нет.
Классы
Внутри каждого пространства имен WMI выделяет один или несколько классов. Класс – это абстрактное значение компонента управления. Например, пространство имен RootCimv2 содержит класс, который называется Win32_TapeDrive. Этот класс определяет свойства ленточного накопителя и существует в пространстве имени независимо от того, подключен данный носитель к компьютеру или нет.
Классы пространства имен The RootCimv2 почти всегда имеют префикс Win32_, даже на 64-битных компьютерах. Этот префикс не используется в названиях классов других пространств имен. В других пространствах имен названия классов вообще редко имеют какой-либо префикс.
К другим классам пространства имен RootCimv2 относятся:
• Win32_Account
• Win32_BIOS
• Win32_Desktop
• Win32_Fan
• Win32_Group
• Win32_Keyboard
• Win32_LogicalDisk
• Win32_NetworkAdapterConfiguration
• Win32_NTDomain
• Win32_Product
• Win32_Service
Как вы видите, пространство имен RootCimv2 содержит классы, имеющие отношение к операционной системе Windows и аппаратному обеспечению компьютера. Это одно из немногих пространств имен, содержащихся на каждом компьютере с Windows, хотя классы внутри этого пространства имен различаются на серверных и клиентских компьютерах, а также на различных версиях Windows ОС. Классы определяют два важных элемента: свойства и методы. Каждый класс имеет как минимум одно свойство, и подобно другим объектам в Windows PowerShell, свойства класса обеспечивают доступ к управленческой и конфигурационной информации. Некоторые классы обладают методами, которые требуют определенных действий, например, перезагрузки компьютера или изменения конфигурации.
Экземпляры
Реальное существование класса называют экземпляром. Например, если на вашем компьютере есть четыре логических диска, то вы имеете четыре экземпляра класса Win32_LogicalDisk. Если на вашем компьютере нет подключенного ленточного накопителя, у него будет нулевой экземпляр класса Win32_TapeDrive, хотя сам класс будет существовать в виде абстрактного значения.
Экземпляры являются такими же объектами, как и любые другие объекты, которые используются в Windows PowerShell. Экземпляры обладают свойствами и методами, которые определены их классом, и вы можете работать с этими свойствами и методами внутри конвейера оболочки.
Во многих случаях экземпляры предназначены только для чтения, что означает, что вы можете извлечь значение свойства, но не можете изменить его. Особенно это касается классов в пространстве имен RootCimv2. Для того, чтобы вы могли изменить настройки конфигурации, класс должен обладать методом, который вы сможете использовать для осуществления изменений. За пределами пространства имен RootCimv2 принцип работы может быть другим. В некоторых случаях вы можете изменить значение свойства путем прикрепления к нему нового свойства. Примером этого может служить пространство имен для Internet Information Services (IIS) 6 внутри WMI. В этом заключается одно из главных противоречий WMI: в разные времена разные группы специалистов, занимающихся разработкой новых продуктов Microsoft, высказывали разные идеи по поводу того, как WMI может использоваться для управления продуктами, технологиями и функциями. Иногда идеи одной группы находили поддержку у специалистов другой группы и были адаптированы ими, что приводило к некоторой стабильности и схожести различных пространств имен; в других случаях эти идеи никогда более не были использованы, и пространства имен, использованные той или иной группой специалистов, оставались уникальными внутри WMI.
Как найти нужный класс.
При существовании десятков тысяч WMI классов найти тот единственный, который помог бы выполнить конкретную задачу, очень сложно. Центральной директории WMI классов не существует, к тому же, существует очень мало способов (конечно, кроме использования поисковых машин) поиска классов по ключевым словам. Для поиска нужного класса следует основываться на трех базовых принципах:
• Опыт. По мере того, как вы будете приобретать опыт в использовании WMI, вы научитесь угадывать имена классов, после чего с помощью специальных инструментов или поисковых машин вы сможете подтвердить свои догадки. Также может помочь обращение к более опытным администраторам за помощью. Такую возможность предоставляют некоторые онлайн-сообщества, например:
• The “Windows PowerShell” Internet newsgroup (доступна по адресу: http://go.microsoft.com/fwlink/?LinkId=193516)
• www.PoshComm.org
• www.PowerShell.com
• www.ScriptingAnswers.com
• www.ConcentratedTech.com
• Исследования. Различные «исследовательские» и «поисковые» инструменты WMI позволяют просматривать WMI хранилища как на локальном, так и на удаленных компьютерах. В хранилищах классы обычно располагаются в алфавитном порядке, что упрощает поиск класса по названию и просмотр доступных классов.
• Примеры. Используя поисковые интернет-машины для поиска по ключевым словам (например, “WMI BIOS” или “WMI disk space), зачастую можно обнаружить примеры, написанные другими людьми. Эти примеры, даже если они и не являются в точности тем, что вам нужно, могут помочь вам найти классы, имеющие отношение к выполняемой вами задаче. Хорошей стартовой точкой для поиска примеров, имеющих отношение ко многим видам административной работы, является Microsoft TechNet Script Center Repository (http://go.microsoft.com/fwlink/?LinkId=193517).
Обратите внимание, что даже примеры, имеющие отношение к другим технологиям, таким как VBScript, JScript или Perl, могут быть полезными для поиска названий WMI классов. Не исключайте такие варианты примеров лишь потому, что они не относятся исключительно к Windows PowerShell.
Помимо этого, вы можете дать Windows PowerShell команду отобразить список классов:
Get-WmiObject -list
Эта команда отображает список классов пространства имен, используемого по умолчанию. Чтобы отобразить классы из другого пространства имен, следует добавить параметр – namespace и уточнить имя пространства имен, например, RootSecurityCenter. Также оболочка может помочь найти классы, название которых содержит определенную строку символов:
Get-WmiObject -list -class *user*
Поскольку параметр –class является позиционным, вы можете даже опустить имя параметра –class:
Get-WmiObject -list *user*
WMI развивалась годами, и продолжает развиваться. Это означает, что конкретный WMI класс может вести себя слегка по-разному в разных версиях Windows, могут иметь меньше свойств или полностью отсутствовать в старых версиях Windows. Обязательно учитывайте это, особенно при работе с удаленными компьютерами. Пространства имен на разных компьютерах могут очень сильно различаться, не считая пространства имен RootCimv2. Клиентский и серверный компьютер обычно имеют разные наборы пространств имен; пространства имен часто бывают доступными только когда соответствующий продукт или технология установлены на компьютер.
Документация
Было бы замечательно, если бы для каждого пространства имен и WMI класса существовало бы централизованное хранилище. К сожалению, это не так.
Главные классы операционной системы, такие как классы в пространстве имен RootCimv2, последовательно задокументированы; эта документация хранится в Интернете как часть библиотеки Microsoft Developer Network (MSDN®). Поскольку библиотека периодически подвергается реорганизации, меняя URL адреса, самый простой способ найти документацию для класса – воспользоваться поисковыми системами. Например, если вы введете в строку поиска Win32_Service, вы обнаружите, что первые результаты выдачи будут вести именно в Библиотеку, а уже оттуда вы можете начать поиск других классов в пространстве имен, используя таблицу дерева контента.
Вне пространства имен RootCimv2 документация намного менее стабильна и согласованна, как по форме, так и в плане доступности. У многих групп разработчиков просто не было времени, чтобы подготовить необходимую документацию. В других случаях группы разработчиков могли создать WMI классы для собственного использования, но не думали о том, что эти классы станет использовать кто-то еще, поэтому, документация так и не была опубликована для широкого доступа.
Если документация доступна – а это чаще всего бывает с классами пространства имен RootCimv2 – обращайте пристальное внимание на детали, указывающие, с какими продуктами ли с какой версией Windows данный класс работает. Однако не забывайте, что классы могут различаться в зависимости от версии Windows. Несмотря на то, что класс Win32_Processor присутствует, например, на Windows NT 4.0, он ведет себя совсем не так, как на Windows Server 2008 R2 (хотя в данном случае в документации объясняется разница).
Безопасность WMI
WMI содержит мощную систему безопасности. Защита может устанавливаться как для целого пространства имен, так и для отдельного атрибута класса. По умолчанию большая часть защитной информации конфигурируется в пространстве имен Root, тогда как прочие пространства имен и их классы перенимают это корневое разрешение.
Также по умолчанию защита WMI конфигурируется таким образом, чтобы локальные пользователи могли запрашивать почти любую информацию из WMI. Члены локальной административной группы (которая в доменной среде обычно включает доменные админские группы доменного уровня), могут запрашивать информацию удаленно. Не стоит менять настройки конфигурации системы безопасности WMI до тех пор, пока вы не будете осознавать на 100%, что вы делаете, и каковы возможные последствия. Модификация системы безопасности может привести к полной остановке WMI или негативно повлиять на продукты, основанные на WMI, такие как System Center Configuration Manager. Настройки безопасности, заданные по умолчанию, подходят для большинства ситуаций, и чаще всего самым мудрым решением будет не трогать их совсем.
Настройки безопасности WMI можно просмотреть и модифицировать с помощью оснастки WMI Control в консоли Microsoft Management Console (MMC). По умолчанию консоль не содержит эту оснастку; вам необходимо открыть новое MMC-окно или существующую консоль и добавить оснастку вручную.
Обратите внимание, что WMI чувствительна к User Account Control (UAC) на тех версиях Windows, которые поддерживают эту технологию защиты. Если вы планируете запросить WMI информацию с удаленного компьютера, вы должны обладать действующим администраторским токеном. Обычно это означает, что вы должны либо работать в Windows PowerShell как «Администратор» (чтобы иметь необходимую привилегию), либо обеспечить альтернативный мандат после установления WMI соединения.
Просмотр WMI из PowerShell
Windows PowerShell также может помочь вам изучить все классы в заданном пространстве имен, так как она может выдать список всех классов, присутствующих в пространстве имен. Чтобы получить список всех классов, содержащихся в пространстве имен, используемом по умолчанию, запустите команду:
Get-WmiObject –namespace rootcimv2 –list
Вы можете заменить название пространства имен RootCimv2 другим названием пространства имен для того, чтобы увидеть классы, содержащиеся в нем. А если добавить параметр –computerName, можно увидеть классы пространства имен на удаленном компьютере:
Get-WmiObject –namespace rootcimv2 –list –computername LON-DC1
Обычно командлет Get-WmiObject использует мандат того пользовательского аккаунта, через который вы открыли окно Windows PowerShell. Это единственный аккаунт, который может запрашивать WMI информацию локально. WMI сама по себе не позволит использование альтернативного мандата для локального соединения. Однако для удаленного соединения вы можете добавить параметр –credential, чтобы указать альтернативный аккаунт. Имя пользователя должно быть в формате DOMAINUSERNAME:
Get-WmiObject –namespace rootcimv2 –list –computername LON-DC1 –credential CONTOSOAdministrator
Наконец, чтобы увидеть список всех пространств имен, запустите в Windows PowerShell следующую команду:
get-wmiobject -namespace root -class «__namespace» | ft name
Использование WMI
Windows PowerShell делает доступной большую часть WMI информации с помощью двух простых командлетов, тем самым предоставляя вам легкий способ извлечения WMI информации с локального и удаленного компьютера, а также способ задействовать WMI методы.
Помните, что Windows PowerShell отображает всю WMI информацию в форме объектов, так же, как она поступает с любой другой информацией. Это означает, что командлеты, используемые для сортировки, фильтрации, группировки, экспорта, сравнения, и.т.д. могут использоваться в сочетании с WMI в рамках оболочки.
Опрос WMI
Командлет Get-WmiObject отвечает за извлечение информации либо с локального компьютера, либо с одного или нескольких удаленных компьютеров. Параметр –class уточняет имя класса, которое вы хотите извлечь; по умолчанию извлекаются все экземпляры этого класса. Если класс находится вне пространства имен RootCimv2, используйте параметр –namespace для уточнения имени пространства имен, в котором можно найти класс. Также используйте параметр –computername, чтобы уточнить имя удаленного компьютера и параметр –credential, чтобы уточнить альтернативный мандат для удаленного подключения. За один раз можно запросить только один класс.
Командлет извлекает указанные экземпляры и помещает их в конвейер, например:
Get-WmiObject Win32_Service
Обратите внимание, что некоторые классы WMI перехлестываются с другими командлетами Windows PowerShell, например, Get-Service. Однако вы, возможно, уже заметили различия в их работе и способе отображения информации. Например, Get-Service использует Microsoft .NET Framework для извлечения информации о сервисах; эта информация не включает некоторые детали, такие как режим запуска сервиса или его учетная запись, поскольку такая информация не включена в Framework. Класс WMI Win32_Service, в свою очередь, включает информацию о режиме запуска и учетной записи сервиса. Вы можете увидеть эти свойства, передав экземпляр свойства по конвейеру командлету Get-Member:
Get-WmiObject Win32_Service | Get-Member
Также вы можете увидеть все свойства всех экземпляров класса, используя Format-List:
Get-WmiObject Win32_Service | Format-List *
Встроенный псевдоним командлета Get-WmiObject — gwmi.
В разделе справочника, посвященном командлету Get-WmiObject, обратите внимание на параметр –computerName. В справочнике по синтаксису он указывается в следующем виде:
[-ComputerName <string[]>]
Значение <string[]> указывает на то, что параметр может принимать несколько имен компьютеров. Одним из способов указать эти имена является их перечисление через запятую, поскольку Windows PowerShell автоматически интерпретирует такой список как набор объектов:
-computerName «LON-DC1″,»SEA-DC2»
Однако к параметру –computerName можно прикрепить все, что обозначает набор объектов. Например, вы можете создать текстовый файл, в котором в каждой строчке указано одно имя компьютера:
LON-DC1
SEA-DC2
NYC-SRV7
Для чтения этого файла вы можете использовать командлет Get-Content. Командлет обрабатывает каждую строчку текстового файла как объект строки – именно это необходимо параметру –computerName:
-computerName (Get-Content c:names.txt)
Скобки указывают оболочке на то, что команду Get-Content необходимо выполнить в первую очередь. Результаты этого командлета передаются параметру –computerName.
При соединении с несколькими удаленными компьютерами командлет Get-WmiObject все же может работать с альтернативным мандатом, на который указывает параметр –credential. Однако для всех компьютеров должен использоваться один и тот же мандат. Множественные соединения производятся последовательно, а не параллельно, поэтому, может потребоваться некоторое время для извлечения списка имен. Если командлен по каким-то причинам не может получить доступ к компьютеру (компьютер находится в режиме оффлайн, доступ заблокирован или не получено разрешение), то ситуация воспринимается как бесконечная ошибка, в результате чего командлет выдает сообщение об ошибке и продолжает работу, пытаясь подключиться к следующему в списке компьютеру.
Объекты, возвращаемые командлетом Get-WmiObject, всегда обладают свойством __SERVER, которое содержит имя компьютера, из которого поступил данный объект. Это свойство может быть полезным, когда вы отправляете запрос нескольким компьютерам, так как позволяет отсортировать и сгруппировать объекты по имени компьютера:
Get-WmiObject Win32_Service –computer (Get-Content c:names.txt) | Sort __SERVER | Format-Table –groupBy __SERVER
Командлет Get-WmiObject всегда использует Remote Procedure Calls (RPCs) для подключения к удаленным компьютерам; «родные» способности удаленной работы Windows PowerShell не задействуются. По этой причине Get-WmiObject может подключиться к любому удаленному компьютеру, на котором запущен сервис WMI, даже если на нем не установлена Windows PowerShell.
Еще одним способом запросить данные с нескольких компьютеров является использование командлета ForEach-Object. Помните, что командлет Get- Content читает текстовый файл и возвращает каждую строчку в виде объекта. ForEach-Object дает возможность перечислить все эти объекты. Если бы каждая строчка текста содержала имена компьютеров, вы бы перечисляли имена компьютеров. Преимущество этой техники состоит в том, что командлет ForEach-Object может выполнять множественные команды по отношению к каждому компьютеру:
Gc c:names.txt | ForEach-Object {
gwmi win32_computersystem;
gwmi win32_operatingsystem } |
select buildnumber,servicepackmajorversion,totalphysicalmemory
Скриптовый блок ForEach-Object содержит два WMI запроса, каждый из которых возвращает разные объекты. Объекты обоих типов отправляются по конвейеру командлету Select-Object. Select-Object затем выбирает три указанные свойства. Выходные данные будут выглядеть примерно так:
buildnumber servicepackmajorversion totalphysicalmemory
———— ———————— ——————-
3220758528
7600 0
Если вы посмотрите внимательно, то заметите, что выходные данные расположены не в одну строчку. Первый объект в конвейере – это Win32_ComputerSystem, который не имеет свойства BuildNumber или ServicePackMajorversion – поэтому, данные колонки в первой строчке будут пустыми. Второй объект в конвейере не имеет свойства TotalPhysicalMemory, поэтому, эта колонка во второй строчке является пустой. Другими словами, вы увидите пример, в котором эти отдельные куски информации объединяются в один поток выходных данных.
Вы уже знаете, как использовать командлет Select-Object и добавлять новые свойства объекту. Часть значения свойства под названием Expression может содержать почти любой код Windows PowerShell, в том числе и абсолютно новый командлет. Например, следующая команда позволит извлечь сведения о логических дисках компьютера и отобразить информацию об имеющемся на них свободном месте в гигабайтах:
gwmi win32_logicaldisk |
select deviceid,drivetype,
@{Label=’freespace(gb)’;Expression={$_.freespace/1GB}}
Чуть более усовершенствованный вариант этой техники может задействовать параметр –as, чтобы привести полученные данные об имеющемся свободном месте к целому числу. Поскольку целое число не имеет дробей, результат округляется в сторону ближайшего целого числа, а десятичные значения игнорируются:
gwmi win32_logicaldisk |
select deviceid,drivetype,
@{Label=’freespace(gb)’;Expression={$_.freespace/1GB –as [int]}}
Другой вариант этой техники позволяет объединять информацию из двух или более WMI классов в единую строку выходных данных. Предположим, вы хотите извлечь информацию о версии Windows и объеме физической памяти компьютера. Вы можете начать с запроса информации о классе Win32_OperatingSystem:
Gwmi win32_operatingsystem | select caption
Затем вы можете добавить новое пользовательское свойство в выходные данные, и значением этого свойства будет абсолютно новый WMI запрос к классу
Win32_ComputerSystem:
Gwmi win32_operatingsystem |
select caption,
@{Label=’PhysMemory’;
Expression={(gwmi win32_computersystem).totalphysicalmemory}}
Что мы здесь видим? Часть команды Expression выполняет новый WMI запрос. Обратите внимание, что запрос помещен в круглые скобки. Благодаря этому, результаты запроса воспринимаются как объект, что особенно важно по той причине, что этот запрос возвращает только один WMI объект (в конце концов, на любом компьютере установлена только одна операционная система). Точка после закрывающей скобки говорит о том, что вы хотите получить доступ к составной части WMI объекта, возвращенного в результате выполнения запроса, в частности, к свойству TotalPhysicalMemory. Значение этого свойства становится значением нашего пользовательского свойства PhysMemory. Попробуйте запустить вышеуказанную команду и посмотрите результат.
Что если вы пытались бы связаться с удаленным компьютером? Один из способов сделать это – просто уточнить имя компьютера для обоих WMI запросов.
Gwmi win32_operatingsystem –comp Server1 |
select caption,
@{Label=’PhysMemory’;
Expression={
(gwmi win32_computersystem –comp Server1).totalphysicalmemory}
}
Но есть способ лучше – уточнить имя компьютера только для начального WMI соединения. После того как WMI объект станет доступным, вы можете использовать специальное свойство __SERVER, чтобы получить доступ к имени компьютера. Это означает, что вам придется изменить имя компьютера только в одном месте, для того чтобы отправить запрос другому компьютеру:
Gwmi win32_operatingsystem –comp Server1 |
select caption,
@{Label=’PhysMemory’;
Expression={
(gwmi win32_computersystem –comp $_.__SERVER).totalphysicalmemory}
}
В данном примере заполнитель $_ , расположенный в скриптовом блоке Expression, содержит WMI_объект, который был передан по конвейеру командлету Select-Object. Вслед за ним идет точка, которая указывает, что мы хотим получить доступ к части объекта, содержащегося в данном заполнителе. Мы получаем доступ к параметру __SERVER, который содержит информацию об имени компьютера, из которого пришел WMI-объект. Это имя компьютера станет значением параметра –computerName в нашем следующем WMI запросе.
Отбор данных
В некоторых случаях вам, возможно, не понадобятся все экземпляры классов. Например, вы хотите запросить информацию только об одном сервисе, BITS. Одним из способов добиться этого станет использование командлета Where-Object:
Gwmi Win32_Service | Where { $_.Name –eq ‘BITS’ }
Однако эта техника имеет один недостаток – в данном случае оболочка отправляет запрос в каждый экземпляр класса, возвращает результаты и проверяет каждый из них, чтобы определить, какой из них соответствует вашим критериям. Когда вы извлекаете данные о большом количестве объектов, особенно с удаленных компьютеров, этот процесс может занять очень много времени и привести к большой нагрузке на процессор.
Командлет Get-WmiObject предлагает параметр –filter, который отправляет ваш критерий WMI-сервису. WMI-сервис может отфильтровать информацию намного быстрее и вернуть только те результаты, которые соответствуют вашим критериям. К сожалению, WMI-сервис не принимает символы сравнения Windows PowerShell, поэтому, вам придется вспомнить несколько другой синтаксис для указания критериев:
Gwmi Win32_Service –filter «Name = ‘BITS'»
Пару слов об этом синтаксисе:
• Строки могут быть заключены в одинарные кавычки. Поэтому, весь критерий обычно заключен в двойные кавычки, как показано выше.
• К знакам сравнения относятся:
= (equality)
<> (inequality)
>= (greater than or equal to)
<= (less than or equal to)
> (greater than)
< (less than)
• LIKE (разрешает групповые символы)
• Не используйте заполнитель $_, поскольку он работает только в Windows PowerShell, но не в WMI. Для указания критерия WMI указывайте имя свойства.
• Можно использовать ключевые слова AND и OR, чтобы указать несколько критериев.
Символ LIKE является особенно гибким. Применяя его, вы можете:
• Использовать % в качестве группового символа. “Name LIKE ‘%windows%’”
• Использовать _ в качестве 1-символьного группового знака.
• Использовать [ и ], чтобы обозначить ряд или набор символов: “DriveType LIKE ‘[abcdef]’”
WMI, как и Windows PowerShell, обычно нечувствительна к регистру. Ключевые слова, такие как LIKE могут быть напечатаны и строчными буквами – like; символы в командной строке, например, названия сервисов, также нечувствительны к регистру. Некоторые WMI-провайдеры чувствительны к регистру, но это, скорее, исключения.
И, наконец, лучший способ произвести фильтрацию – это расположить критерии фильтрации как можно ближе к левому краю командной строки Windows PowerShell. Когда вы можете произвести фильтрацию путем использования параметра –filter командлета, предпочтительнее использовать Where-Object для выполнения этой задачи.
WQL-синтаксис
Иногда вы можете столкнуться с языком написания запросов WMI Query Language (WQL), например, в рамках более старых технологий, таких как VBScript, где WQL был приоритетным способом составления запросов по извлечению данных. Windows PowerShell позволяет использовать такие запросы. Для этого нужно просто прикрепить строку запроса к параметру –query командлета Get-WmiObject:
Gwmi –query «SELECT * FROM Win32_Process»
Параметр –query может быть использован в сочетании с –namespace, –credential, –computername и многими другими параметрами, но не с – class, так как строка запроса должна уточнять, к какому классу обращен запрос.
В разделе справочника, посвященному Get-WmiObject, можно найти более подробную информацию об этих параметрах.
Использование параметра –query не имеет конкретных достоинств или недостатков по сравнению с другими формами командлета Get-WmiObject.
Системные свойства
Если вы попробуете передать WMI-объект по конвейеру командлету Format-List *, вы заметите несколько свойств, имена которых начинаются с двойного нижнего подчеркивания, например, __SERVER и __PATH:
Get-WmiObject Win32_Process | Format-List *
Эти системные свойства относятся непосредственно к WMI и могут содержать весьма ценную информацию. Например, вы уже видели, что свойство __SERVER содержит информацию об имени компьютера, с которого «пришел» WMI-объект. Это работает даже в том случае, если вы указали локальный хост или IP адрес для WMI-соединения:
Gwmi Win32_BIOS –computer localhost | Format-List *
__SERVER всегда содержит настоящее имя компьютера. Свойство __PATH также может быть полезным: оно содержит указатель, который может использоваться для уникальной ссылки на WMI-объект. Вы даже можете использовать его для повторного извлечения этого WMI_объекта.
WMI и ForEach-Object
Зачастую приходится извлекать несколько WMI-объектов, после чего работать с каждым из них индивидуально. Так как WMI не является частью Windows PowerShell, оболочка содержит ограниченное количество командлетов для работы с WMI-объектами. В большинстве случаев основные командлеты оболочки могут манипулировать WMI-объектами так, как это требуется для выполнения ваших задач. Но иногда, однако, вы будете вынуждены отправлять WMI_объекты командлету ForEach-Object, чтобы выполнить определенные действия над каждым из них по очереди:
Gwmi Win32_Process | ForEach-Object { $_ }
В данном примере каждый WMI-объект отправляется в конвейер, что означает, что ForEach-Object в действительности не выполняет никакой важной функции. Однако в этот скриптовый блок вы можете поместить практически любую команду Windows PowerShell или даже несколько задач.
- Что такое WMI
- Классы, события и безопасность WMI
- Средства работы с WMI
- Язык запросов WMI
- Использование WMI в сценариях
- Подключение к WMI
- Подключение методом локатора
- Подключение методом моникера
- Использование объекта репозитория
- Асинхронное использование объектов репозитория
- Работа с объектами и коллекциями объектов, полученных в результате запросов
- Примеры сценариев на VBScript
- Использование WMI в программах
- Пример программы на VB.NET
- Использование специальных средств для написания запросов
- Scriptomatic
- WMI Code Creator
- Заключение
Windows Management Instrumentation (WMI) в дословном переводе — это инструментарий управления Windows. Если говорить более развернуто, то WMI — это одна из базовых технологий для централизованного управления и слежения за работой различных частей компьютерной инфраструктуры под управлением платформы Windows. Технология WMI — это расширенная и адаптированная под Windows реализация стандарта WBEM, принятого многими компаниями, в основе которого лежит идея создания универсального интерфейса мониторинга и управления различными системами и компонентами распределенной информационной среды предприятия с использованием объектно-ориентированных идеологий и протоколов HTML и XML.
В основе структуры данных в WBEM лежит Common Information Model (CIM), реализующая объектно-ориентированный подход к представлению компонентов системы. CIM является расширяемой моделью, что позволяет программам, системам и драйверам добавлять в нее свои классы, объекты, методы и свойства.
WMI, основанный на CIM, также является открытой унифицированной системой интерфейсов доступа к любым параметрам операционной системы, устройствам и приложениям, которые функционируют в ней.
Важной особенностью WMI является то, что хранящиеся в нем объекты соответствуют динамическим ресурсам, то есть параметры этих ресурсов постоянно меняются, поэтому параметры таких объектов не хранятся постоянно, а создаются по запросу потребителя данных. Хранилище свойств объектов WMI называется репозиторием и расположено в системной папке операционной системы Windows:
%SystemRoot%System32WBEMRepositoryFS
Так как WMI построен по объектно-ориентированному принципу, то все данные операционной системы представлены в виде объектов и их свойств и методов.
Все классы группируются в пространства имен, которые иерархически упорядочены и логически связаны друг с другом по определенной технологии или области управления. В WMI имеется одно корневое пространство имен Root, которое в свою очередь имеет 4 подпространства: CIMv2, Default, Secutiry и WMI.
Классы имеют свойства и методы и находятся в иерархической зависимости друг от друга, то есть классы-потомки могут наследовать или переопределять свойства классов-родителей, а также добавлять свои свойства.
Свойства классов используются для однозначной идентификации экземпляра класса и для описания состояния используемого ресурса. Обычно все свойства классов доступны только для чтения, хотя некоторые из них можно модифицировать определенным методом. Методы классов позволяют выполнить действия над управляемым ресурсом.
Каждому экземпляру класса можно обратиться по полному пути, который имеет следующую структуру:
[\ComputerNameNameSpace][:ClassName][.KeyProperty1=Value1][,KeyProperty2=Value2]…] где ComputerName - имя компьютера NameSpace - название пространства имен ClassName - имя класса KeyProperty1=Value1, KeyProperty2=Value2 - свойства объекта и значения, по которым он идентифицируется.
Пример обращения к процессу с именем «Calc.exe», который запущен на локальной машине:
\.CIMv2:Win32_Process.Name="Calc.exe"
Экземпляры классов могут генерировать события, к которым можно подписываться. При наступлении события WMI автоматически создает экземпляр того класса, которому соответствует это событие. Такой механизм удобно использовать для выполнения определенной команды при наступлении определенного события, то есть следить за состоянием объектов операционной системы.
Общая безопасность в WMI реализуется на уровне операционной системы, а дополнительная политика безопасности основана на уровнях пространств имен и протокола DCOM. То есть если пользователь не имеет права делать какое-то действие через операционную систему, он не сможет это сделать и через WMI. Если же пользователю дано какое-то право в операционной системе, то это еще не означает, что это право будет и в WMI, так как в WMI действуют дополнительные параметры безопасности на уровне пространств имен.
Каждый объект операционной системы имеет свое описание безопасности (SD) со своим списком доступа (ACL), в котором перечислены идентификаторы пользователей (SID) и их привилегии. Каждое пространство имен может иметь собственное SD со своим ACL, где пользователям могут быть назначены разрешения на чтение данных, выполнение методов, запись классов и данных и другие. Данные о дополнительных разрешениях хранятся в репозитории WMI. Отдельные классы из пространств имен не имеют собственных описаний безопасности, они наследуют их от своего пространства имен.
По умолчанию администратор компьютера имеет полные права на использование WMI, а остальные пользователи могут лишь вызывать методы, считывать данные и записывать в репозиторий экземпляры классов провайдеров WMI.
Для доступа к инфраструктуре WMI используется протокол DCOM, через который пользователь подключается к WMI. Чтобы определить, какие права будут у подключившегося пользователя, используется механизмы олицетворения и аутентификации протокола DCOM.
Уровни олицетворения могут принимать следующие значения:
Anonymous | Анонимный | WMI-объект не может получить информацию о пользователе — доступ по такому типу не предоставляется |
Identify | Идентификация | WMI-объект запрашивает маркер доступа пользователя — доступ предоставляется только локально |
Impersonate | Олицетворение | WMI-объект имеет такие же права, какие имеет пользователь — рекомендуемый уровень для выполнения команд на удаленном компьютере |
Delegate | Делегирование | WMI-объект может обратиться от имени пользователя к другому WMI-объекту — нерекомендуемый уровень, так как команды можно выполнять удаленно через цепочку из нескольких компьютеров |
Уровни аутентификации (подлинности) могут принимать следующие значения:
None | Отсутствует | Проверка подлинности отсутствует |
Default | По умолчанию | Стандартные настройки безопасности, которые задаются компьютером-целью команды |
Connect | Подключение | Проверка только во время подключения к компьютеру-цели команды, проверка в ходе работы отсутствует |
Call | Вызов | Проверка подлинности при каждом запросе к компьютеру-цели команды, заголовки пакетов подписываются, но содержимое не шифруется |
Pkt | Пакет | Проверка подлинности всех пакетов к компьютеру-цели команды, заголовки пакетов подписываются, но содержимое не шифруется |
PktIntegrity | Целостность пакета | Проверка подлинности и целостности всех пакетов к компьютеру-цели команды, заголовки пакетов подписываются, но содержимое не шифруется |
PktPrivacy | Секретность пакета | Проверка подлинности и целостности всех пакетов к компьютеру-цели команды, заголовки и содержимое пакетов подписываются и шифруются |
wmimgmt.msc — оснастка консоли управления MMC для настройки WMI на локальном компьютере.
Оснастка консоли управления MMC для настройки WMI
winmgmt.exe — консольная утилита управления WMI локального компьютера.
Консольная утилита управления WMI
wbemtest.exe — графическая утилита для взаимодействия со структурой WMI на локальном или удаленном компьютере.
Графическая утилита для взаимодействия со структурой WMI
wmic.exe — консольная утилита для взаимодействия со структурой WMI на локальном компьютере.
Консольная утилита для взаимодействия со структурой WMI
mofcomp.exe — компилятор MOF-файлов для расширения структуры WMI, управления библиотекой классов WMI и восстановления репозитория.
Компилятор MOF-файлов для расширения структуры WMI
Для обращения к объектам WMI используется специфический язык запросов WMI Query Language (WQL), который является одним из разновидностей SQL. Основное его отличие от ANSI SQL — это невозможность изменения данных, то есть с помощью WQL возможна лишь выборка данных с помощью команды SELECT. Помимо ограничений на работу с объектами, WQL не поддерживает такие операторы как DISTINCT, JOIN, ORDER, GROUP, математические функции. Конструкции IS и NOT IS применяются только в сочетании с константой NULL.
Запросы WQL обычно применяются в скриптах, но их также можно протестировать в программе Wbemtest и в консольной утилите Wmic (утилита wmic не требует написания ключевого слова SELECT и полей выборки)
Общий синтаксис запроса WQL выглядит так:
SELECT свойства FROM имя_класса WHERE свойство оператор значение
Например:
' Выбрать все значения класса Win32_Product и вывести все его свойства SELECT * FROM Win32_Product ' Выбрать все значения класса Win32_Product и вывести свойство Version SELECT Version FROM Win32_Product ' Выбрать значения класса Win32_Product, где свойство Description равно ' "Microsoft Office", и вывести свойство Version SELECT Version FROM Win32_Product WHERE Description = "Microsoft Office"
Как видно из примеров, оператор FROM — это источник (класс), коллекцию экземпляров которого нужно получить, а оператор WHERE — это фильтр в запросе.
В скриптах для подключения к WMI используются два метода: с использованием локатора (SWbemLocator) и с использованием моникера (WinMgmts). Метод локатора позволяет установить соединие с пространством имен от имени определенной учетной записи. Метод моникера разрешает подключаться к WMI только от имени текущей учетной записи.
Использование этого метода необходимо, когда в сценарии нужно явно задать имя и пароль учетной записи для подключения к WMI. Объект SWbemLocator создается так:
Set mSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Подключение к репозиторию WMI производится с помощью метода ConnectServer:
mSWbemServices = mSWbemLocator.ConnectServer([ServerName], [NameSpace], [User], _ [Password], [Locate], [Authority], [SecurityFlags], [WbemNamedValueSet]) где ServerName - имя компьютера (если не указано, то локальный компьютер), NameSpace - пространство имен (если не указано, то пространство по умолчанию), User - имя пользователя в формате ДоменУчетнаяЗапись (если не указано, то текущий пользователь), Password - пароль указанного пользователя, Locate - код локализации (если не указано, то текущий язык), Authority - имя домена, если он не указан в параметре User (если не указано, то текущий домен), SecurityFlags - время ожидания подключения, WbemNamedValueSet - контекстная информация для провайдера, который используется для запроса.
Безопасность объекта указывается с помощью свойства Security_, в котором указывается уровень олицетворения и привилегии.
Пример использования локатора:
' Создание объекта Set mSWbemLocator = CreateObject("WbemScripting.SWbemLocator") ' Задание уровня аутентификации (6 - секретность пакетов) mSWbemLocator.Security_.AuthenticationLevel = 6 ' Задание уровня олицетворения (3 - олицетворение) mSWbemLocator.Security_.ImpersonationLevel = 3 ' Добавление привелегии (разрешение завершать работу) mSWbemLocator.Security_.Privileges.AddAsString("SeShutdownPrivilege") ' Подключение к репозиторию Set mSWbemServices = mSWbemLocator.ConnectServer(".", "RootCIMv2",,,,, 128)
Моникер — это строка, задающая путь к классу WMI, экземпляр которого должен быть создан. Моникер состоит из обязательного префикса «winmgmts:», необязательных настроек безопасности, необязательного пути к требуемому классу:
Set mSWbemServices = GetObject("winmgmts:[{SecurityOptions}!]\[Server][NameSpace]")
Пример использования моникера:
' Подключение к пространству имен по умолчанию локального компьютера Set mSWbemServices0 = GetObject("winmgmts:") ' Подключение к указанному пространству имен удаленного компьютера ' с указанием метода олицетворения Set mSWbemServices1 = GetObject("winmgmts:{impersonationLevel=Impersonate}!" & _ "\MyComputerRootCIMv2") ' Подключение к указанному объекту локального компьютера ' с указанием метода олицетворения и привилегий Set mSWbemServices2 = GetObject("winmgmts:" & _ "{impersonationLevel=Impersonate, (Shutdown, RemoteShutdown)}!" & _ "\.RootCIMv2:Win32Process.Handle=4") ' Подключение к указанному объекту локального компьютера Set mSWbemServices3 = GetObject("winmgmts:\.RootCIMv2:Win32Process.Handle=4")
В результате подключения к WMI получается объект SWbemServices, который обладает определенными свойствами и методами. Наиболее часто используемые из них — это Get, ExecQuery, ExecMethod.
Метод Get используется для возвращения определения класса или экземпляра управляемого ресурса:
Set mObject = Get([ObjectPath],[Flags],[WbemNamedValueSet]) где ObjectPath - путь к объекту WMI, Flags - опции, WbemNamedValueSet - контекстная информация для провайдера.
Пример использования метода Get:
' Подключение к пространству имен Set mSWbemServices = GetObject("winmgmts:\.RootCIMv2") ' Получение экземпляра класса с заданным свойством Set mProcess = mSWbemServices.Get("Win32_Process.Handle=4")
Метод ExecQuery используется для выполнения запросов на языке WQL:
Set mObject = ExecQuery(Query,[QueryLanguage],[Flags],[WbemNamedValueSet]) где Query - текст запроса, QueryLanguage - язык запроса (всегда равен "WQL") Flags - опции, WbemNamedValueSet - контекстная информация для провайдера.
Пример использования метода ExecQuery:
' Подключение к пространству имен Set mSWbemServices = GetObject("winmgmts:\.RootCIMv2") ' Получение всех экземпляров класса с заданным свойством Set mProcesses = mSWbemServices.ExecQuery("SELECT * FROM Win32_Process WHERE Handle = 4")
Метод ExecMethod используется для выполнения метода указанного объекта:
Set mObject = ExecMethod(ObjectPath, MethodName,[InParams],[Flags],[WbemNamedValueSet]) где ObjectPath - путь к объекту WMI, MethodName - имя метода, InParams - входные параметры для метода, Flags - опции (всегда равно нулю), WbemNamedValueSet - контекстная информация для провайдера.
Пример использования метода ExecMethod:
' Подключение к пространству имен Set mSWbemServices = GetObject("winmgmts:\.RootCIMv2") ' Получение указателя на класс Set mProcess = mSWbemServices.Get("Win32_Process") ' Создание коллекции входных параметров для метода Set mInParams = mProcess.Methods_("Create").InParameters.SpawnInstance_ mInParams.CommandLine = "notepad.exe" ' Выполнение метода Set mOutParams = mSWbemServices.ExexMethod("Win32_Process", "Create", mInParams)
Указанные выше методы работают в синхронном и полусинхронном режиме, то есть программа или сценарий не выполняет следующую команду или запрос до тех пор, пока не получит ответ от текущего запущенного метода.
Аналогично синхронным методам WMI позволяет выполнять команды асинхронно, то есть не дожидаться результатов выполнения очередного запроса и продолжать работу сценария или программы. Названия таких асинхронных методов имеют окончание «Async», а работа с ними почти не отличается от обычных методов, но должны быть использованы два обязательных параметра: ссылка на специальный объект «слив событий» и контекстная информация объекта.
Объект «слива событий» (от английского «sink» — раковина) создается следующим образом:
Set mSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_") где Sink_ - префикс для функций.
Наиболее часто используемые события, обрабатываемые таким «сливом» асинхронных методов, — это OnObjectReady и OnCompleted. Как можно догадаться из названий событий, первое происходит, когда возвращается очередной объект, порожденный асинхронным запросом. Второе происходит после полного завершения асихронного метода. Событие OnObjectReady выдает на выход объект, который был запрошен асихронной операцией, а событие OnCompleted — код ошибки или 0.
Пример использования асинхронного метода:
' Подключение к пространству имен Set mSWbemServices = GetObject("winmgmts:\.RootCIMv2") ' Создание объекта "слива событий" Set mSink = WScript.CreateObject("WbemScripting.SWbemSink", "Sink_") ' Флаг завершения асинхронного метода mCompleted = False ' Вызов асинхрнонного запроса mSWbemServices.ExecQueryAsync mSink, "SELECT * FROM Win32_Process" ' Зацикливание скрипта до окончание запроса (здесь можно выполнять любые другие операции) ' Как только асинхронный метод вернет какое-нибудь событие, то будет вызвана ' соотвествующая процедура, которая описана ниже, а работа основного скрипта на время ' прервется While Not mCompleted WScript.Sleep 1000 Wend ' Процедура обработки события возврата очередного объекта Sub Sink_OnObjectReady(mWbemObject, mWbemAsyncContext) WScript.Echo mWbemObject.Name End Sub ' Процедура обработки события завершения запроса Sub Sink_OnCompleted(mResult, mWbemErrorObject, mWbemAsyncContext) If mResult = 0 Then WScript.Echo "Запрос успешно завершен" Else WScript.Echo "Запрос завершен с ошибкой" End If mCompleted = True End Sub
Рассмотренные выше методы возвращают объекты и коллекции объектов, которые обладают своими методами и свойствами. Информацию о всех свойствах и методах, поддерживаемых конкретным объектом, можно получить с помощью такого скрипта:
' Объект mObject получен методом Get ' Получение свойств и их значений For Each mCurrentProperty in mObject.Properties_ Wscript.Echo mCurrentProperty.Name & ": " & mCurrentProperty.Value Next ' Получение методов For Each mCurrentMethod in mObject.Methods_ Wscript.Echo mCurrentMethod.Name Next
Коллекция объектов всегда обладает общими для всех экземпляров свойствами, наиболее часто используемые свойства — это Count и Item.
Count — это свойство коллекции объекта, которое содержит количество элементов коллекции.
Item(mObjectPath) — это метод, который возвращает один объект коллекции, соответствующий указанному пути.
Как уже выяснилось, объект имеет свои методы и свойства, которые соответствуют классу данного экземпляра, но помимо классовых свойств и методов всем объектам присущи универсальные, которые оканчиваются на символ подчеркивания, чтобы отличать их от классовых. Наиболее часто используемые универсальные методы — это ExecMethod_ и Put_.
ExecMethod_(mMethod, mWbemInParamsm, mFlags, mWbemNamedValueSet) — это метод для исполнения классового метода у используемого объекта.
Put_(mFlags, mWbemNamedValueSet) — это метод для записи измененных свойств объекта в репозиторий WMI и в реальный объект.
Пример использования метода Put_ — изменение метки диска:
' Подключение к пространству имен Set mSWbemServices = GetObject("winmgmts:\.RootCIMv2") ' Получение объекта логического диска Set mDisks = mSWbemServices.ExecQuery("SELECT * FROM Win32_LogicalDisk WHERE DeviceID = 'C:'") ' Перебор коллекции возвращенных объектов For Each mDisk in mDisks ' Смена метки диска oDisk.VolumeName = "System" ' Запись изменений oDisk.Put_ Next
Пример использование класса CIM_DataFile для переименования файлов:
' Целевой компьютер mComputer = "." ' Целевая папка mFolderPath = "C:Temp" ' Подключение к пространству имен целевого компьютера Set mSWbemServices = GetObject("winmgmts:\" & mComputer & "RootCIMv2") ' Получение колекции файлов целевой папки Set mFileList = mSWbemServices.ExecQuery ("ASSOCIATORS OF {Win32_Directory.Name='" _ & mFolderPath & "'} WHERE ResultClass = CIM_DataFile") ' Обработка коллекции файлов For Each mCurrentFile In mFileList ' Формирование нового имени файла mNewName = mCurrentFile.Drive & mCurrentFile.Path & mCurrentFile.FileName _ & "." & mCurrentFile.Extension & ".old" ' Переименование файла errResult = mCurrentFile.Rename(mNewName) ' Формирование отчета о переименовании if errResult = 0 then mResultText = mResultText & "File " & mCurrentFile.Name & " renamed to " _ & mNewName & vbCrLf else mResultText = mResultText & "Error at renaming " & mCurrentFile.Name & _ " file" & vbCrLf errResult = 0 end if Next ' Вывод отчета о переименовании Wscript.Echo(mResultText)
Аналогично приведенному примеру можно совершать и другие действия с файлами, так как класс CIM_DataFile поддерживает методы: копирование, удаление, переименование, NTFS-сжатие, смена разрешений, смена владельца.
Пример использования классов оборудования компьютера для получения информации о количестве портов USB 2.0 и используемых USB-устройствах:
iCounter = 0 ' Целевой компьютер mComputer = "." ' Подключение к пространству имен целевого компьютера Set mSWbemServices = GetObject("winmgmts:\" & mComputer & "RootCIMv2") ' Получение колекции USB-контроллеров Set mControllerList = mSWbemServices.ExecQuery("Select * From Win32_USBController") ' Обработка USB-контроллеров For Each mCurrentController in mControllerList If Instr(mCurrentController.Name, "Enhanced") Then iCounter = iCounter + 1 End If Next ' Формирование отчета о USB-контроллерах mResultText = "USB 2.0 Ports count: " & iCounter & vbCrLf & vbCrLf ' Получение колекции USB-устройств Set mDeviceList = mSWbemServices.ExecQuery ("Select * From Win32_USBControllerDevice") ' Обработка USB-устройств For Each mCurrentDevice in mDeviceList mDeviceName = mCurrentDevice.Dependent mDeviceName = Replace(mDeviceName, Chr(34), "") mDeviceNames = Split(mDeviceName, "=") mDeviceName = mDeviceNames(1) ' Получение свойств каждого устройства по его идентификатору Set mUSBDeviceList = mSWbemServices.ExecQuery("Select * From Win32_PnPEntity " _ & "Where DeviceID = '" & mDeviceName & "'") ' Обработка свойств устройства For Each mCurrentUSBDevice in mUSBDeviceList ' Формирование отчета о USB-устройствах mResultText = mResultText & mCurrentUSBDevice.Description & vbCrLf Next Next ' Вывод результата Wscript.Echo(mResultText)
Пример использования класса свойств принтеров для получения информации о настройках принтеров:
' Целевой компьютер mComputer = "." ' Задание констант кодов типов доступа к текстовому файлу Const ForReading = 1 Const ForWriting = 2 Const ForAppending = 8 ' Создание объекта оболочки и получение текущей директории Set oShell = CreateObject("wscript.shell") sWorkDirectory = oShell.CurrentDirectory ' Создание объекта файловой системы и файла Set oFSO = CreateObject ("Scripting.FileSystemObject") Set mResultFile = oFSO.OpenTextFile(sWorkDirectory & "PrinterList.txt", ForWriting, True, 0) ' Подключение к пространству имен целевого компьютера Set mSWbemServices = GetObject("winmgmts:\" & mComputer & "RootCIMv2") ' Получение колекции локальных принтеров Set mPrinterList = mSWbemServices.ExecQuery("SELECT * FROM Win32_Printer WHERE Local = True") ' Запись заголовка в файл mResultFile.WriteLine("Name;Comment;Location;ShareName;DriverName;PortName;") ' Обработка каждого принтера For Each mCurrentPrinter in mPrinterList mResultFile.WriteLine(mCurrentPrinter.Name & ";" & mCurrentPrinter.Comment & ";" & _ mCurrentPrinter.Location & ";" & mCurrentPrinter.ShareName & ";" & _ mCurrentPrinter.DriverName & ";" & mCurrentPrinter.PortName & ";") Next ' Закрытие файла mResultFile.Close
Пример использования класса свойств сетевого адаптера для изменения конфигурации сетевой карты — перевода с DHCP на статическую конфигурацию:
' Целевой компьютер mComputer = "." ' Новые сетевые параметры задаются конкретными значениями ' Аналогичные параметры задаются значением "The same" ' Пустые парамеры задаются значением "" mNewIPAddress = "The same" mNewSubnetMask = "The same" mNewDNSServer = "The same" mNewDefaultIPGateway = "The same" mNewWINSPrimaryServer = "The same" mNewWINSSecondaryServer = "The same" ' Рабочие массивы Dim mDNSServerList() Dim mDefaultIPGatewayList() Dim mGatewayMetricList() Dim mNewDNSServerList() Dim mNewDefaultIPGatewayList() Dim mNewGatewayMetricList() ' Подключение к пространству имен целевого компьютера Set mSWbemServices = GetObject("winmgmts:\" & mComputer & "RootCIMv2") ' Получение коллекции адаптеров с указанным IP-адресом Set mAdapterList = mSWbemServices.ExecQuery ("Select * From Win32_NetworkAdapter") ' Получение MAC-адреса адаптера локального адаптера For Each mCurrentAdapter In mAdapterList If InStr(LCase(mCurrentAdapter.NetConnectionID), "локальн") > 0 _ Or InStr(LCase(mCurrentAdapter.NetConnectionID), "local") > 0 Then mMACAddress = mCurrentAdapter.MACAddress mCaption = mCurrentAdapter.Caption Exit For End If Next ' Получение коллекции параметров адаптера с указанным MAC-адресом Set mAdapterConfigList = mSWbemServices.ExecQuery _ ("Select * From Win32_NetworkAdapterConfiguration WHERE MACAddress = '" _ & mMACAddress & "'") ' Получение текущих параметров сетевого адаптера с указанным MAC-адресом For Each mCurrentAdapterConfig In mAdapterConfigList ' IP-адрес If IsNull(mCurrentAdapterConfig.IPAddress) = False Then For Each mCurrentIPAddress In mCurrentAdapterConfig.IPAddress mIPAddress = mCurrentIPAddress Exit For Next End If If mNewIPAddress = "The same" Then mNewIPAddress = mIPAddress mNewIPAddressList = Array(mNewIPAddress) ' Маска подсети If IsNull(mCurrentAdapterConfig.IPSubnet) = False Then For Each mCurrentIPSubnet In mCurrentAdapterConfig.IPSubnet mSubnetMask = mCurrentIPSubnet Exit For Next End If If mNewSubnetMask = "The same" Then mNewSubnetMask = mSubnetMask mNewSubnetMaskList = Array(mNewSubnetMask) ' DNS сервера If IsNull(mCurrentAdapterConfig.DNSServerSearchOrder) = False Then iCounter = 0 For Each mCurrentDNSServer In mCurrentAdapterConfig.DNSServerSearchOrder Redim Preserve mDNSServerList(iCounter) mDNSServerList(iCounter) = mCurrentDNSServer iCounter = iCounter + 1 Next End If If mNewDNSServer = "The same" Then For iCounter = 0 To UBound(mDNSServerList) Redim Preserve mNewDNSServerList(iCounter) mNewDNSServerList(iCounter) = mDNSServerList(iCounter) Next Else For iCounter = 0 To UBound(Split(mNewDNSServer,";")) Redim Preserve mNewDNSServerList(iCounter) mNewDNSServerList(iCounter) = Split(mNewDNSServer,";")(iCounter) Next End If ' Шлюзы If IsNull(mCurrentAdapterConfig.DefaultIPGateway) = False Then iCounter = 0 For Each mCurrentDefaultIPGateway In mCurrentAdapterConfig.DefaultIPGateway Redim Preserve mDefaultIPGatewayList(iCounter) mDefaultIPGatewayList(iCounter) = mCurrentDefaultIPGateway Redim Preserve mGatewayMetricList(iCounter) mGatewayMetricList(iCounter) = iCounter + 1 iCounter = iCounter + 1 Next End If If mNewDefaultIPGateway = "The same" Then For iCounter = 0 To UBound(mDefaultIPGatewayList) Redim Preserve mNewDefaultIPGatewayList(iCounter) mNewDefaultIPGatewayList(iCounter) = mDefaultIPGatewayList(iCounter) Redim Preserve mNewGatewayMetricList(iCounter) mNewGatewayMetricList(iCounter) = iCounter + 1 Next Else For iCounter = 0 To UBound(Split(mNewDefaultIPGateway,";")) Redim Preserve mNewDefaultIPGatewayList(iCounter) mNewDefaultIPGatewayList(iCounter) = Split(mNewDefaultIPGateway,";")(iCounter) Redim Preserve mNewGatewayMetricList(iCounter) mNewGatewayMetricList(iCounter) = iCounter + 1 Next End If ' WINS сервера If IsNull(mCurrentAdapterConfig.WINSPrimaryServer) = False Then mWINSPrimaryServer = mCurrentAdapterConfig.WINSPrimaryServer End If If mNewWINSPrimaryServer = "The same" Then If IsNull(mCurrentAdapterConfig.WINSPrimaryServer) = True Then mNewWINSPrimaryServer = "" Else mNewWINSPrimaryServer = mWINSPrimaryServer End If End If If IsNull(mCurrentAdapterConfig.WINSSecondaryServer) = False Then mWinsSecondaryServer = mCurrentAdapterConfig.WINSSecondaryServer End If If mNewWinsSecondaryServer = "The same" Then If IsNull(mCurrentAdapterConfig.WINSSecondaryServer) = True Then mNewWinsSecondaryServer = "" Else mNewWinsSecondaryServer = mWINSSecondaryServer End If End If Exit For Next ' Формирование сообщения по текущей и по будущей конфигурациям сетевого адаптера mInfoMessage = "Network adapter: " & mCaption & vbCrLf _ & "MAC address: " & mMACAddress & vbCrLf _ & "Current configuration:" & vbCrLf _ & vbTab & "IP address: " & mIPAddress & vbCrLf _ & vbTab & "Subnet mask: " & mSubnetMask & vbCrLf _ & vbTab & "Default Gateway: " & Join(mDefaultIPGatewayList,";") & vbCrLf _ & vbTab & "DNS servers: " & Join(mDNSServerList,";") & vbCrLf _ & vbTab & "WINS Primary Server: " & mWINSPrimaryServer & vbCrLf _ & vbTab & "WINS Secondary Server: " & mWINSSecondaryServer & vbCrLf _ & "New configuration:" & vbCrLf _ & vbTab & "IP address: " & mNewIPAddress & vbCrLf _ & vbTab & "Subnet mask: " & mNewSubnetMask & vbCrLf _ & vbTab & "Default Gateway: " & Join(mNewDefaultIPGatewayList,";") & vbCrLf _ & vbTab & "DNS servers: " & Join(mNewDNSServerList,";") & vbCrLf _ & vbTab & "WINS Primary Server: " & mNewWINSPrimaryServer & vbCrLf _ & vbTab & "WINS Secondary Server: " & mNewWINSSecondaryServer & vbCrLf _ & vbCrLf & "Please confirm the changes" & mNewWINSSecondaryServer & vbCrLf ' Окно подтверждения изменения настроек сетевого параметра mChangeFlag = MsgBox(mInfoMessage, vbOKCancel, "Network card settings change") If mChangeFlag = vbOK Then ' Установка нового IP адреса For Each mCurrentAdapterConfig in mAdapterConfigList errEnable = mCurrentAdapterConfig.EnableStatic _ (mNewIPAddressList, mNewSubnetMaskList) errGateways = mCurrentAdapterConfig.SetGateways _ (mNewDefaultIPGatewayList, mNewGatewayMetricList) errWINS = mCurrentAdapterConfig.SetWINSServer _ (mNewWINSPrimaryServer, mNewWinsSecondaryServer) errDNS = mCurrentAdapterConfig.SetDNSServerSearchOrder _ (mNewDNSServerList) Exit For Next ' Pезультат операции mInfoMessage = "Operation result:" & vbCrLf _ & "IP address error code: " & errEnable & vbCrLf _ & "Gateway error code: " & errGateways & vbCrLf _ & "DNS error code: " & errDNS & vbCrLf _ & "WINS error code: " & errWINS & vbCrLf Else mInfoMessage = "The operation is canceled" End If Wscript.Echo(mInfoMessage)
Ресурсы WMI доступны не только через скрипты, к ним можно обращаться из других языков программирования и даже из программ.
Существует два способа обращения к WMI через Visual Basic.NET.
Первый способ берет свое начало из скриптов VBS. Он использует обращение к инстументу winmgmts, как это делалось в методе моникера:
oComputerSystem = GetObject("winmgmts:[Options!]WMINameSpace).ExecQuery(WQLQuery)
Пример запроса модели комьютера (консольное приложение)
Module TestModule Sub Main() ' Объявление переменных Dim oWMIObject As Object Dim oComputerSystem As Object Try ' Подключение к WMI oWMIObject = GetObject("winmgmts:{impersonationLevel=impersonate}!\.rootcimv2") ' Выполнение запроса oComputerSystem = oWMIObject.ExecQuery("Select * from Win32_ComputerSystem") For Each oConfigutation As Object In oComputerSystem ' Вывод результатов в консоль Console.Write(oConfigutation.Model) Next Catch ex As Exception Console.Write("Ошибка запроса к WMI") End Try End Module
Второй способ является более правильным с точки зрения Visual Studio. Он использует классSystem.Managementдля запросов к WMI, в котором указываются пространство WMI, параметры подключения и WQL запрос:
' Задание параметров подключения mOptions = New Management.ConnectionOptions([Options]) ' Задания WMI пространства имен mScope = New Management.ManagementScope(WMINameSpace, mOptions) ' Задание WQL запроса mQuery = New Management.ObjectQuery(WQLQuery) ' Создание объекта поиска по WMI с указанными параметрами mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery) ' Выполнение запроса mQueryCollection = mSearcher.Get()
Использование полученных объектов аналогично использованию в скриптах.
Пример запроса сервисов локального комьютера (консольное приложение):
Module TestModule Sub Main() ' Объявление переменных Dim mOptions As Management.ConnectionOptions Dim mScope As Management.ManagementScope Dim mQuery As Management.ObjectQuery Dim mSearcher As Management.ManagementObjectSearcher Dim mQueryCollection As Management.ManagementObjectCollection ' Задание параметров подключения mOptions = New Management.ConnectionOptions ' Задания WMI пространства имен mScope = New Management.ManagementScope("\.rootcimv2", mOptions) ' Задание WQL запроса mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service") ' Создание объекта поиска по WMI с указанными параметрами mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery) Try ' Выполнение запроса mQueryCollection = mSearcher.Get() ' Вывод результатов в консоль For Each mObject As Management.ManagementObject In mQueryCollection Console.WriteLine(mObject.Item("DisplayName").ToString) Next Catch ex As Exception Console.Write("Ошибка запроса к WMI") End Try End Sub End Module
В качестве примера прораммы использования WMI в Visual Basic.Net представлено консольное приложение управления сервисом печати компьютера. Приложение запрашивает модель компьютера и выводит результат в консоль. После чего запрашивает состояние сервиса печати и, если он остановлен, предлагает запустить его.
Приложение разделено на две части: класс, который компилируется в динамическую библиотеку DLL, и программа, которая собирается в исполняемый файл EXE.
Листинг файла WMIClass.vb:
Public Class WMIClass ' Функция получения модели копьютера #Region "GetModel 1.0" Public Function GetModel(Optional ByVal IPAddress As String = ".") As String Dim mTempValue As String = Nothing Try Dim oComputerSystem = GetObject("winmgmts:{impersonationLevel=impersonate}!\" & _ IPAddress & "rootcimv2").ExecQuery("Select * from Win32_ComputerSystem") For Each oConfigutation As Object In oComputerSystem mTempValue = oConfigutation.Model Next Catch ex As Exception End Try Return mTempValue End Function #End Region ' Функция получения состояния сервиса компьютера #Region "GetServiceState 1.0" Public Function GetServiceState(Optional ByVal IPAddress As String = ".", _ Optional ByVal ServiceName As String = "winmgmt") As Boolean Dim mOptions As Management.ConnectionOptions Dim mScope As Management.ManagementScope Dim mQuery As Management.ObjectQuery Dim mSearcher As Management.ManagementObjectSearcher mOptions = New Management.ConnectionOptions mScope = New Management.ManagementScope("\" & IPAddress & "rootcimv2", mOptions) mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service " & _ "WHERE DisplayName = '" & ServiceName & "'") mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery) Try Dim mQueryCollection As Management.ManagementObjectCollection = mSearcher.Get() For Each mObject As Management.ManagementObject In mQueryCollection If mObject("State") = "Running" Then Return True Else Return False End If Next Return False Catch ex As Exception Return False End Try End Function Public Function GetServiceStateFull(Optional ByVal IPAddress As String = ".", _ Optional ByVal ServiceName As String = "winmgmt") As String Dim mOptions As Management.ConnectionOptions Dim mScope As Management.ManagementScope Dim mQuery As Management.ObjectQuery Dim mSearcher As Management.ManagementObjectSearcher mOptions = New Management.ConnectionOptions mScope = New Management.ManagementScope("\" & IPAddress & "rootcimv2", mOptions) mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service " & "WHERE DisplayName = '" & ServiceName & "'") mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery) Try Dim mQueryCollection As Management.ManagementObjectCollection = mSearcher.Get() For Each mObject As Management.ManagementObject In mQueryCollection Return mObject("State") Next Return "No data" Catch ex As Exception Return "No data" End Try End Function #End Region ' Процедура управления сервисом компьютера #Region "Manage Service 1.0" Public Sub ManageService(Optional ByVal IPAddress As String = ".", _ Optional ByVal ServiceName As String = "winmgmt", _ Optional ByVal Action As String = "StartService") Dim mOptions As Management.ConnectionOptions Dim mScope As Management.ManagementScope Dim mQuery As Management.ObjectQuery Dim mSearcher As Management.ManagementObjectSearcher Dim mQueryCollection As Management.ManagementObjectCollection mOptions = New Management.ConnectionOptions mScope = New Management.ManagementScope("\" & IPAddress & "rootcimv2", mOptions) mQuery = New Management.ObjectQuery("SELECT * FROM Win32_Service " & _ "WHERE DisplayName = '" & ServiceName & "'") mSearcher = New Management.ManagementObjectSearcher(mScope, mQuery) Try mQueryCollection = mSearcher.Get() For Each mObject As Management.ManagementObject In mQueryCollection mObject.InvokeMethod(Action, Nothing) Next Catch ex As Exception End Try End Sub #End Region End Class
Листинг файла TestModule.vb:
Module TestModule ' Создание экземпляра класса WMIClass Private mWMIClass_Instance As New WMIClass Sub Main() Dim mKeyNumber As Integer ' Получение модели компьютера и результата в консоль Console.WriteLine("Модель компьютера: " & mWMIClass_Instance.GetModel()) ' Проверка состояния сервиса "Диспетчер печати" If mWMIClass_Instance.GetServiceState(, "Диспетчер печати") = True Then Console.WriteLine("Служба ""Диспетчер печати"" запущена") Else Console.WriteLine("Служба ""Диспетчер печати"" остановлена") Console.Write("Запустить службу ""Диспетчер печати""? Y/N: ") ' Чтение символа с клавиатуры mKeyNumber = Console.Read If mKeyNumber = 89 Or mKeyNumber = 121 Then Console.WriteLine("Запуск службы ""Диспетчер печати""...") ' Попытка запуска сервиса "Диспетчер печати" mWMIClass_Instance.ManageService(, "Диспетчер печати", "StartService") ' Ожидание 5 секунда Threading.Thread.Sleep(5000) ' Проверка состояния сервиса "Диспетчер печати" If mWMIClass_Instance.GetServiceState(, "Диспетчер печати") = True Then Console.WriteLine("Служба ""Диспетчер печати"" успешно запущена") Else Console.WriteLine("Запуск службы ""Диспетчер печати"" не удался") End If End If End If Console.WriteLine("Нажмите любую клавишу для продолжения") ' Ожидание нажатия любой клавиши Console.ReadKey() End Sub End Module
Для того, чтобы облегчить написание скриптов и программ, существуют специальные утилиты, которые помогают просмотреть структуру пространства WMI и показавают примеры использования всех классов. Наиболее распространенные утилиты — это Scriptomatic и WMI Code Creator.
Инструмент Scriptomatic предствляет из себя HTA-приложение, которое генерирует код, использующий WMI, на VBSScript, JScript, Perl и Python. Сам по себе WMI может оказаться трудным для изучения, поэтому рекомендуется использовать Scriptomatic для освоения классов WMI, а также для быстрого создания шаблонов обращения к ресерсум WMI. Scriptomatic позволяет выбрать интересующий объект WMI, а затем генерирует код на указанном языке программирования. Полученный код можно выполнить непосредственно в оболочке программы, а результаты вывести в консоль, текстовый файл, HTML, Excel или XML. Инструмент доступен на сайте Microsoft по этой ссылке.
WMI Scriptomatic — Инициализация
WMI Scriptomatic — Win32_OpepatingSystem
Программа WMI Code Creator представляет из себя генератор кода, который использует WMI для получения информации и для осуществления задач упраления компьютерами. Программа может помочь научиться использовать WMI-скрипты и WMI-приложения для управления как локальным, так и удаленным компьютером. Инструмент доступен на сайте Microsoft по этой ссылке.
Используя WMI Code Creator можно найти любую информацию о компьютере: имя и версия операционной системы, свободное место на диске, состояние сервисов и так далее. Можно выполнить метод из WMI класса для осуществления управления компьютером: создать или удалить сервис, запустить или закрыть программы, назначить разрешения на папку или файл и многое другое. Этот инструмент так же позволяет просматривать доступное WMI-пространство и WMI-классы, чтобы найти нужную для программирования инстанцию с ее описанием, свойствами, методами и примером использования.
WMI Code Creator — Query
WMI Code Creator — Method
WMI Code Creator — Event
WMI Code Creator — Namespace
Итак, Windows Management Instrumentation — это мощный инструмент для администрирования операционных систем семейства Windows с помощью скриптов. С помощью WMI можно управлять устройствами, учетными записями, сервисами, процессами, сетевыми интерфейсами и другими программами, которые расширяют базовую структуру WMI своими классами.
Помимо скриптов WMI может применяться и в полноценных программах, то есть программисты могут внедрять запросы к WMI в исполняемый код, завязывая свою программу с работой WMI, благодаря чему программа становится проще и легче, но зависимой от правильности работы Windows Management Instrumentation.
Интересно, что новая командная оболочка Windows PowerShell связана с WMI как технической точки зрения, так и с точки зрения создания запросов — утилита Wmic.exe функционирует в некотором смысле аналогичным образом. В Windows PowerShell поддержка WMI, представлена в точно таком же согласованном объектном виде, как и другие возможности данной оболочки, поэтому при изучении этой оболочки применение WMI не становится такой сложной задачей, как это было в VBScript — не нужно изучать синтаксис и механизмы языка, отличного от языка скрипта.
Инструменты для написания скриптов ScriptReference.zip.
Более подробно о Windows PowerShell можно будет прочитать в следующих выпусках статей сайта www.SysEngineering.ru.
Виталий Бочкарев
Last time we’ve dealt with objects: PowerShell for Beginners (Part 8): The Power of PowerShell – Getting in Touch with Objects (Get-Member, Select-Object). Of course, I was thinking something. Part 8 is a prerequisite for this part. We are now going to make a huge step forward. And this part is full of examples. But before we begin, the answer of the last exercise. We will also have a quick review what we’ve learned so far in Part 8.
All parts of the series can be found here: PowerShell for Beginners (Series)
Review (Part
Here are the assignments and the solutions from part 8:
Attributes
Create a directory C:Temp1. Create a text file testfile1.txt in C:Temp1. Use only PowerShell. If you need assistance use the help (Get-Help). Open the file. Now show the following attributes with Select-Object or another technique: The name of the file, the file extension and the date of last access.
Let’s create a new directory and a new file.
New-Item -ItemType Directory -Path C:Temp1; New-Item -ItemType File -Path C:Temp1testfile1.txt
The next task is to show only a few attributes. Run Get-Member to explore all of them.
Get-ChildItem C:Temp | Get-Member
We now find the attributes Name, Extension and LastAccessTime. Let’s put this all together in Select-Object.
Get-ChildItem C:temp1testfile1.txt | Select-Object Name,Extension,LastAccessTime
Methods
Calculate back 10 years using Get-Date from today. Answer the following question: Which day of the year was that? (1..365?)
The next task is to calculate 10 years back. For this we can use the .NET method.
(Get-Date).AddYears(-10)
Now use Get-Member to find the attribute DayOfYear. Just add that to the last command.
(Get-Date).AddYears(-10).DayOfYear
Review Part 8
You have to deal with Objects. Otherwise you will never realize the power of PowerShell. Use Get-Member to explore objects. Attributes show you what an Object is. Use Select-Object to retrieve attributes. Methods can change or do something. Put the command and the method values in brackets.
The Power of WMI
Windows Management Instrumentation is a basic Windows technology. WMI (Windows Management Instruments) provides read and write access to almost all Windows settings. WMI is one of the most important interfaces for the administration and remote maintenance of workstations and servers.
WMI is a Windows service. Open Windows PowerShell. Run
wmimgmt.msc
To give you a little foretaste of what’s coming up the further parts of this post a quick and powerful example.
Which software is installed on Client01? Note, that I’m logged on another computer. This is a remote call.
Get-WmiObject win32_product -ComputerName client01 | Select-Object Name,InstallDate
Get-WmiObject has to be used to explore WMI Objects. But there’s also Get-CIMInstance. This could be a little confusing. Just remember WMI = CIM and CIM =WMI.
For the further part, I will use Get-CIMInstance, because it’s the newer and more flexbile command. More about this later.
Get-CimInstance win32_product -ComputerName client01 | Select-Object Name,InstallDate
Summary
WMI (Windows Management Instruments) provides read and write access to almost all Windows settings. WMI is one of the most important interfaces for the administration. There are two important cmdlets: Get-WmiObject and Get-CimInstance.
Exploring WMI Objects
Do you remember my 2 step method from part 8 to explore objects? The same goes here, with WMI.
1. Inquiry of all possibilities: Run Get-Member
Get-CimInstance win32_product | Get-Member -MemberType property
2. Call the attribute or method with (). or select-object or select
Get-CimInstance win32_product | Select-Object Name,InstallDate ,InstallSource,Vendor,Packagename
The question is now how to find all WMI Classes? So far, we’ve only looked at win32_product.
To view all WMI Classes run Get-WmiObject with the list parameter.
Get-WmiObject -List
A huge number of objects fill the screen.
Another option is – if you know about what you’re searching for – using Get-CimInstance and pressing TAB. For example if you want to view something about your BIOS then type
Get-CimInstance win32_bi
and press TAB. The third one is the right one.
It is impossible to go through all instances and classes here. That’s why from now on we will focus on examples you can build on.
What have we learned so far?
Run Get-WmiObject -List for discovering WMI Objects. Run Get-CimInstance and press TAB to discover WMI Objects.
WMI Examples
win32_OperatingSystem
One of the most used wmi queries is related to win32_operatingsystem.
Get-CimInstance win32_operatingsystem
Hmm… Are you impressed? Not really. REMEMBER the 2 step method. There’s more. Find it out!
Get-CimInstance win32_operatingsystem | Get-Member -MemberType property
What do you think about this command:
Get-CimInstance win32_operatingsystem | Select-Object InstallDate,LastBootUpTime,SystemDrive,Version,Serialnumber,OSType,FreePhysicalMemory,Status,NumberOfUsers,WindowsDirectory
win32_UserAccount
Another useful WMI instance is win32_useraccount.
Get-CimInstance Win32_UserAccount
There’s more. Again: Run Get-Member!
Get-CimInstance Win32_UserAccount | Get-Member
There we find hidden attributes. Let’s display some of them!
Get-CimInstance Win32_UserAccount | Select-Object Name,SID,PasswordChangeable,PasswordExpires,PasswordRequired,Status
I am now anticipating something that will be the subject of the next part. What if we want to display the properties of one user. How to achieve this? For this, we can use Where-Object. Let’s assume we want to list all user names that contain the value “schwarzen” in the name.
Here we go:
Get-CimInstance Win32_UserAccount | Where-Object Name -like '*schwarzen*' | Select-Object Name,SID,PasswordChangeable,PasswordExpires,PasswordRequired,Status
Ok, filtering and Where-Object will be the topic of the next post. Let’s move to the next useful instance.
Win32_PhysicalMemory
Do you know the Everest tool? It’s a hardware inventory tool. From now on we don’t need this 3rd party tool anymore. 😉 If you want to find out your type of memory (for example if you have to replace your memory) run
Get-WmiObject win32_physicalmemory | Format-Table Manufacturer,Banklabel,Configuredclockspeed,Devicelocator,Capacity,Serialnumber -autosize
Why Format-Table and not Select-Object? I wanted a sweeter view in table format.
Win32_ComputerSystem
Don’t forget to run Get-Member for discovering all the properties you see in the example below.
Get-CimInstance Win32_ComputerSystem | Select-Object Name,Manufacturer,ThermalState,KeyboardPasswordStatus,NumberOfProcessors
WMI Remoting (Side Note for Active Directory Administrators)
Before we come to the end of this article one more piece of information for Active Directory Systems Engineers. If you are working in an Active Directory environment, then you are able to execute remote WMI queries.
For example, you would like to find out which software is installed on computer dc01 run Get-CimInstance or Get-WmiObject and use the ComputerName parameter.
Get-CimInstance win32_product -ComputerName dc01 | Select-Object Name,InstallDate
Exercise
Here’s the exercise to the next part.
Retrieve information about your hard disk. Use Get-WmiObject or Get-CimInstance. First, search for the WMI Object and once you’ve found it show the Name, the Partitions, the Model, the Firmware and the Serial Number.
See you next time with the topic: Powershell for Beginners (Part 10): Filtering and Where-Object.
Patrick Gruenauer, MVP Powershell
- 04.10.2021
- 4 633
- 0
- 6
- 6
- 0
- Содержание статьи
- Вступление
- Что такое Powershell?
- Знакомство с PowerShell
- Параметры
- Конвейер
- Получение сведений об объектах
- Безопасность
- Псевдонимы
- Диски PowerShell
- Профили PowerShell
- Работа с объектами WMI
- Заключение
- Добавить комментарий
Вступление
Немалая часть задач, связанных с обслуживанием локальных вычислительных сетей, представляет собой выполнение рутинных операций, ручная реализация которых может потребовать значительного времени. Вероятно, решения, позволяющие автоматизировать выполнение административных задач, которые могли бы повысить производительность, возникли почти сразу же с появлением профессии системного администратора.
Наиболее распространенным средством «экономии времени и избавления от головной боли» стала запись и последовательное пакетное исполнение необходимых операций — исполнение сценариев или скриптов в интерпретаторе команд операционной системы.
Попытки улучшить состояние дел в области управления и администрирования Windows с помощью командного интерфейса привели не к адаптации чужеродного для системы языка сценариев или созданию супер-утилиты, работающей в DOS, а к появлению PowerShell – новой командной оболочки.
В составе MS-DOS и Windows 9x таким интерпретатором, позволяющим выполнять обработку пакетных файлов (bat-файлов), являлся command.com, впоследствии (начиная с выхода Windows NT) замененный cmd.exe. Позднее появился Windows Script Host.
Тем не менее, процесс написания и выполнения сценариев в ОС Windows не развит так хорошо, как, например, в UNIX-системах. Одна из причин этого – сам графический интерфейс ОС Windows, видимо и сделавший ее столь популярной среди обычных, не корпоративных пользователей. Возможность управления некоторыми элементами среды Windows с помощью графического интерфейса не всегда можно реализовать с помощью системных утилит, выполняемых в командной строке. С другой стороны, возможности каких-то системных программ, поставляемых в составе Windows, не всегда представлены в GUI. К тому же интерпретаторы в Windows имеют довольно ограниченный набор команд, «зашитых» в саму оболочку. Windows Script Host не интегрирован с командной строкой и сам по себе представляет потенциальную опасность – его использует достаточно большое количество вредоносных программ.
Попытки улучшить состояние дел в области управления и администрирования Windows с помощью командного интерфейса привели не к адаптации чужеродного для системы языка сценариев или созданию супер-утилиты, работающей в DOS, а к появлению Windows PowerShell – новой командной оболочки. По некоторым данным, ее появление связано с использованием платформы .NET при создании командного интерфейса для WMI. В данный момент PowerShell является отдельным приложением, который можно установить на любую систему, использующую платформу .Net 2.0 (Windows XP, Vista, Server 2003). Начиная с Server 2008, PowerShell будет являться встроенным компонентом Windows-систем. Если же у вас не Server 2008, для знакомства с PowerShell предварительно необходимо будет его загрузить (возможно, вам понадобится и установка .NET).
Что такое Powershell?
PowerShell — расширяемое средство автоматизации от Microsoft с открытым исходным кодом, состоящее из оболочки с интерфейсом командной строки и сопутствующего языка сценариев
Знакомство с PowerShell
Запустив PowerShell, вы не обнаружите поначалу никаких различий между ним и cmd.exe (разве что цвет фона окна у PowerShell по умолчанию — синий). Более того, вскоре вы обнаружите, что операции копирования/вставки в PowerShell реализованы также безобразно, как и в cmd.exe. Но первое впечатление о схожести этих оболочек, скажем так, не совсем соответствует действительности.
То обстоятельство, что работа оболочки PowerShell основана на .NET Framework, является главным ее отличием от предыдущих командных оболочек Windows. PowerShell полностью объектно-ориентирована. Результатом выполнения команды в PowerShell является не некий «текст сам по себе», а объект платформы .NET. Этот объект представляет собой собственно данные и имеет набор присущих ему свойств и методов.
Внутренние команды (точнее, командные структуры) для работы с объектами в PowerShell называются командлетами. Для них придумано специальное единообразное именование в виде комбинации действие-цель. Например, для получения данных используется действие “set”, для получения – “get”, для вывода — “out” и т. д. Цель – это тип объекта, к которому будет применено действие. Командлеты можно рассматривать как мини-программы, исполняемые в среде PowerShell. Для повышения функциональности можно создавать собственные командлеты или устанавливать командлеты сторонних разработчиков. Кроме командлетов, PowerShell позволяет выполнять функции, внешние сценарии (хранятся в файлах с расширением ps1
) и внешние исполняемые файлы.
В состав PowerShell включена довольно обширная справочная система. Для начала работы с ней можно выполнить команду Get-Help
.
Для получения детальной справки по какому-либо командлету или разделу основных сведений, необходимо указать его название в качестве параметра команды.
Параметры
Строго говоря, следуя духу единообразного именования в PowerShell, все передаваемые командлету имена параметров должны следовать за символом «-». Однако для простоты написания названия некоторых параметров можно опускать. Например, для вызова справки по командлету Get-Content вместо полного указания
Get-Help –name Get-Content
можно ввести команду
Get-Help Get-Content
Параметр может иметь какое-либо значение (в только что приведенном примере значением параметра name являлось Get-Content
) или не иметь его. В этом случае он является аналогом переключателя какой-либо функциональности команды. Например, если необходимо получить полную информацию о командлете Get-Content
, введите
Get-Help Get-Content –Detailed
Конвейер
В PowerShell реализован механизм передачи данных от одного процесса другому или вывод их в файл. Поскольку, как отмечалось выше, PowerShell оперирует не текстом, а объектами, при перенаправлении элементом обмена информации является объект, вместе со своей структурой. Такая возможность позволяет оперировать с объектами — отбирать их по заданному фильтру, сортировать, группировать их и т. д. Для организации такого конвейера (в документации на английском языке используется термин pipeline — трубопровод или канал) в тексте сценария используется знак вертикальной черты. При обнаружении такого знака интерпретатор передает объекты от одного командлета другому в качестве входных параметров.
В качестве примера конвейера и возможности получать доступ к свойствам передаваемых по нему объектов, приведем следующую ситуацию. Для проверки, не выполняются ли на компьютере некие подозрительные программы, мы хотим получить список всех запущенных процессов, получить пути и названия файлов, их запускающих, а также посмотреть дату создания таких файлов. В дополнение, отсортируем такой список по дате создания в убывающем порядке и отберем 10 наиболее «свежих» из них. Добавим к выводной информации также время последней модификации файла. Процессы с именами «System» и «Idle» из рассмотрения исключим, так как они не содержат пути к файлам.
Как говорится, хорошо сформулированный вопрос — уже половина решения. Взгляните:
Get-Process |
where-Object {"System", "Idle" -notContains $_.Name} |
Get-Item | Sort CreationTime -desc |
Select Directory, Name, CreationTime, LastWriteTime -first 10
Вводя код, вы всегда можете разбить строку, поставив в месте переноса знак «`» после пробела. Можно даже просто нажать клавишу Enter, не закончив строки. В этом случае PowerShell изменит приглашение на >>, давая пользователю понять, что интерпретатор считает код не завершенным и ожидает окончания его ввода.
Как и множество других скриптовых языков, PowerShell позволяет использовать переменные. Обозначением переменной служит знак «$». В случае передачи объекта по конвейеру, переменная $_ указывает на сам передаваемый объект.
Рассмотрим действия кода «по шагам». Сначала мы получаем список процессов с помощью командлета Get-Process
. Эти данные передаются по конвейеру далее и фильтруются по условиям, заданным в where-Object
(мы откидываем процессы с именами «System» и «Idle»).
Следующий элемент конвейера — Get-Item
возвращает атрибуты отобранных объектов. Осталось их отсортировать (время создания в убывающем порядке) и выбрать интересующие нас значения (имена папки и исполняемого файла, время создания и последней модификации файла). Последний параметр, -first 10
указывает, что выводиться будут лишь первые 10 элементов из списка объектов. Попробуем выполнить:
Замечательно, то что надо. Однако при попытке выполнить тот же код в среде Windows XP или Server 2003 обнаружилось, что там это выглядит не столь гладко:
При просмотре результатов выполнения
Get-Process | Select Path
выяснилось, что пути двух процессов — winlogon и csrss — в Windows XP и Server 2003 PowerShell интерпретирует как ??C:WINDOWSsystem32. За разъяснением такого поведения я обратился к Василию Гусеву, специалисту по PowerShell. Он пояснил, что эти процессы не используют Win32API, и столь разная реакция на них в XP/Vista со стороны .NET, вероятно, вызвана различием платформ этих операционных систем.
Решив, что использовать механизмы обработки ошибок (в части обхода «непонятного» пути с подавлением вывода сообщения об ошибке) или исключения из списка процессов winlogon и csrss в данном случае не годится (возможно, они инфицированы, а дату их модификации в результатах мы уже не увидим), команды были изменены следующим образом:
Get-Process |
ForEach-Object {
if ($_.Path -ne $NULL )
{
Get-Item ($_.Path -replace "\??\", "")
}
} | Sort CreationTime -desc | Select FullName, Name, CreationTime, LastWriteTime -first 10
А читатель может получить некоторое представление об использовании в PowerShell условий и регулярных выражений. Небольшие пояснения к коду. На втором этапе конвейера применен командлет ForEach-Object
, позволяющий выполнить заданную операцию для каждого объекта из набора, передаваемого на его вход. Как указывалось выше, текущий объект, над которым выполняется операция, представлен переменной $_. В качестве заданной операции здесь выступает условие вида if (условие){исполняемый код, если условие истинно}. Так же, как и в cmd.exe, для операторов сравнения используются не символы вида < или >, а аббревиатуры — в данном случае это «не равно»(not equal): -ne. Итак, если путь процесса содержит какое-либо значение (в случае с «System» и «Idle» путь просто отсутствует), с помощью функции replace все символы «??» в пути будут удалены (пожалуй, более детально затрагивать вопрос регулярных выражений мы пока не будем), а командлет Get-Item
предоставит доступ к свойствам текущего процесса. Ну а далее — все, как и в первом примере. Результат выполнения теперь одинаков:
Получение сведений об объектах
Возможно, у читателя уже возник вопрос — а как, вообще говоря, можно узнать, какую информацию можно получить в результате выполнения той или иной команды? Какие действия можно произвести с полученными данными? Например, в вышеописанном случае, откуда можно было узнать, что мы сможем получить дату создания файла? Одним из простых способов анализа объекта, возвращаемого командой, является передача этого объекта на вход командлета Get-Member
. Этот командлет выводит сведения о типе объекта и всех его элементов. Как правило, объекты имеют большое количество разнообразных свойств и результатом работы Get-Member
может стать весьма объемный текст, который не очень удобно просматривать. В этом случае можно либо разделять информацию на части, либо ее отфильтровывать. Пример получения информации об объекте, возвращаемом командлетом Get-Process
, просмотр которой можно осуществлять постранично:
Get-Process | Get-Member | Out-Host -Paging
По заполнении страницы, пользователь может выбрать один из вариантов — вывести еще одну страницу, вывести еще одну строку или прекратить вывод данных.
Фильтрация данных выполняется при помощи параметра MemberType, определяющего, сведения какого рода должны быть выведены. Например, команда
Get-Process | Get-Member -MemberType Properties
выведет лишь свойства объекта, а
Get-Process | Get-Member -MemberType Methods
— лишь его методы. Еще один способ посмотреть свойства объекта — присвоить переменной объект, затем набрать в консоли имя переменной, поставить точку и нажать клавишу Tab. С каждым нажатием клавиши PowerShell будет перебирать и подставлять методы и свойства объекта. Перебор в обратную сторону возможен с помощью сочетания клавиш Shift+Tab.
Безопасность
Как уже отмечалось, использование сценариев VBScript/JScript представляет потенциальную опасность для системы — для их исполнения достаточно щелкнуть по значку мышью. Опасность еще более возрастает, если пользователь вошел под учетной записью, входящей в группу администраторов. В PowerShell скрипт с расширением ps1
невозможно запустить на исполнение с помощью мыши — в системе такой файл будет открыт не в командной оболочке, а в Блокноте. Для запуска сценария необходимо запустить саму оболочку PowerShell, ввести имя файла и нажать клавишу Enter.
В новой оболочке так же невозможна подмена команд. Суть этого приема, применяемого злоумышленниками, заключается в следующем. Обычно у пользователя, не имеющего прав администратора, есть некоторые папки с разрешениями на запись и выполнение файлов. Характерный пример — папка C:Documents and Settingsимя_пользователя. Вредоносная программа создает в такой папке исполняемый файл с именем, совпадающим с именем команды оболочки или именем исполняемой системной программы. К примеру, я создал в «своей» папке документов ipconfig.vbs, выводящий простое сообщение. Теперь, если, запустив cmd.exe, и находясь в своей папке, я попытаюсь выполнить команду Windows ipconfig
, то получу вот такой результат:
Для полноты иллюстрации можно поместить в папку с документами и исполняемый файл, переименованный в нашем случае в ipconfig.exe. Тогда даже при вызове с указанием расширения будет запускаться файл из текущей папки, а не из system32. С PowerShell такой фокус не пройдет — для вызова скрипта, путь к которому не совпадает с путями, заданными в системной переменной %Path, необходимо явно указать его расположение. Даже в том случае, когда скрипт расположен в папке, являющейся для оболочки текущей, необходимо указать путь в таком виде: .имя_файла. Точка с обратным слешем указывают интерпретатору на текущую папку.
Еще одним механизмом обеспечения безопасности является политика выполнения сценариев. Изначально оболочка настроена так, что даже при правильном вызове сценария его выполнение будет запрещено, а пользователь получит соответствующее сообщение. Политика выполнения может переключаться в один из четырех режимов:
- Restricted — настройка по умолчанию, запуск любых сценариев запрещен
- AllSigned — разрешен запуск сценариев, имеющих цифровую подпись надежного издателя; сценарии, созданные пользователем, также должны быть заверены центром сертификации
- RemoteSigned — разрешен запуск сценариев, если они не являются доверенными, но созданы локальным пользователем; сценарии, загруженные из Интернета, не имеющие подписи, не исполняются
- Unrestricted — разрешен запуск любых сценариев
Текущий режим политики можно узнать, выполнив команду Get-ExecutionPolicy
в оболочке. Для изменения режима выполните команду Set-ExecutionPolicy
с необходимым названием политики в качестве параметра.
Также к инструментам, помогающим повысить безопасность при работе с PowerShell, я бы отнес параметры команд из разряда «а что будет, если…». Их два — whatif
и confirm
. Первый позволяет определить, какое действие и с каким объектом будет произведено, однако само действие реализовано не будет. Что-то вроде моделирования. Второй перед выполнением действия будет запрашивать подтверждения пользователя, и в случае утвердительного ответа — запускать необходимую команду фактически. То есть, такой вид подстраховки.
Приведу, пожалуй, наиболее яркий и забавный пример использования этих параметров. Если пользователь попытается выполнить команду:
Get-Process | Stop-Process
то через несколько секунд его будет ждать синий экран со STOP-ом. PowerShell, как и следует из текста команды, последовательно начнет «прибивать» все запущенные в системе процессы, что и приведет к ее критическому останову. Если же запустить:
Get-Process | Stop-Process -whatif
ничего страшного не произойдет — просто PowerShell покажет, что бы он сделал, если бы команда выполнялась без ключа -whatif
:
Псевдонимы
Оболочка имеет встроенный механизм псевдонимов команд. С одной стороны, псевдонимы используются для упрощения ввода команд. Как правило, в этом случае в качестве псевдонима используется сокращенное наименование командлета (например, gc
для Get-Content
или fl
для Format-List
). С другой стороны, этот механизм обеспечивает совместимость интерфейсов различных командных интерпретаторов. К примеру, имея опыт работы с cmd.exe, вы привыкли выводить содержимое папки с помощью команды dir. Выполнение этой команды в PowerShell приведет к тому же результату, хотя на самом деле оболочка вместо псевдонима dir будет выполнять командлет Get-ChildItem
. Список всех доступных псевдонимов можно получить с помощью команды Get-Alias
. Пользователь может создавать собственные псевдонимы, используя команду Set-Alias
.
Диски PowerShell
Так же, как Windows оперирует с данными, используя файловую систему, оболочка PowerShell работает с хранилищами данных, представленных в виде дисков. Физические диски системы являются не единственным встроенным в оболочку видом хранилищ, с которыми обеспечивается взаимодействие. Пользователь может работать с реестром, встроенными переменными и переменными среды, хранилищами сертификатов точно так же, как и с обычными дисками, папками и файлами. Реализация такого взаимодействия и обеспечение абстракций, позволяющих пользователю применять одинаковые команды и методы к различным хранилищам данных, выполняется провайдерами — программами .NET.
Список провайдеров, доступных в данный момент оболочке, можно получить командой Get-PSProvider
. Изначально в PowerShell присутствуют следующие «диски» — псевдонимы (Alias), переменные среды (Env), физические диски системы (C, D, и т. д.), функции, системный реестр, внутренние переменные (Variable) и хранилище сертификатов.
Вот пример чтения содержимого ветки реестра HKLMSoftwareMicrosoft
Как видно, использованы те же команды, что для получения сведений о файловой системе. Но структура получаемых данных, естественно, различна. Кроме названия и свойств для каждого элемента выводится номер подраздела (SKC) и номер записи (VC). С помощью PowerShell пользователь может просматривать сведения о реестре, добавлять, удалять и модифицировать ключи. Позволю привести себе что-то вроде шпаргалки по работе с элементами реестра:
И код для примера выполнения различных манипуляций с ключами реестра и их параметрами:
# Создаем новый подраздел с именем valks в ветке HKEY_CURRENT_USERSoftware
New-Item -path HKCU:Softwarevalks
# Добавляем в созданный раздел новый строковый параметр с именем Param1 и значением StringValue
New-ItemProperty -path HKCU:Softwarevalks -name Param1 -propertyType String -value StringValue
# Создадим подраздел SubFolder
New-Item -path HKCU:SoftwarevalksSubFolder
# Добавляем еще один параметр - Param2 типа DWord и значением 12
New-ItemProperty -path HKCU:Softwarevalks -name Param2 -propertyType DWord -value 12
# Получаем список всех параметров
Get-ItemProperty HKCU:Softwarevalks
# Получаем значение параметра Param2
Get-ItemProperty HKCU:Softwarevalks | Format-list Param2
# Или можем считать раздел в переменную $key
$key = Get-ItemProperty HKCU:Softwarevalks
# И вывести значение нужного параметра
Write-Host "Значение параметра Param2: " $key.Param2
# Изменим значение параметра Param2 на 193
Set-ItemProperty HKCU:Softwarevalks -name Param2 -value 193
# Изменим название параметра Param1 на Параметр1
Rename-ItemProperty -path HKCU:Softwarevalks -name Param1 -newname Параметр1
# Удаляем Параметр1
Remove-ItemProperty HKCU:Softwarevalks -name Параметр1
# Удаляем весь подраздел valks
Remove-Item HKCU:Softwarevalks
Вот еще небольшой пример в виде функции, которая осуществляет поиск программ, автоматически загружающихся при старте системы. Область поиска определяется массивом, включающим в себя некоторые известные точки автозапуска в реестре. Код содержит комментарии, надеюсь, они пояснят суть работы.
function GetAutoexec ($hives) {
# Если функции не передается входной массив ключей реестра,
# используем этот:
$hives = "HKCU:SoftwareMicrosoftWindowsCurrentVersionRun", `
"HKLM:SOFTWAREMicrosoftWindowsCurrentVersionRun", `
"HKLM:SOFTWAREMicrosoftWindowsCurrentVersionpoliciesExplorerRun"
# Выодим заголовок и переносим строку
Write-Host "Список автозагрузки`n"
# Начинаем перебирать элементы массива - ветви реестра
Foreach ($hive in $hives){
# Выводим название ветви зеленым цветом
Write-Host "Ветвь $hive" -ForegroundColor Green
# Проверяем, существует ли ветвь в реестре
if (Test-Path $hive){
# Получаем очередной ключ реестра
[Microsoft.Win32.RegistryKey]$param = Get-Item $hive
# для каждого ключа...
foreach ($p in $param){
# ...получаем список его параметров
foreach ($key in $p.getvalueNames()){
# выводим название параметра и его значение
"Загрузка $key из " + $p.GetValue($key)
}
}
}
# переносим строку
Write-Host "`n"
}
}
# осуществляем вызов самой функции
GetAutoexec
Пользователь может создавать собственные диски, используя существующие провайдеры. Вот пример создания диска PowerShell с именем Win, содержимое которого будет являться корневой папкой C:Windows
:
New-PSDrive -Name Win –PSProvider FileSystem -Root "C:Windows"
После создания диска PowerShell к нему можно обращаться точно так же , как к обычному диску системы.
Однако необходимо знать, что по завершении сеанса работы с PowerShell он будет автоматически удален. Так же, как и псевдонимы, функции и переменные, созданные пользователем в течение сеанса. Для того, чтобы сохранить перечисленные изменения, необходимо создать профиль PowerShell.
Профили PowerShell
Профиль — это файл с расширением ps1
. Фактически, это тот же скрипт, выполняемый оболочкой при ее запуске. Профили в оболочке не создаются автоматически — они должны быть созданы пользователем самостоятельно. Созданные профили будут загружаться при каждом запуске PowerShell, если политикой выполнения разрешено загружать конфигурационные файлы. Возможна обработка до четырех различных профилей. Расположение файлов в порядке последовательности их загрузки:
- %windir%system32WindowsPowerShellv1.0profile.ps1 — профиль, применяемый ко всем пользователям и оболочкам
- %windir%system32WindowsPowerShellv1.0 Microsoft.PowerShell_profile.ps1 — профиль, применяемый ко всем пользователям только оболочки PowerShell
- %UserProfile%My DocumentsWindowsPowerShellprofile.ps1 — применяется для текущего пользователя во всех оболочках
- %UserProfile%My DocumentsWindowsPowerShellMicrosoft.PowerShell_profile.ps1 — применяется для текущего пользователя только в оболочке PowerShell
Под различными оболочками здесь нужно учитывать то обстоятельство, что PowerShell может оказаться не единственным приложением, использующим файлы профилей ps1
. Некоторые интегрированные среды разработки (IDE) также могут использовать их. Один из характерных примеров — инструмент PowerGUI, разработанный Quest Software, предоставляющий средства графического интерфейса для работы с PowerShell.
Путь к профилю текущего пользователя только оболочки PowerShell хранится во встроенной переменной $profile. Для его создания выполните команду:
New-Item -Path $profile -ItemType file -force
После создания его можно открыть любым текстовым редактором, например Блокнотом:
notepad $profile
и сделать в нем необходимые изменения. Не забудьте проверить, разрешен ли политикой выполнения запуск скриптов.
Работа с объектами WMI
WMI (Windows Management Interface, интерфейс управления Windows) — набор интерфейсов для управления ОС Windows с помощью специальных компонентов. Возможно управление локальным компьютером, и находящимся в сети. WMI — разновидность Web-Based Enterprise Management (WBEM) и Common Information Model (CIM), разработанная Microsoft. Входит в состав Windows Vista, Windows Server 2003, Windows XP, Windows Me и Windows 2000. Для Windows 95 и Windows 98 доступна в виде отдельно устанавливаемого компонента. Поддерживает использование скриптовых языков, таких как VBScript или Windows PowerShell для управления персональными компьютерами и серверами, работающими под управлением Microsoft Windows.
Объекты WMI являются для PowerShell вполне «родными». Достаточно выполнить команду:
Get-WmiObject -List
чтобы увидеть большое количество классов, обеспечивающих доступ к объектам WMI в оболочке. В случае подключения к WMI на удаленном компьютере, состав классов будет зависеть от ОС и установленных на нем расширений WMI. Для получения сведений о доступных классах на удаленной машине, необходимо указать его IP-адрес или имя в качестве параметра:
Get-WmiObject -List -ComputerName Server
Для успешного подключения на удаленном компьютере должен быть запущен интерфейс WMI, а используемая учетная запись должна входить в группу локальных администраторов.
Если не использовать специальное указание, некоторые сведения не выводятся, видимо из соображений «не захламлять экран». Для получения более детальной информации можно воспользоваться командами форматирования и отбора данных.
PS C:Documents and SettingsАдминистратор> Get-WmiObject -Class Win32_OperatingSystem
SystemDirectory : C:WINDOWSsystem32
Organization : Nrest
BuildNumber : 3790
RegisteredUser : Сергей
SerialNumber : 69889-650-3137304-45684
Version : 5.2.3790
PS C:Documents and SettingsАдминистратор> Get-WmiObject -Class Win32_OperatingSystem |
Format-List Locale, Version, CurrentTimeZone, OSLanguage, InstallDate
Locale : 0419
Version : 5.2.3790
CurrentTimeZone : 180
OSLanguage : 1049
InstallDate : 20081022233211.000000+240
А вот небольшой пример опроса всех компьютеров в локальной сети с адресом 192.168.1.0 и маской подсети 255.255.255.0:
1..254|
ForEach-Object -Process
{
Get-WmiObject -Class Win32_PingStatus
-Filter ("Address='192.168.1." + $_ + "'")
-ComputerName .
} |
Select-Object -Property Address,ResponseTime,StatusCode
В первом элементе конвейера генерируется массив чисел от 1 до 254. На втором этапе каждое число из массива подставляется в IP-адрес, который будет пинговаться при помощи средств WMI. Результаты будут выводиться в таблицу с тремя столбцами — адрес хоста, время отклика и статус ответа. В случае ответа хоста возвращается статус с кодом «0».
Заключение
Конечно, в одной статье невозможно описать все возможности PowerShell. К тому же Microsoft продолжает работу над его улучшением — вторая версия должна поддерживать управление удаленными компьютерами непосредственно самой оболочкой. Ожидаются и другие нововведения. Учитывая, что PowerShell будет являться компонентом новых ОС, не приходится сомневаться в том, что сфера его применения в продуктах Microsoft будет только расширяться.
Автор выражает признательность Василию Гусеву за помощь, оказанную при подготовке статьи