Перейти к основному содержимому

Объектная модель и конвейерная обработка

Разработчику Архитектору

Объектная модель и конвейерная обработка

Основы объектной модели PowerShell

PowerShell представляет собой среду автоматизации, основанную на объектно-ориентированной архитектуре .NET Framework. В отличие от традиционных оболочек командной строки, таких как CMD или Bash, которые оперируют исключительно текстовыми потоками данных, PowerShell работает с полноценными объектами. Каждый результат выполнения команды является экземпляром класса, обладающим свойствами, методами и событиями.

Объект — это экземпляр класса, инкапсулирующий данные (свойства) и поведение (методы). В контексте PowerShell объект хранит информацию о конкретном элементе системы, приложении или ресурсе. Например, процесс запущенного приложения — это объект типа Система.Diagnostics.Process. Этот объект содержит свойства, такие как Id, Name, Path, StartTime, а также методы, позволяющие управлять процессом, например Kill(), WaitForExit(), Restart().

При выполнении команды в PowerShell система не просто выводит текст на экран. Она создает объект в памяти, заполняет его данными, а затем преобразует этот объект в строку только для отображения пользователю. Это фундаментальное отличие позволяет передавать объекты между командами без потери информации и структуры данных.

Все объекты в PowerShell наследуются от базового класса Система.Object. Каждый объект обладает набором стандартных свойств, доступных по умолчанию:

  • PSObject — ссылка на сам объект;
  • GetType() — метод, возвращающий информацию о типе объекта;
  • ToString() — метод, преобразующий объект в строковое представление;
  • Equals() — метод сравнения объектов;
  • GetHashCode() — метод получения хеш-кода объекта.

Пользователь может исследовать структуру любого объекта, используя команду Get-Member. Эта команда выводит список всех доступных свойств и методов конкретного объекта.

Get-Process | Get-Member -Type Property | Select-Object Name

Вывод этой команды покажет перечень имен всех свойств, доступных для объектов процессов. Пользователь может фильтровать вывод, указывая конкретные типы членов (-Type Method, -Type ScriptProperty, -Type NoteProperty).

Свойства объектов делятся на несколько категорий:

  • NoteProperties — пользовательские свойства, добавленные динамически;
  • ScriptProperties — свойства, значение которых вычисляется скриптом;
  • CodeProperties — свойства, реализованные через код .NET;
  • MethodProperties — свойства, представляющие методы;
  • DynamicProperties — свойства, создаваемые во время выполнения.

Методы объектов выполняют действия. Вызов метода осуществляется указанием имени метода и скобок с параметрами. Пример вызова метода Stop() у объекта процесса:

$process = Get-Process notepad
$process.Stop()

Объекты могут быть сложными и содержать вложенные структуры. Например, объект веб-запроса может содержать свойство Response, которое само является объектом с собственными свойствами и методами. Такая иерархическая структура позволяет глубоко взаимодействовать с системой.

Типизация объектов в PowerShell строго следует принципам языка C#. Каждый объект имеет определенный тип, который определяет набор доступных ему операций. При работе с объектами важно понимать их тип, чтобы корректно использовать свойства и методы. Ошибки в типизации приводят к исключению运行时 (RuntimeException), которое прерывает выполнение скрипта.


Конвейерная обработка данных

Конвейер (pipeline) в PowerShell — это механизм передачи объектов из одной команды в другую. Символ вертикальной черты | обозначает начало конвейера. Данные, поступающие на вход конвейера, называются входными данными, а команды, обрабатывающие эти данные, — потребителями.

В отличие от других оболочек, где конвейер передает текст, PowerShell передает объекты. Команда, стоящая слева от символа |, генерирует объекты, которые передаются команде справа. Правая команда принимает эти объекты и выполняет над ними свои операции. Если правая команда ожидает конкретный тип объекта, она автоматически пытается привести входящие данные к этому типу.

Пример работы конвейера:

Get-Service | Where-Object {$_.Status -eq "Running"} | Select-Object Name, Status

В этом примере:

  1. Get-Service получает список всех служб Windows и создает объекты типа Система.ServiceProcess.ServiceController;
  2. Where-Object принимает каждый объект службы, проверяет свойство Status и пропускает только те, где значение равно "Running";
  3. Select-Object принимает оставшиеся объекты и формирует новый объект, содержащий только свойства Name и Status.

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

Конвейер поддерживает параллельную обработку. Если команда потребляет объекты, она может обрабатывать их по мере поступления, не дожидаясь завершения работы всей предыдущей команды. Это особенно полезно при работе с большими объемами данных, когда загрузка всех объектов в память перед обработкой нецелесообразна.

Существуют специальные параметры управления поведением конвейера:

  • -InputObject — явное указание входного объекта;
  • -PipelineVariable — сохранение промежуточных результатов в переменную;
  • -Continue — продолжение обработки после ошибки;
  • -ErrorAction — управление обработкой ошибок внутри конвейера.

Команды могут иметь разные требования к входным данным. Некоторые принимают объекты напрямую, другие ожидают значения конкретных типов. PowerShell автоматически выполняет приведение типов, если это возможно. Например, строка "42" может быть автоматически преобразована в целое число 42 при необходимости.

Для проверки того, какие типы данных принимает команда, используется параметр -ParameterSetInfo или изучение документации. Понимание требований к входным данным критично для построения эффективных конвейеров.


Передача объектов через конвейер

Передача объектов через конвейер происходит без сериализации в строку. Объект сохраняется в своей исходной форме и передается следующим командам в виде ссылки на память. Это означает, что все свойства и методы остаются доступными на протяжении всего конвейера.

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

Пример модификации объекта в конвейере:

Get-Process | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name "CustomValue" -Value ($_.CPU * 2) -PassThru
}

В этом коде создается новое свойство CustomValue для каждого объекта процесса, значение которого рассчитывается на основе свойства CPU. Параметр -PassThru гарантирует, что модифицированный объект будет передан дальше по конвейеру.

Свойство $_ (или $_) представляет текущий элемент потока данных, проходящего через конвейер. Это встроенная переменная, доступная внутри блоков ForEach-Object, Where-Object и других команд, работающих с потоком.

Использование $_ позволяет обращаться к свойствам текущего объекта без необходимости создавать временные переменные. Это делает код более лаконичным и эффективным.

Get-ChildItem | Where-Object { $_.Length -gt 1MB } | Select-Object Name, Length

Здесь $_ ссылается на каждый объект файла, создаваемый командой Get-ChildItem. Условие проверяет размер файла, а Select-Object формирует итоговый отчет.

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

Важно помнить, что порядок команд в конвейере влияет на результат. Команды, выполняющие фильтрацию, должны стоять до команд, выполняющих тяжелые операции, чтобы сократить объем обрабатываемых данных. Команды сортировки обычно ставятся в конце, так как они требуют наличия полного набора данных.


Работа со свойствами и методами объектов

Работа со свойствами и методами объектов является основной задачей при написании скриптов PowerShell. Доступ к свойствам осуществляется через точку, а к методам — через точку с круглыми скобками.

$service = Get-Service -Name "wuauserv"
$serviceName = $service.Name
$serviceStatus = $service.Status
$service.Stop()

В этом примере:

  • $service — переменная, хранящая объект службы;
  • $service.Name — обращение к свойству Name;
  • $service.Status — обращение к свойству Status;
  • $service.Stop() — вызов метода Stop().

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

Методы могут принимать параметры. Параметры указываются в скобках после имени метода, разделенные запятыми.

$file = Get-Item -Path "C:\Temp\test.txt"
$file.CopyTo("C:\Backup\test.txt", $true)

Метод CopyTo принимает два параметра: путь назначения и флаг перезаписи. Результат выполнения метода возвращается в переменную, если это требуется.

Некоторые методы возвращают сложные объекты. Например, метод Invoke-WebRequest возвращает объект System.Net.HttpWebResponse, который содержит множество свойств и методов для анализа ответа сервера.

$response = Invoke-WebRequest -Uri "https://example.com"
$content = $response.Content
$status = $response.StatusCode

Доступ к свойствам вложенных объектов осуществляется через цепочку точек.

$process = Get-Process -Id 1234
$module = $process.Modules[0]
$moduleName = $module.ModuleName

В этом примере Modules — свойство, содержащее массив модулей. Индекс [0] выбирает первый модуль из массива.

Для динамического добавления свойств используется cmdlet Add-Member. Это позволяет расширять функциональность объектов без изменения их исходного кода.

$person = New-Object PSObject
$person | Add-Member -MemberType NoteProperty -Name "Name" -Value "John"
$person | Add-Member -MemberType NoteProperty -Name "Age" -Value 30

Созданный объект теперь имеет два свойства: Name и Age. Такие объекты часто используются для формирования структурированных данных, которые можно экспортировать в файлы или передать другим системам.


Фильтрация и выборка данных

Фильтрация данных в PowerShell осуществляется с помощью команд Where-Object и Select-Object. Эти команды работают в связке с конвейером и позволяют извлекать нужные элементы из потока данных.

Команда Where-Object применяет условие к каждому объекту в потоке и пропускает только те, которые соответствуют условию. Условие указывается в блоке скрипта {...}.

Get-Process | Where-Object { $_.CPU -gt 100 }

Это выражение фильтрует процессы, у которых потребление процессорного времени превышает 100 единиц.

Условия могут быть сложными и включать логические операторы:

  • -eq — равно;
  • -ne — не равно;
  • -gt — больше;
  • -ge — больше или равно;
  • -lt — меньше;
  • -le — меньше или равно;
  • -like — соответствует шаблону;
  • -match — соответствует регулярному выражению;
  • -and — логическое И;
  • -or — логическое ИЛИ;
  • -not — логическое НЕ.
Get-Service | Where-Object { $_.Status -eq "Running" -and $_.DisplayName -like "*Windows*" }

Эта команда находит службы со статусом "Running" и именем, содержащим слово "Windows".

Команда Select-Object выбирает определенные свойства из объектов. Если свойства не указаны, команда возвращает все свойства, но в сокращенном формате.

Get-Process | Select-Object Id, Name, CPU

Эта команда выводит только три свойства каждого процесса: идентификатор, имя и использование процессора.

Для выбора свойств по маске используется параметр -Property.

Get-Service | Select-Object -Property *Status*

Это выберет все свойства, содержащие слово "Status" в названии.

Комбинация Where-Object и Select-Object позволяет создавать мощные запросы к данным.

Get-ChildItem -Recurse | Where-Object { $_.Length -gt 1GB } | Select-Object FullName, Length, LastWriteTime

Этот скрипт ищет файлы размером более 1 ГБ, рекурсивно просматривая все поддиректории, и выводит их имена, размеры и дату последнего изменения.


Группировка и агрегация данных

Группировка данных позволяет объединять объекты по определенным признакам. Команда Group-Object разделяет поток данных на группы на основе значений указанного свойства.

Get-Service | Group-Object DisplayName

Эта команда группирует службы по имени дисплея. Для каждой группы создается объект, содержащий ключевое значение и список элементов группы.

Результат работы Group-Object имеет следующие свойства:

  • Count — количество элементов в группе;
  • Name — значение свойства, по которому выполнена группировка;
  • Group — массив объектов, входящих в группу.
Get-Service | Group-Object DisplayName | Select-Object Count, Name

Это выведет количество служб для каждого уникального имени дисплея.

Агрегация данных выполняется с помощью функций Measure-Object, Sum, Average, Min, Max. Эти функции работают с числовыми значениями свойств.

Get-Process | Measure-Object -Property CPU -Sum

Эта команда подсчитывает сумму использования процессора всеми процессами.

Get-Process | Measure-Object -Property WorkingSet -Minimum, Maximum, Average

Вычисляются минимальное, максимальное и среднее значение рабочей памяти для всех процессов.

Комбинация группировки и агрегации позволяет получать сводную статистику.

Get-Process | Group-Object Name | ForEach-Object {
[PSCustomObject]@{
ProcessName = $_.Name
Count = $_.Count
TotalCPU = ($_.Group | Measure-Object CPU -Sum).Sum
}
}

Этот скрипт группирует процессы по имени, считает количество экземпляров каждого процесса и суммарное потребление ими процессорного времени.


Трансформация и преобразование данных

Трансформация данных включает изменение формата, структуры или содержания объектов. Команда ForEach-Object позволяет применять произвольную логику к каждому элементу потока.

Get-Process | ForEach-Object {
[PSCustomObject]@{
Id = $_.Id
Name = $_.Name
MemoryMB = [math]::Round($_.WorkingSet / 1MB, 2)
}
}

В этом примере создается новый объект для каждого процесса. Свойство MemoryMB вычисляется путем деления рабочей памяти на 1 МБ и округления до двух знаков после запятой. Использование [PSCustomObject] позволяет создать объект с произвольными свойствами.

Преобразование типов данных осуществляется через приведение типов.

$number = "123"
$intValue = [int]$number

Строка "123" преобразуется в целое число 123.

Форматирование чисел и дат выполняется с использованием специальных операторов.

$price = 1234.5678
$formattedPrice = "{0:C}" -f $price

Число форматируется как валюта.

Сортировка данных осуществляется командой Sort-Object.

Get-Process | Sort-Object CPU -Descending | Select-Object -First 5

Эта команда сортирует процессы по использованию процессора в порядке убывания и выбирает первые пять.

Сортировка может выполняться по нескольким полям.

Get-ChildItem | Sort-Object Directory, Name

Сначала сортировка по директории, затем по имени файла.


Обработка ошибок в конвейере

Обработка ошибок в конвейере требует понимания поведения команд при возникновении проблем. По умолчанию PowerShell останавливает выполнение скрипта при ошибке, которая не была обработана.

Параметр -ErrorAction управляет реакцией на ошибки. Возможные значения:

  • Stop — остановить выполнение (по умолчанию);
  • Continue — продолжить выполнение, вывести сообщение об ошибке;
  • SilentlyContinue — продолжить выполнение без вывода сообщения;
  • Ignore — проигнорировать ошибку полностью.
Get-Item -Path "C:\NonExistentFile" -ErrorAction SilentlyContinue

Эта команда не выведет ошибку, если файл не найден, и продолжит выполнение.

Команда Try-Catch позволяет перехватывать исключения и обрабатывать их программно.

try {
Get-Service -Name "NonExistentService"
} catch {
Write-Host "Ошибка: $_"
}

Блок catch выполняется, если возникает ошибка. Переменная $_ содержит описание ошибки.

Обработка ошибок в конвейере возможна с помощью параметра -ErrorVariable.

Get-Service -Name "Test" -ErrorVariable err -ErrorAction SilentlyContinue
if ($err) {
Write-Host "Произошли ошибки: $($err.Count)"
}

Этот подход позволяет собрать все ошибки в массив и обработать их позже.

Для контроля потока выполнения используется конструкция If с проверкой результата команды.

if (Get-Service -Name "W32Time") {
Write-Host "Служба найдена"
} else {
Write-Host "Служба не найдена"
}

Такой подход позволяет строить условную логику на основе наличия или отсутствия объектов.


Продвинутые техники работы с объектами

Продвинутые техники включают работу с коллекциями, лямбда-выражениями и динамическими свойствами. Коллекции в PowerShell представлены типами Система.Collections.Generic.List<T>, ArrayList, Hashtable.

$list = New-Object Система.Collections.Generic.List[string]
$list.Add("Element1")
$list.Add("Element2")

Список поддерживает методы добавления, удаления, поиска и сортировки.

Лямбда-выражения позволяют создавать анонимные функции.

$filter = { $_.Status -eq "Running" }
Get-Service | Where-Object $filter

Переменная $filter хранит блок кода, который передается команде Where-Object.

Динамические свойства добавляются с помощью Add-Member с параметром -Force.

$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "Prop1" -Value "Value1"
$obj | Add-Member -MemberType NoteProperty -Name "Prop1" -Value "NewValue1" -Force

Параметр -Force позволяет переопределить существующее свойство.

Работа с пространством имен Система.Management.Автоматизация дает доступ к внутренним механизмам PowerShell.

using namespace Система.Management.Автоматизация
$cmd = Get-Command Get-Process
$cmd.Parameters["Name"].DefaultValue

Это позволяет анализировать параметры команд и их значения по умолчанию.

Интеграция с внешними API осуществляется через создание объектов HttpRequestMessage и отправку запросов.

$request = New-Object System.Net.Http.HttpRequestMessage
$request.Method = [System.Net.Http.HttpMethod]::Get
$request.RequestUri = "https://api.example.com/Данные"
$client = New-Object System.Net.Http.HttpClient
$response = $client.SendAsync($request).Result
$content = $response.Content.ReadAsStringAsync().Result

Этот код отправляет HTTP-запрос и получает ответ в виде строки.


Примеры использования

Практическое применение объектной модели и конвейера охватывает широкий спектр задач администрирования и разработки.

Пример сбора информации о системе:

[Система.Collections.ArrayList]$systemInfo = @()
$os = Get-WmiObject Win32_OperatingSystem
$cpu = Get-WmiObject Win32_Processor
$memory = Get-WmiObject Win32_PhysicalMemory

foreach ($mem in $memory) {
$systemInfo.Add([PSCustomObject]@{
Component = "RAM"
SizeGB = [math]::Round($mem.Capacity / 1GB, 2)
Manufacturer = $mem.Manufacturer
}) | Out-Null
}

foreach ($proc in $cpu) {
$systemInfo.Add([PSCustomObject]@{
Component = "CPU"
Model = $proc.Name
Cores = $proc.NumberOfCores
Threads = $proc.NumberOfLogicalProcessors
}) | Out-Null
}

$systemInfo | Format-Table -AutoSize

Этот скрипт собирает информацию об оперативной памяти и процессорах, формирует единый объект и выводит таблицу.

Пример мониторинга дискового пространства:

Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Used -gt 0 } | ForEach-Object {
$usedPercent = ([math]::Round(($_.Used / ($_.Used + $_.Free)) * 100, 2))
if ($usedPercent -gt 90) {
Write-Warning "Диск $($_.Name) заполнен на $usedPercent%"
} elseif ($usedPercent -gt 80) {
Write-Host "Диск $($_.Name) заполнен на $usedPercent% (внимание)" -ForegroundColor Yellow
} else {
Write-Host "Диск $($_.Name) заполнен на $usedPercent% (норма)" -ForegroundColor Green
}
}

Скрипт анализирует использование дисков и выдает цветовую индикацию в зависимости от уровня заполнения.

Пример создания отчета о пользователях:

Get-LocalUser | Where-Object { $_.Enabled } | Select-Object Name, LastLogon, @{Name="LastLogonDate";Expression={[DateTime]::Parse($_.LastLogon)}} | Sort-Object LastLogonDate -Descending | Format-Table -AutoSize

Отчет показывает активных пользователей с датами последнего входа, отсортированными по убыванию.

Пример автоматизации резервного копирования:

$source = "C:\Данные"
$destination = "D:\Backup\$(Get-Date -Format 'yyyy-MM-dd')"
if (!(Test-Path $destination)) {
New-Item -ItemType Directory -Path $destination -Force | Out-Null
}
Copy-Item -Path "$source\*" -Destination $destination -Recurse -Force
Write-Host "Резервное копирование завершено в $destination"

Скрипт создает папку с текущей датой и копирует туда все файлы из источника.

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


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).