В операционных системах 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:\Windows\System32\notepad.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. Для однозначной идентификации экземпляра класса (объекта) и описания состояния соответствующего ему ресурса используются свойства класса, которые обычно доступны только для чтения. Для управления ресурсом используются методы.
К экземпляру класса можно обратиться по полному пути, который имеет следующий вид:
[\\ComputerName\NameSpace][: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 подключаются к пространству имен Root\CIMV2, в котором хранится большое количество классов для управления системой. Для смены пространства имен применяется параметр -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("$Home\Desktop\Home.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: Работа с объектами, собственные классы