Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

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

Зміст:

Об'єкти в PowerShell
Перегляд структури об'єктів
Фільтрування об'єктів
Сортування об'єктів
Виділення об'єктів та їх частин
ForEach-Object, Group-Object та Measure-Object
Створення об'єктів .NET та COM (New-Object)
Виклик статичних методів
Тип PSCustomObject
Створення власних класів

Об'єкти в PowerShell

Нагадаємо, що об'єкт - це сукупність полів даних (властивостей, подій тощо) та способів їх обробки (методів). Його структура задається типом, який зазвичай базується на класах, що використовуються в уніфікованій платформі .NET Core. Також є можливість працювати з об'єктами COM, CIM (WMI) та ADSI. Властивості та методи потрібні для виконання різних дій над даними, крім того в PowerShell об'єкти можна передавати як аргументи у функції та командлети, надавати їх значення змінним, а також існує механізм композиції команд (Конвеєр або pipeline). Кожна команда в конвеєрі передає свій висновок по черзі — об'єкт за об'єктом. Для обробки можна використовувати скомпіловані командлети або створювати власні розширені функції, щоб проводити різні маніпуляції з об'єктами в конвеєрі: фільтрацію, сортування, угруповання та навіть зміна їх структури. Передача даних у такому вигляді має серйозну перевагу: команді, що приймає, не потрібно займатися синтаксичним розбором потоку байтів (тексту), вся потрібна інформація легко витягується за допомогою звернення до відповідних властивостей і методів.

Перегляд структури об'єктів

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Він виведе на екран деякі відформатовані текстові дані, що не дають уявлення про властивості об'єктів, що повертаються, і їх методи. Для тонкого препарування висновку необхідно навчитися досліджувати структуру об'єктів, і в цьому нам допоможе командлет Get-Member:

Get-Process | Get-Member

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Тут ми вже бачимо тип і структуру, а за допомогою додаткових параметрів можемо, наприклад, вивести тільки властивості об'єкта, що потрапив на вхід:

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"}

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Тут ми знову бачимо текстову виставу, але при бажанні зрозуміти тип і внутрішній пристрій об'єктів, що проходять через конвеєр, неважко:

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Сортування об'єктів

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

Get-Process | Sort-Object –Property cpu

Параметр -Property під час виклику командлета Sort-Object можна не вказувати, він використовується за замовчуванням. Для зворотного сортування застосовується параметр -Descending:

Get-Process | Sort-Object cpu -Descending

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Виділення об'єктів та їх частин

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

Наступна команда виводить інформацію про 10 процесів, що споживають максимальний обсяг оперативної пам'яті (властивість WS):

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Можна виділити лише певні властивості об'єктів, що проходять через конвеєр і створити на їх основі нові:

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

В результаті роботи конвеєра ми отримаємо новий об'єкт, структура якого відрізнятиметься від структури Get-Process, що повертаються командлетом. Переконаємося в цьому за допомогою Get-Member:

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

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

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

За допомогою Select-Object можна додавати об'єктам обчислювані властивості, які необхідно подати у вигляді хеш-таблиці. При цьому значення першого ключа відповідає імені властивості, а значення другого - значенню властивості для поточного елемента конвеєра:

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Подивимося на структуру об'єктів, що проходять через конвеєр:

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Оскільки ми не вказали певний журнал подій, отриманий екземпляр класу не містить даних. Щоб це змінити, необхідно під час створення викликати спеціальний метод-конструктор за допомогою параметра -ArgumentList. Якщо ми хочемо отримати доступ до журналу додатків, конструктор слід передати рядок «Application» як аргумент:

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Зверніть увагу: вихідні дані команди ми зберегли у змінній $AppLog. Хоча в інтерактивному режимі зазвичай використовуються конвеєри, написання сценаріїв часто вимагає збереження посилання на об'єкт. Крім того, основні класи .NET Core містяться в просторі імен System: PowerShell за замовчуванням шукає в ньому зазначені типи, тому написання Diagnostics.EventLog замість System.Diagnostics.EventLog цілком коректне.

Для роботи з журналом можна звертатися до відповідних методів:

$AppLog | Get-Member -MemberType Method

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Скажімо, він очищається методом 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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Для перегляду статичних елементів потрібно викликати Get-Member з параметром -Static (зверніть увагу на тип об'єкта):

[System.Environment] | Get-Member -Static

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

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

[System.Environment]::OSVersion

Або

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Тип PSCustomObject

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

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

Подивимося на структуру об'єкта:

$object | Get-Member

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Починаючи з 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()

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Один із недоліків об'єктів цього типу - порядок їх властивостей може змінитися. Щоб цього уникнути, необхідно використовувати атрибут [ordered]:

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

Є й інші варіанти створення об'єкта: ми розглянули вище використання командлета Select-Object. Залишилося розібратися з додаванням та видаленням елементів. Зробити це для об'єкта з попереднього прикладу досить просто:

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Командлет Add-Member дозволяє додавати раніше створеному об'єкту $object як властивості, а й методи з допомогою конструкції "-MemberType ScriptMethod":

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

Зверніть увагу: для збереження коду нового методу ми використовували змінну $ScriptBlock типу ScriptBlock.

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Для видалення властивостей використовується відповідний метод:

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

Створення власних класів

У PowerShell 5.0 з'явилася можливість визначення класів з використанням характерного для об'єктно орієнтованих мов програмування синтаксису. Для цього призначено службове слово Class, після якого слід задати ім'я класу та описати його тіло в операторних дужках:

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

Це справжній тип .NET Core, у тілі якого описуються його властивості, методи та інші елементи. Розглянемо приклад визначення найпростішого класу:

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

Для створення об'єкта (примірника класу) використовується командлет New-Object, або літерал типу [MyClass] та псевдостатичний метод new (конструктор за замовчуванням):

$object = New-Object -TypeName MyClass

або

$object = [MyClass]::new()

Проаналізуємо структуру об'єкта:

$object | Get-Member

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Не слід забувати про область видимості: не можна посилатися на ім'я типу у вигляді рядка або використовувати літерал типу за межами скрипта або модуля, в якому визначено клас. При цьому функції можуть повертати екземпляри класу (об'єкти), які будуть доступні поза модулем або скриптом.

Після створення об'єкта заповнимо його властивості:

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

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Зазначимо, що у описі класу задаються як типи властивостей, а й значення за замовчуванням:

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 зі сторонніми програмними компонентами. Попередні частини можна знайти за посиланнями нижче.

Частина 1: основні можливості Windows PowerShell
Частина 2: введення в мову програмування Windows PowerShell
Частина 3: передача параметрів у скрипти та функції, створення командлетів

Що таке Windows PowerShell та з чим його їдять? Частина 4: Робота з об'єктами, власні класи

Джерело: habr.com

Додати коментар або відгук