НОВОСТИ Что такое Windows PowerShell и с чем его едят? Часть 4: Работа с объектами, собственные классы

BDFpromo
Оффлайн

BDFpromo

.
.
Регистрация
23.09.18
Сообщения
12.347
Реакции
176
Репутация
0


Текстовый вывод команд в окне интерпретатора PowerShell — всего лишь способ отображения информации в пригодном для человеческого восприятия виде. На самом деле среда на работу с объектами: командлеты и функции получают их на входе и , а доступные в интерактивном режиме и в сценариях типы переменных базируются на классах .NET. В четвертой статье цикла мы изучим работу с объектами более детально.

Оглавление:













Объекты в PowerShell


Напомним, что объект — это совокупность полей данных (свойств, событий и т.д.) и способов их обработки (методов). Его структура задается типом, который как правило базируется на использующихся в унифицированной платформе .NET Core классах. Также есть возможность работать с объектами COM, CIM (WMI) и ADSI. Свойства и методы нужны для выполнения различных действий над данными, кроме того в PowerShell объекты можно передавать как аргументы в функции и командлеты, присваивать их значения переменным, а также существует (конвейер или pipeline). Каждая команда в конвейере передает свой вывод следующей поочередно — объект за объектом. Для обработки можно использовать скомпилированные командлеты или создавать собственные , чтобы производить различные манипуляции с объектами в конвейере: фильтрацию, сортировку, группировку и даже изменение их структуры. Передача данных в таком виде имеет серьезное преимущество: принимающей команде не нужно заниматься синтаксическим разбором потока байтов (текста), вся нужная информация легко извлекается с помощью обращения к соответствующим свойствам и методам.

Просмотр структуры объектов


Для примера запустим командлет Get-Process, позволяющий получить информацию о работающих в системе процессах:

4kfoqsdoj0-r5h7lz6y5ecwjskc.png


Он выведет на экран некие отформатированные текстовые данные, не дающие представления о свойствах возвращаемых объектов и их методах. Для тонкого препарирования вывода необходимо научиться исследовать структуру объектов и в этом нам поможет командлет Get-Member:


Get-Process | Get-Member

86fqttuizhkkraqk9eoh9lnrfc4.png


Здесь мы уже видим тип и структуру, а с помощью дополнительных параметров можем, например, вывести только свойства попавшего на вход объекта:


Get-Process | Get-Member -MemberType Property

Эти знания понадобятся для решения задач администрирования в интерактивном режиме или для написания собственных скриптов: скажем, чтобы получить сведения о зависших процессах по свойству Responding.

Фильтрация объектов


PowerShell позволяет пропускать по конвейеру объекты, удовлетворяющие определенному условию:


Where-Object { блок сценария }

Результатом выполнения блока сценария в операторных скобках должно быть логические значение. Если оно истинно ($true) попавший на вход командлету Where-Object объект будет передан по конвейеру дальше, в противном случае (значение $false) он будет удален. Для примера выведем список остановленных служб Windows Server, т.е. таких, у которых свойство Status имеет значение «Stopped»:


Get-Service | Where-Object {$_.Status -eq "Stopped"}

eqw6gyo6ww_hha2hw_cnbse9_ki.png


Здесь мы снова видим текстовое представление, но при желании понять тип и внутреннее устройство проходящих через конвейер объектов нетрудно:


Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member

quukuy29t6wndu8hhktdyei1rsi.png


Сортировка объектов


При конвейерной обработке объектов часто возникает необходимость их сортировки. В командлет Sort-Object передаются имена свойств (ключей сортировки), а он возвращает упорядоченные по их значениям объекты. Вывод запущенных процессов несложно отсортировать по затраченному процессорному времени (свойство cpu):


Get-Process | Sort-Object –Property cpu

Параметр -Property при вызове командлета Sort-Object можно не указывать — он используется по умолчанию. Для обратной сортировки применяется параметр -Descending:


Get-Process | Sort-Object cpu -Descending

i5-logdefolkpn4oiqab5549qac.png


Выделение объектов и их частей


Командлет Select-Object позволяет выделить определенное количество объектов в начале или в конце конвейера с помощью параметров -First или -Last. С его помощью можно выбрать единичные объекты или определенные свойства, а также создать на их основе новые объекты. Разберем работу командлета на простых примерах.

Следующая команда выводит информацию о 10 процессах, потребляющих максимальный объем оперативной памяти (свойство WS):


Get-Process | Sort-Object WS -Descending | Select-Object -First 10

uztk4gok8nqkynaqcaupcito0ri.png


Можно выделить только определенные свойства проходящих через конвейер объектов и создать на их основе новые:


Get-Process | Select-Object ProcessName, Id -First 1

В результате работы конвейера мы получим новый объект, структура которого будет отличаться от структуры возвращаемых командлетом Get-Process. Убедимся в этом при помощи Get-Member:


Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member

fw2y0cn_xin2jr571bsy1crcite.png


Обратите внимание, что Select-Object возвращает единичный объект (-First 1), у которого всего два указанных нами поля: их значения были скопированы из первого переданного в конвейер командлетом Get-Process объекта. На использовании Select-Object основан один из способов создания объектов в сценариях PowerShell:


$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType()

lfrpfonoe8e6xidulqfn8s6xfh8.png


С помощью Select-Object можно добавлять объектам вычисляемые свойства, которые необходимо представить в виде . При этом значение ее первого ключа соответствует имени свойства, а значение второго — значению свойства для текущего элемента конвейера:


Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}}

vmoq6l8umcadkrnqomarqazayms.png


Посмотрим на структуру проходящих через конвейер объектов:


Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member

zt_adfbgvhdylarb7lxrrj1gpp4.png


ForEach-Object, Group-Object и Measure-Object


Для работы с объектами существуют и другие командлеты. Для примера расскажем о трех наиболее полезных:

ForEach-Object позволяет выполнить код на языке PowerShell для каждого объекта в конвейере:


ForEach-Object { блок сценария }

Group-Object группирует объекты по значению свойства:


Group-Object PropertyName

Если запустить его с параметром -NoElement, можно узнать количество элементов в группах.

Measure-Object агрегирует различные сводные параметры по значениям полей объектов в конвейере (вычисляет сумму, а также находит минимальное, максимальное или среднее значение):


Measure-Object -Property PropertyName -Minimum -Maximum -Average -Sum

Обычно рассмотренные командлеты используются в интерактивном режиме, а в скриптах чаще создаются с блоками Begin, Process и End.

Создание объектов .NET и COM (New-Object)


Есть множество программных компонентов с интерфейсами .NET Core и COM, которые пригодятся системным администраторам. С помощью класса System.Diagnostics.EventLog можно управлять системными журналами непосредственно из Windows PowerShell. Разберем пример создания экземпляра этого класса при помощи командлета New-Object с параметром -TypeName:


New-Object -TypeName System.Diagnostics.EventLog

xuqrdgtwodglftnhuszvu4uxaws.png


Поскольку мы не указали определенный журнал событий, полученный экземпляр класса не содержит данных. Чтобы это изменить, необходимо во время его создания вызвать специальный метод-конструктор при помощи параметра -ArgumentList. Если мы хотим получить доступ к журналу приложений, в конструктор следует передать строку «Application» в качестве аргумента:


$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog

gjdlvvpxyezep9mwm180v702fb0.png


Обратите внимание: выходные данные команды мы сохранили в переменной $AppLog. Хотя в интерактивном режиме обычно используются конвейеры, написание сценариев часто требует сохранения ссылки на объект. Кроме того основные классы .NET Core содержатся в пространстве имен System: PowerShell по умолчанию ищет в нем указанные типы, поэтому написание Diagnostics.EventLog вместо System.Diagnostics.EventLog вполне корректно.

Для работы с журналом можно обращаться к соответствующим методам:


$AppLog | Get-Member -MemberType Method

t790c5xr4ripd1fr9la0euc5yym.png


Скажем очищается он методом Clear() при наличии прав доступа:


$AppLog.Clear()

Командлет New-Object применяется и для работы с СОМ-компонентами. Их довольно много — от поставляемых с сервером сценариев Windows библиотек до приложений ActiveX, таких, например, как Internet Explorer. Чтобы создать СОМ-объект, требуется задать параметр -ComObject с программным идентификатора ProgId нужного класса:


New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObject

Для создания собственных объектов с произвольной структурой использование New-Object выглядит слишком архаичным и громоздким, этот командлет используется для работы с внешними по отношению к PowerShell программными компонентами. В следующих статьях этот вопрос будет разобран более подробно. Помимо объектов .NET и COM мы также изучим объекты CIM (WMI) и ADSI.

Вызов статических методов


Экземпляры некоторых классов .NET Core создать невозможно: к их числу относятся System.Environment и System.Math. Они являются и содержат только статические свойства и методы. По сути это справочные библиотеки, которые используются без создания объектов. Сослаться на статический класс можно через литерал, заключив имя типа в квадратные скобки. При этом если посмотреть на структуру объекта с помощью Get-Member, мы увидим тип System.RuntimeType вместо System.Environment:


[System.Environment] | Get-Member

ikhek0k2z6vca22zc3eycacvo5i.png


Для просмотра только статических элементов нужно вызвать Get-Member с параметром -Static (обратите внимание на тип объекта):


[System.Environment] | Get-Member -Static

o0g7pb_kewdzes-asln_mcgslz4.png


Для доступа к статическим свойствам и методам используются два идущих подряд двоеточия вместо точки после литерала:


[System.Environment]::OSVersion

Или


$test=[System.Math]::Sqrt(25)
$test
$test.GetType()

yidacsgbamkq7sxl32r51ifmie0.png


Тип PSCustomObject


Среди многочисленных доступных в PowerShell типов данных отдельно стоит упомянуть PSCustomObject, предназначенный для хранения объектов с произвольной структурой. Создание такого объекта с помощью командлета New-Object считается классическим, но громоздким и устаревшим способом:


$object = New-Object –TypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'}


Посмотрим на структуру объекта:


$object | Get-Member

m8jrvxzu6wvnk4x2oi3bt-6w6zg.png


Начиная с PowerShell 3.0 доступен и другой синтаксис:


$object = [PSCustomObject]@{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'
}


Получить доступ к данным можно одним из эквивалентных способов:


$object.Name

$object.'Name'

$value = 'Name'
$object.$value


Приведем пример преобразования в объект существующей хэштаблицы:


$hash = @{'Name'='Ivan Danko'; 'City'='Moscow'; 'Country'='Russia'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()


m1uugarnq3obtfdapd18xzqecva.png


Один из недостатков объектов этого типа — порядок их свойств может поменяться. Чтобы этого избежать, необходимо использовать атрибут [ordered]:


$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'
}


Есть и другие варианты создания объекта: выше мы рассмотрели использование командлета . Осталось разобраться с добавлением и удалением элементов. Сделать это для объекта из предыдущего примера довольно просто:


$object | Add-Member –MemberType NoteProperty –Name Age –Value 33
$object | Get-Member


au3vfg5kkxvcg9hhotimmx_viog.png


Командлет Add-Member позволяет добавлять ранее созданному объекту $object не только свойства, но и методы посредством использования конструкции "-MemberType ScriptMethod":


$ScriptBlock = {
# код
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member


Обратите внимание: для хранения кода нового метода мы использовали переменную $ScriptBlock типа ScriptBlock.

1kh7umvv2w2ralp_6xwyxvhq2za.png


Для удаления свойств используется соответствующий метод:


$object.psobject.properties.remove('Name')

Создание собственных классов


В PowerShell 5.0 появилась возможность определения с использованием характерного для объектно-ориентированных языков программирования синтаксиса. Для этого предназначено служебное слово Class, после которого следует задать имя класса и описать его тело в операторных скобках:


class MyClass
{
# тело класса
}


Это настоящий тип .NET Core, в теле которого описываются его свойства, методы и другие элементы. Рассмотрим пример определения простейшего класса:


class MyClass
{
[string]$Name
[string]$City
[string]$Country
}


Для создания объекта (экземпляра класса) используется командлет , либо литерал типа [MyClass] и new (конструктор по умолчанию):


$object = New-Object -TypeName MyClass

или


$object = [MyClass]::new()

Проанализируем структуру объекта:


$object | Get-Member

gkptprl6q2cwswt7lsdb2-0e_w8.png


Не стоит забывать про область видимости: нельзя ссылаться на имя типа в виде строки или использовать литерал типа за пределами скрипта или модуля, в котором определен класс. При этом функции могут возвращать экземпляры класса (объекты), которые будут доступны вне модуля или скрипта.

После создания объекта заполним его свойства:


$object.Name = 'Ivan Danko'
$object.City = 'Moscow'
$object.Country = 'Russia'
$object


tjx4sqnhix6a4d7wmd_kqahdnj0.png


Отметим, что в описании класса задаются не только типы свойств, но и их значения по умолчанию:


class Example
{
[string]$Name = 'John Doe'
}


Описание метода класса напоминает описание функции, но без использования служебного слова function. Как и в функции, в методы при необходимости передаются параметры:


class MyClass
{
[string]$Name
[string]$City
[string]$Country

#описание метода
Smile([bool]$param1)
{
If($param1) {
Write-Host ':)'
}
}
}


Теперь представитель нашего класса умеет улыбаться:


$object = [MyClass]::new()
$object.Smile($true)


Методы можно перегружать, кроме того у класса бывают , а также конструкторы, имена которых совпадают с именем самого класса. Определенный в скрипте или модуле PowerShell класс может служить базовым для другого — так реализуется наследование. При этом в качестве базовых допускается использование существующих классов .NET:


class MyClass2 : MyClass
{
#тело нового класса, базовым для которого является MyClass
}
[MyClass2]::new().Smile($true)


Наше описание работы с объектами в PowerShell трудно назвать исчерпывающем. В следующих публикациях попробуем его углубить на практических примерах: пятая статья цикла будет посвящена вопросам интеграции PowerShell со сторонними программными компонентами. Прошлые части можно найти по ссылкам ниже.






 
Сверху Снизу