Возвращение к основам: понимание объектов PowerShell

PowerShell – это мощный язык. Но что делает этот язык сценариев таким мощным? Объекты PowerShell. Что это за волшебные объекты и как PowerShell работает с ними? Оставайтесь с нами, чтобы узнать.

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

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

Если вы предпочитаете визуальное обучение, можете посмотреть видео-компаньон этой статьи ниже.

Пристегните ремни! Вас ждет запоминающийся опыт, который поможет вам овладеть концепцией объектов в PowerShell!

Предварительные требования

В этой статье вы узнаете о объектах в PowerShell с помощью практического подхода. Если вы решите следовать и пробовать примеры кода, Windows PowerShell 5.1 или любая версия PowerShell 6+ должны работать. Однако все примеры, которые вы увидите, будут выполнены в Windows 10 сборка 1903 с Windows PowerShell 5.1.

Понимание анатомии объекта

Объекты повсюду в PowerShell. Возможно, вы задаетесь вопросом: «Как выглядит объект?» В этом первом разделе вы получите обзор того, из чего состоит объект. Как только вы получите общую картину того, что делает объект объектом, вы сможете приступить к примерам кода!

Открытие членов объекта с помощью Get-Member

У объектов есть множество различных типов информации, связанной с ними. В PowerShell эта информация иногда называется членами. Член объекта – это общий термин, который относится ко всей информации, связанной с объектом.

Чтобы узнать информацию о объекте (членах), вы можете использовать командлет Get-Member. Командлет Get-Member – это удобная команда, которая позволяет найти доступные свойства, методы и т. д. для любого объекта в PowerShell.

Например, предположим, вы хотите просмотреть члены для определенного объекта, возвращенного с помощью командлета Get-Service. Вы можете сделать это, направив вывод команды Get-Service на командлет Get-Member, как показано ниже.

language-powershell
Get-Service -ServiceName 'BITS' | Get-Member

Привыкайте к командлету Get-Member. Вы будете использовать его очень часто в этой статье.

Каждая команда в PowerShell, которая производит вывод, может быть направлена на Get-Member. Просто помните, что нужно разместить этот командлет в самом конце конвейера, так как он перезапишет вывод своим собственным выводом.

Типы объектов и классы

Без вдавання в деталі об’єктно-орієнтованого програмування, кожен об’єкт має “схему”. “Схема” об’єкта – це шаблон, в якому міститься чертіж для створення об’єкта. Цей чертіж називається типом.

Кожен об’єкт в PowerShell має певний тип. Кожен об’єкт має чертіж, за яким він був створений. Тип об’єкта визначається класом. Розгляньте цей приклад: 9 – це число, Bluegill – це риба, Labrador – це собака, і т. д. Клас йде перед типом.

Об’єкти є екземплярами класів певного типу.

Не хвилюйтесь занадто багато про цю тему. Якщо ви не є розробником програмного забезпечення, вам, ймовірно, не потрібно докладно заморочуватися семантикою на цьому етапі. Однак це важливе поняття, про яке слід знати на базовому рівні.

Властивості

Найважливіша концепція, яку ви повинні розуміти про об’єкти, – це властивості. Властивості – це атрибути, які описують об’єкт. Об’єкт може мати багато різних властивостей, що представляють різні атрибути.

Одним з найпростіших способів виявити, які властивості є у об’єктів, є використання команди Get-Member. Ви можете побачити нижче, що за допомогою параметра MemberType команда Get-Member обмежить вивід, повернутий лише об’єктами. Ви також побачите, що вона відображає тип об’єкта System.ServiceProcess.ServiceController.

PS51> Get-Service | Get-Member -MemberType Property
Get-Service object properties

Теперь рассмотрим пример службы BITS, рассмотренной ранее, и просмотрим конкретные значения свойств этого объекта, используя следующий код. Команда Get-Member позволяет найти имена свойств, но не их значения. Однако, используя команду Select-Object в PowerShell, можно проверить значения свойств.

Ниже вы можете видеть, что StartType – это свойство объекта. Возвращенный объект имеет много разных элементов, но с помощью команды Select-Object вывод ограничен только показом этого свойства.

PS51> Get-Service -ServiceName 'BITS' | Select-Object -Property 'StartType'
BITS service start type

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

Псевдонимы

Некоторые свойства имеют MemberType с типом Alias. Псевдонимы являются псевдонимами для имен свойств. Иногда они могут давать свойствам более интуитивные имена.

Вы можете увидеть пример объекта со свойствами-псевдонимами, используя команду Get-Service снова, как показано ниже. Свойство Name имеет псевдоним ServiceName, а RequiredServices имеет псевдоним для свойства ServicesDependedOn.

PS51> Get-Service | Get-Member -MemberType 'AliasProperty'
AliasProperty members on service objects

Когда свойство имеет псевдоним, вы можете обращаться к значению этого свойства, используя имя псевдонима, а не фактическое имя свойства. В этом примере описательный атрибут, такой как Name и RequiredServices, более интуитивен и легче набирать, чем ServiceName и ServicesDependedOn.

Ниже приведен пример использования этих псевдонимов.

# Используйте AliasProperty вместо реального имени свойства
PS51> $Svc = Get-Service -ServiceName 'BITS' # Объект, с которым вы работаете
PS51> $Svc.Name
BITS
PS51> $Svc.RequiredServices

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

Properties on the BITS service object

Методы

Свойства – это только одна часть, создающая объект; методы также являются важным концептом для понимания. Методы – это действия, которые можно выполнить с объектом. Как и свойства, вы можете узнать о методах объекта, используя командлет Get-Member.

Чтобы ограничить вывод Get-Member только методами, установите значение параметра MemberType равным Method, как показано ниже.

PS51> Get-Service | Get-Member -MemberType 'Method'
Methods on service objects

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

Другие типы членов

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

Для полноты ниже приведены еще несколько типов членов, с которыми вы можете столкнуться.

  • Script Property – используются для вычисления значений свойств.
  • Note Property – используются для статических имен свойств.
  • Наборы свойств – это аналоги, содержащие то, что подразумевает их название; наборы свойств. Например, вы создали пользовательское свойство с именем Specs для вашей функции Get-CompInfo. Specs фактически является подмножеством свойств Cpu, Mem, Hdd, IP. Основная цель наборов свойств – предоставить одно имя свойства для объединения группы свойств.

Также важно упомянуть понятие событий объекта. События выходят за рамки этой статьи.

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

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

Многие команды PowerShell генерируют вывод, но иногда вам не нужно видеть весь этот вывод. Вам нужно ограничить или somehow изменить этот вывод. К счастью, в PowerShell есть несколько команд, которые позволяют вам это сделать.

Давайте начнем с примера перечисления всех служб на локальном компьютере с использованием cmdlet Get-Service, как показано ниже. Вы можете видеть, что выводится множество различных служб (объектов).

PS51> Get-Service -ServiceName *
Using a wildcard on ServiceName parameter

Управление свойствами возвращаемых объектов

Продолжая работу с примером Get-Service, возможно, вам не нужно видеть каждое свойство. Вместо этого вам просто нужно увидеть свойства Status и DisplayName. Для ограничения возвращаемых свойств вы будете использовать команду Select-Object.

Командлет Select-Object “фильтрует” различные свойства, возвращаемые в конвейер PowerShell. Чтобы “фильтровать” свойства объекта, которые возвращаются, вы можете использовать параметр Property и указать через запятую одно или несколько свойств, которые нужно вернуть.

Ниже приведен пример, когда возвращаются только свойства Status и DisplayName.

PS51> Get-Service -ServiceName * | Select-Object -Property 'Status','DisplayName'
Showing the Status and DisplayName properties

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

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

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

Например, с помощью параметра Property командлета Sort-Object вы можете указать одно или несколько свойств объектов, полученных от Get-Service, для их сортировки. PowerShell передаст каждый объект командлету Sort-Object и затем вернет их, отсортированными по значению свойства.

Ниже приведен пример, когда возвращаются все объекты служб, отсортированные по их свойству Status в порядке убывания с использованием параметра Descending командлета Sort-Object.

PS51> Get-Service -ServiceName * | Select-Object -Property 'Status','DisplayName' |
	Sort-Object -Property 'Status' -Descending
Using Sort-Object to sort service objects by Status in descending order

В PowerShell символ ” | ” (вертикальная черта) – это одна из нескольких техник продолжения строки, которую следует использовать при необходимости. Используйте его вместо обратных кавычек.

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

Возможно, вы решили, что не хотите видеть все сервисы на компьютере. Вместо этого вам нужно ограничить вывод по определенным критериям. Один из способов ограничить количество возвращаемых объектов – использовать командлет Where-Object.

В то время как командлет Select-Object ограничивает вывод определенных свойств, командлет Where-Object ограничивает вывод целых объектов.

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

Возможно, вы решили, что вы хотите получить только объекты с значением свойства Status равным Running и только те, у которых значение свойства DisplayName начинается с A.

В следующем фрагменте кода вы можете видеть, что ссылка на командлет Where-Object была вставлена между командлетами Select-Object и Sort-Object в порядке конвейера. Используя блок сценария со значением условия, созданным для каждого объекта, чтобы выполнить через параметр FilterScript, вы можете создать любой тип запроса, который вам нужен.

Ознакомьтесь с командлетом Format-Table, если вы хотите изменить формат возвращаемого вывода на консоль.

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object -FilterScript {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending | Format-Table -AutoSize
Formatting object output

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

Команда Get-Service возвращает множество разных объектов. С помощью командлета Where-Object вы отфильтровали некоторую часть этих объектов, но сколько именно? Вводим командлет Measure-Object.

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

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

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending | Measure-Object

После обработки команд вы увидите, что в данном случае изначально было возвращено 21 объектов, созданных с помощью командлета Get-Service.

Finding the number of objects returned with Measure-Object

Возможно, вам интересно только общее количество возвращаемых объектов. Поскольку команда Measure-Object возвращает общее количество найденных объектов через свойство Count, вы можете снова использовать командлет Select-Object. Но на этот раз возвращайте только свойство Count.

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending |
			Measure-Object |
				# Мы начинаем снова, сначала фильтруем, в конце форматируем
				Select-Object -Property 'Count'
Only returning the count property

Принятие действий над объектами с помощью циклов

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

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

Продолжая использовать пример Get-Service, возможно, вы хотите найти все службы на компьютере с Windows, имя которых начинается с “Windows” и которые запущены. Используя командлет Where-Object, вы можете создать условия, как вы делали ранее.

Where-Object -FilterScript {$_.DisplayName -Like "Windows*" -and $_.Status -eq 'Running'}

Но теперь, вместо возвращения целых объектов или даже нескольких свойств, вы хотите вернуть строку <ServiceName> работает для каждого объекта, используя код **Write-Host -ForegroundColor 'Yellow' <ServiceName> "работает".

Вы теперь изменяете вывод и создаете свою собственную строку. Единственный способ сделать это – использовать командлет ForEach-Object, как показано ниже. Ниже вы можете видеть, что для каждого объекта, возвращенного через Where-Object, PowerShell выполняет код Write-Host -ForegroundColor 'Yellow' $_.DisplayName "работает".

PS51> Get-Service -ServiceName * |
	Where-Object {$_.DisplayName -Like "Windows*" -and $_.Status -eq 'Running'} | 
		Foreach-Object {
			Write-Host -ForegroundColor 'Yellow' $_.DisplayName "is running"
		}
Filtering by property with Where-Object

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

Представьте себе возможности, которые это предоставляет вам! С небольшой мыслью и планированием вы можете создать сценарий, который выполняет одну команду и без труда выполняет ее для множества объектов.

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

Иногда вам нужно посмотреть на два объекта и сравнить значения свойств.

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

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

$A = 'Svr01a.contoso.com'
$B = 'Svr02b.contoso.com'

$ProcA = Invoke-Command -Computername $A -Scriptblock {Get-Process -Name *}
$ProcB = Invoke-Command -ComputerName $B -Scriptblock {Get-Process -Name *}

Теперь вы получили все процессы на каждом компьютере в переменных $ProcA и $ProcB. Вам теперь нужно их сравнить. Вы можете вручную просмотреть каждый набор процессов, или вы можете сделать это легким путем, используя командлет Compare-Object.

Compare-Object позволяет сравнивать значения свойств двух разных объектов. Этот командлет читает каждое свойство в каждом объекте, смотрит на их значения и затем возвращает различия, по умолчанию, а также то, что совпадает.

Чтобы использовать Compare-Object, укажите параметры ReferenceObject и DifferenceObject, предоставив каждый объект в качестве значений параметров, как показано ниже.

Compare-Object -ReferenceObject $ProcA -DifferenceObject $ProcB

По умолчанию Compare-Object будет возвращать только различия в объектах, указанных свойством SideIndicator. Символы или индикаторы стороны, используемые, это >, < , и & = для отображения совпадений объектов, которые сравниваются.

Running Compare-Object

Вы можете использовать параметр переключателя IncludeEqual с Compare-Object, чтобы вернуть свойства объекта, которые совпадают. Если это так, вы увидите == в качестве индикатора стороны. Аналогично, вы можете использовать ExcludeDifferent, чтобы исключить различия.

Compare-Object – очень полезный cmdlet. Если вы хотите узнать больше, обязательно посетите онлайн-документацию.

Работа с пользовательскими объектами

Теперь, когда у вас есть хорошее понимание объектов и того, как с ними работать, пришло время создать свои собственные объекты!

Создание пользовательских объектов из хэш-таблиц

Один из способов создания собственных объектов – использование хэш-таблиц. Хэш-таблицы представляют собой наборы пар ключ/значение, именно то, что вам нужно для создания свойств объекта.

Давайте начнем с создания пользовательского объекта PowerShell с некоторыми ключами/значениями с использованием хэш-таблицы. В приведенном ниже примере вы создаете хэш-таблицу. Эта хэш-таблица представляет собой один объект и его свойства. После определения хэш-таблицы $CarHashtable, вы затем используете PsCustomObject ускоритель типа.

Ускоритель типа pscustomobject – это быстрый способ создать экземпляр класса pscustomobject. Это поведение называется приведением типов.

В конце данного фрагмента кода у вас есть объект ($CarObject) типа pscustomobject с пятью присвоенными свойствами.

## Определение хэш-таблицы
$CarHashtable = @{
	Brand      = 'Ford'
	Style      = 'Truck'
	Model      = 'F-150'
	Color      = 'Red'
	Drivetrain = '4x4'
}

## Создание объекта
$CarObject = [PsCustomObject]$CarHashTable

Также можно использовать командлет New-Object. Используя ту же хэш-таблицу, вместо использования ускорителя типа pscustomobject, можно сделать это длинным путем с помощью командлета New-Object. Пример приведен ниже.

$CarHashtable = @{
	Brand      = 'Ford'
	Style      = 'Truck'
	Model      = 'F-150'
	Color      = 'Red'
	Drivetrain = '4x4'
}
#Создание объекта
$CarObject = New-Object -TypeName PsObject -Properties $CarHashtable

После создания $CarObject вы можете видеть, что можете ссылаться на каждое свойство так же, как если бы оно было встроенным командлетом PowerShell, например, Get-Service.

Inspecting object properties

Добавление и удаление свойств

Вы можете не только создавать пользовательские объекты, но и добавлять к ним. Вспомните командлет Get-Member? У командлета Get-Member есть относительный командлет Add-Member. Командлет Add-Member не перечисляет члены, он добавляет их.

Используя ранее созданный пользовательский объект в качестве примера, возможно, вы хотите добавить свойство “год выпуска” к этому объекту. Вы можете сделать это, передавая объект в командлет Add-Member и указывая:

  • Тип участника (в данном случае простой NoteProperty)
  • Имя свойства (Year)
  • Значение свойства (Value)

Вы можете увидеть пример ниже.

PS51> $CarObject | Add-Member -MemberType NoteProperty -Name 'Year' -Value '2010'

Как видно ниже, свойство выглядит так же, как любое другое свойство.

Adding and viewing a new property

Вы можете использовать аналогичные методы для добавления различных типов участников. Если вы хотите исследовать это самостоятельно, ознакомьтесь с документацией по командлету Add-Member.

Вы также можете легко удалить участника из объекта. Хотя нет командлета Remove-Member, вы все равно можете удалить его, вызвав метод Remove() на объекте, как показано ниже. Вы узнаете о методах в следующем разделе.

PS51> $CarObject.psobject.properties.remove('Drivetrain')

Краткое введение в методы

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

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

Например, вы, возможно, знакомы с командой Stop-Service. Эта команда останавливает службу Windows. Для этого вы можете передать объект из Get-Service напрямую в Stop-Service, чтобы это произошло.

Ниже приведен пример остановки службы BITS. В этом примере служба BITS останавливается, а затем проверяется ее статус, чтобы убедиться, что она остановлена. Вы выполнили два действия с помощью командлетов: остановка службы и проверка статуса.

PS51> Get-Service -ServiceName 'BITS' | Stop-Service
PS51> Get-Service -ServiceName 'BITS'

Вместо двухкратного выполнения команды Get-Service и отдельной команды Stop-Service можно воспользоваться методами, которые встроены прямо в объекты служб. Многие объекты имеют методы. В данном случае это метод Stop-Service, и второе упоминание Get-Service даже не требуется.

Running commands to stop and start a service

Вызывая методы непосредственно на объекте службы, вы можете остановить и получить обновленный статус, используя только один объект. Ниже вы можете увидеть это на практике. Обратите внимание, что, используя методы Stop() и Start(), вы можете управлять службой точно так же, как это делали команды.

Чтобы убедиться, что значение свойства Status актуально после изменения статуса службы, вы можете вызвать метод Refresh(), который действует подобно команде Get-Service.

## Остановите BITS на локальной машине
$Svc = Get-Service -ServiceName 'BITS' #Объект, с которым вы работаете
$Svc.Stop() #Метод / действие, которое вы выполняете
$Svc.Refresh() #Метод / действие, которое вы выполняете
$Svc.Status #Свойство

#Запустите BITS на локальной машине
$Svc = Get-Service -ServiceName 'BITS' #Объект, с которым вы работаете
$Svc.Start() #Метод / действие, которое вы выполняете
$Svc.Refresh() #Метод / действие, которое вы выполняете
$Svc.Status #Свойство

Вы должны увидеть следующий результат:

Executing methods on the service object

Для получения дополнительной информации о методах, ознакомьтесь с разделом справки about_Methods.

Заключение

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

Source:
https://adamtheautomator.com/powershell-objects/