Текстовий висновок команд у вікні інтерпретатора PowerShell — лише спосіб відображення інформації в придатному для людського сприйняття вигляді. Насправді середа
Зміст:
Об'єкти в PowerShell
Нагадаємо, що об'єкт - це сукупність полів даних (властивостей, подій тощо) та способів їх обробки (методів). Його структура задається типом, який зазвичай базується на класах, що використовуються в уніфікованій платформі .NET Core. Також є можливість працювати з об'єктами COM, CIM (WMI) та ADSI. Властивості та методи потрібні для виконання різних дій над даними, крім того в PowerShell об'єкти можна передавати як аргументи у функції та командлети, надавати їх значення змінним, а також існує
Перегляд структури об'єктів
Для прикладу запустимо командлет Get-Process, що дозволяє отримати інформацію про процеси, що працюють в системі:
Він виведе на екран деякі відформатовані текстові дані, що не дають уявлення про властивості об'єктів, що повертаються, і їх методи. Для тонкого препарування висновку необхідно навчитися досліджувати структуру об'єктів, і в цьому нам допоможе командлет Get-Member:
Get-Process | Get-Member
Тут ми вже бачимо тип і структуру, а за допомогою додаткових параметрів можемо, наприклад, вивести тільки властивості об'єкта, що потрапив на вхід:
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"}
Тут ми знову бачимо текстову виставу, але при бажанні зрозуміти тип і внутрішній пристрій об'єктів, що проходять через конвеєр, неважко:
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member
Сортування об'єктів
При конвеєрній обробці об'єктів часто виникає необхідність їх сортування. У командлет Sort-Object передаються імена властивостей (ключів сортування), а він повертає впорядковані за їх значенням об'єкти. Висновок запущених процесів нескладно відсортувати за витраченим процесорним часом (властивість cpu):
Get-Process | Sort-Object –Property cpu
Параметр -Property під час виклику командлета Sort-Object можна не вказувати, він використовується за замовчуванням. Для зворотного сортування застосовується параметр -Descending:
Get-Process | Sort-Object cpu -Descending
Виділення об'єктів та їх частин
Командлет Select-Object дозволяє виділити певну кількість об'єктів на початку або в кінці конвеєра за допомогою параметрів First або Last. З його допомогою можна вибрати одиничні об'єкти або певні властивості, а також створити нові об'єкти. Розберемо роботу командлета на простих прикладах.
Наступна команда виводить інформацію про 10 процесів, що споживають максимальний обсяг оперативної пам'яті (властивість WS):
Get-Process | Sort-Object WS -Descending | Select-Object -First 10
Можна виділити лише певні властивості об'єктів, що проходять через конвеєр і створити на їх основі нові:
Get-Process | Select-Object ProcessName, Id -First 1
В результаті роботи конвеєра ми отримаємо новий об'єкт, структура якого відрізнятиметься від структури Get-Process, що повертаються командлетом. Переконаємося в цьому за допомогою Get-Member:
Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member
Зверніть увагу, що Select-Object повертає одиничний об'єкт (-First 1), у якого всього два вказані поля: їх значення були скопійовані з першого переданого в конвеєр командлетом Get-Process об'єкта. На використанні Select-Object заснований один із способів створення об'єктів у сценаріях PowerShell:
$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType()
За допомогою Select-Object можна додавати об'єктам обчислювані властивості, які необхідно подати у вигляді
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}}
Подивимося на структуру об'єктів, що проходять через конвеєр:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member
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
Зазвичай розглянуті командлети використовують у інтерактивному режимі, а скриптах частіше створюються
Створення об'єктів .NET та COM (New-Object)
Є безліч програмних компонентів з інтерфейсами .NET Core та COM, які стануть у нагоді системним адміністраторам. За допомогою класу System.Diagnostics.EventLog можна керувати системними журналами безпосередньо з Windows PowerShell. Розберемо приклад створення екземпляра цього класу за допомогою командлета New-Object із параметром -TypeName:
New-Object -TypeName System.Diagnostics.EventLog
Оскільки ми не вказали певний журнал подій, отриманий екземпляр класу не містить даних. Щоб це змінити, необхідно під час створення викликати спеціальний метод-конструктор за допомогою параметра -ArgumentList. Якщо ми хочемо отримати доступ до журналу додатків, конструктор слід передати рядок «Application» як аргумент:
$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog
Зверніть увагу: вихідні дані команди ми зберегли у змінній $AppLog. Хоча в інтерактивному режимі зазвичай використовуються конвеєри, написання сценаріїв часто вимагає збереження посилання на об'єкт. Крім того, основні класи .NET Core містяться в просторі імен System: PowerShell за замовчуванням шукає в ньому зазначені типи, тому написання Diagnostics.EventLog замість System.Diagnostics.EventLog цілком коректне.
Для роботи з журналом можна звертатися до відповідних методів:
$AppLog | Get-Member -MemberType Method
Скажімо, він очищається методом 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. Вони є
[System.Environment] | Get-Member
Для перегляду статичних елементів потрібно викликати Get-Member з параметром -Static (зверніть увагу на тип об'єкта):
[System.Environment] | Get-Member -Static
Для доступу до статичних властивостей і методів використовуються дві крапки, що йдуть поспіль, замість крапки після літералу:
[System.Environment]::OSVersion
Або
$test=[System.Math]::Sqrt(25)
$test
$test.GetType()
Тип PSCustomObject
Серед численних доступних PowerShell типів даних окремо варто згадати PSCustomObject, призначений для зберігання об'єктів з довільною структурою. Створення такого об'єкта за допомогою командлета New-Object вважається класичним, але громіздким та застарілим способом:
$object = New-Object –TypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'}
Подивимося на структуру об'єкта:
$object | Get-Member
Починаючи з 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()
Один із недоліків об'єктів цього типу - порядок їх властивостей може змінитися. Щоб цього уникнути, необхідно використовувати атрибут [ordered]:
$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'
}
Є й інші варіанти створення об'єкта: ми розглянули вище використання командлета
$object | Add-Member –MemberType NoteProperty –Name Age –Value 33
$object | Get-Member
Командлет Add-Member дозволяє додавати раніше створеному об'єкту $object як властивості, а й методи з допомогою конструкції "-MemberType ScriptMethod":
$ScriptBlock = {
# код
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member
Зверніть увагу: для збереження коду нового методу ми використовували змінну $ScriptBlock типу ScriptBlock.
Для видалення властивостей використовується відповідний метод:
$object.psobject.properties.remove('Name')
Створення власних класів
У PowerShell 5.0 з'явилася можливість визначення
class MyClass
{
# тело класса
}
Це справжній тип .NET Core, у тілі якого описуються його властивості, методи та інші елементи. Розглянемо приклад визначення найпростішого класу:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
}
Для створення об'єкта (примірника класу) використовується командлет
$object = New-Object -TypeName MyClass
або
$object = [MyClass]::new()
Проаналізуємо структуру об'єкта:
$object | Get-Member
Не слід забувати про область видимості: не можна посилатися на ім'я типу у вигляді рядка або використовувати літерал типу за межами скрипта або модуля, в якому визначено клас. При цьому функції можуть повертати екземпляри класу (об'єкти), які будуть доступні поза модулем або скриптом.
Після створення об'єкта заповнимо його властивості:
$object.Name = 'Ivan Danko'
$object.City = 'Moscow'
$object.Country = 'Russia'
$object
Зазначимо, що у описі класу задаються як типи властивостей, а й значення за замовчуванням:
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)
Методи можна перевантажувати, крім того, у класу бувають
class MyClass2 : MyClass
{
#тело нового класса, базовым для которого является MyClass
}
[MyClass2]::new().Smile($true)
Наш опис роботи з об'єктами PowerShell важко назвати вичерпним. У наступних публікаціях спробуємо поглибити його на практичних прикладах: п'ята стаття циклу буде присвячена питанням інтеграції PowerShell зі сторонніми програмними компонентами. Попередні частини можна знайти за посиланнями нижче.
Джерело: habr.com