Глава 21. Часть 2 — Создание объектов и вывод данных объектами. PowerShell in depth — Don Jones, Richard Siddaway

в 6:35, , рубрики: powershell

здесь перечислены разные способы создания объектов PowerShell. Даны советы и трюки. Текст великоват. Для всех изучающих пошик.

Кроме удобства чтения, количество нажатий на клавиши, требования к сохранению порядка свойств, все эти методы по существу делают тоже самое. Несколько тонких различий: техника 1, хэш таблица. Как правило самая быстрая, техника 2 медленее, техника 3 может быть значительно медленее.

Хорошая рецензия learn-powershell.net/2010/09/19/custom-powershell-objects-and-performance выполненная MVP Boe Prox. Проводится сравнение скорости работы этих трех методов, работа Add-Member в 10 раз медленее. Так что это плюс к технике 1. Мы не тестировали технику 4 как это делал Boe, но наши тесты показывают что техника 4 быстрее на 10% чем техника 1. Техника 5 должна быть использована в тех случаях когда типизация свойств имеет значение.

Сам перевод:

21.2 Синтаксис для создания пользовательских объектов
Мы часто говорили, что всегда есть несколько способов сделать что-либо в PowerShell, и это, верно для пользовательских объектов. Мы покажем вам все основные пути, потому что вы, наверняка столкнетесь с ними в жизни, мы хотим, чтобы вы могли распознать их и использовать их, когда вы захотите.

Глава 21.1 Техника номер 1. Использование хеш таблиц для создания кастомных объектов.

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

# Собираем какието данные, в последующем нам нужно это скомпоновать и вывести
$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select –First 1

# Хэш таблица. Описывает свойства будущего объекта
$props = @{OSVersion=$os.version
Model=$cs.model
Manufacturer=$cs.manufacturer
BIOSSerial=$bios.serialnumber
ComputerName=$os.CSName
OSArchitecture=$os.osarchitecture
ProcArchitecture=$proc.addresswidth}

# Создаем объект из хэш таблицы и выводим
$obj = New-Object –TypeName PSObject –Property $props
Write-Output $obj

выполнив этот код вы получите результат подобный этому:

Manufacturer : Microsoft Corporation
OSVersion : 6.3.9600
OSArchitecture : 64-bit
BIOSSerial : 036685734653
ComputerName : RSSURFACEPRO2
Model : Surface Pro 2
ProcArchitecture : 64

Т.к. на выходе у вас объект имеющий более четырех свойств PowerShell сделал вывод на экран в виде списка. Вы могли бы выполнить

Write-Output $obj | ft

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

Manufacturer=$cs.manufacturer

Если поместить записи хэш-таблицы на одной строке, вам нужно будет отделить каждое свойство точкой с запятой. Если поместить каждое свойство на отдельной строке, вам не нужна точка с запятой, вам намного легче читать и править код.
Скобки с прешедствующим им знаком @ говорят что далее начинается хэш-таблица. Т.к. таблица находится в переменной $props ее легко передать в параметрах -property нового объекта. Объект PSObject специально предусмотрен для этих целей.

Преимущество этого подхода в том что легко построить хэш таблицу на лету и создать из нее много пользовательских объектов. Вы можете заметить что в выходном объекте свойства имеют не тот же самый порядок как они были определены в таблице. Одно из возможных решений — создать форматирование для кастомного объекта (специальный XML файл описывающий как выводить на экран, в каком порядке и т.п.) или, если вы используете powershell 3 и выше, то можно использовать свойство ordered

$props = [ordered]@{ OSVersion=$os.version
Model=$cs.model
Manufacturer=$cs.manufacturer
BIOSSerial=$bios.serialnumber
ComputerName=$os.CSName
OSArchitecture=$os.osarchitecture
ProcArchitecture=$proc.addresswidth}

Все остальное тоже самое. Теперь свойства объекта будут отображаться в том порядке как они были записаны. Если вы передадите $obj на Get-Member, вы увидете что это PS-CustomObject.

Примечание PowerShell по умолчанию не отслеживает порядок элементов в хэш таблице. Вот почему когда вы видете окончательный вывод его свойства идут не в том порядке в каком вы их создавали. Начиная с PowerShell 3 вы можете исправить это использовав атрибут [ordered]. Это создает упорядоченный словарь (другое название хэш таблиц) и поддерживает порядок элементов в ней.

21.2.2 Техника 2. Использование Select-Object
Этот метод был фаворитом в PowerShell v1, и мы по прежнему видим людей использующих его. Нам не она не нравится, посколькую ее гораздо сложнее читать. Следующий листинг показывает технику где мы создадим пустой объект, а затем запишем значения этих свойств

Листинг 21.3. Создание объекта используя Select-Object

# Наши четыре неизменные четыре команды
$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select –First 1

# создание объекта через Select-Object
$obj = 1 | Select-Object ComputerName,OSVersion,OSArchitecture, ProcArchitecture,Model,Manufacturer,BIOSSerial

# заполняем поля
$obj.ComputerName = $os.CSName
$obj.OSVersion = $os.version
$obj.OSArchitecture = $os.osarchitecture
$obj.ProcArchitecture = $proc.addresswidth
$obj.BIOSSerial = $bios.serialnumber
$obj.Model = $cs.model
$obj.Manufacturer = $cs.manufacturer
Write-Output $obj

Обратите внимание, что в листинге 21.3 было сделано $obj = 1, по существу значение 1 никогда не будет использовано.

СОВЕТ Вы увидите много примеров, когда пустая строка используют в качестве инициализатора: $obj="" | select .... Это просто способ определить $obj как объект, закинуть в конвеер что-то, чтобы перейти к Select-Object, который и сделает всю работу.

В этом подходе есть недостаток. Подадим $obj в Get-Member и посмотрим на результат.

PS C:> $obj | Get-Member
TypeName: Selected.System.Int32
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
BIOSSerial NoteProperty System.String BIOSSerial=
ComputerName NoteProperty System.String ComputerName= WIN-KNBA0R0TM23
Manufacturer NoteProperty System.String Manufacturer= VMware, Inc.
Model NoteProperty System.String Model= VMware Virtual Platform
OSArchitecture NoteProperty System.String OSArchitecture= 64-bit
OSVersion NoteProperty System.String OSVersion= 6.1.7601
ProcArchitecture NoteProperty System.UInt16 ProcArchitecture=64

Свойства на месте, но TypeName может привести к проблемам или даже просто путанице, все зависит от того что вы еще намереваетесь делать с этим объектом. Мы рекомендуем избегать эту технику.

вставка от переводчика
Здесь имеет в виду вот что:
подадим в Get-Member пример из листинга 21.2 — где мы создавали хэш таблицей
image

теперь подадим на GM пример из листинга 21.3 — создание через Select-Object
image

21.2.2 Техника 3. Использование Add-Member
Этот метод считается формальным. Мы считаем что он иллюстрирует то что происходит в жизни с формальными подходами. Он наиболее дорогостоящий в вычислительном отношении, медленее всех, так что не часто встретишь людей использующих его в реальной жизни. Это наиболее общий подход PowerShell v1. Есть две вариации, и сначала листинг с кодом.

Листинг 21.4. Создание объекта используя Add-Member

# Наши четыре неизменные четыре команды
$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select –First 1

# создаем объект указав его тип
$obj = New-Object –TypeName PSObject

# добавляем поля указав тип и значение
$obj | Add-Member NoteProperty ComputerName $os.CSName
$obj | Add-Member NoteProperty OSVersion $os.version
$obj | Add-Member NoteProperty OSArchitecture $os.osarchitecture
$obj | Add-Member NoteProperty ProcArchitecture $proc.addresswidth
$obj | Add-Member NoteProperty BIOSSerial $bios.serialnumber
$obj | Add-Member NoteProperty Model $cs.model
$obj | Add-Member NoteProperty Manufacturer $cs.manufacturer
Write-Output $obj

Мы создали PSObject и добавляем по одному свойству к нему за раз. Вам нужно вызвать метод каждый раз когда вы добавляете NoteProperty которая содержит только статическое значение. Для сокращения кода мы использовали позиционные параметры Add-Member. Если использовать полный синтаксис то каждый оператор Add-Member будет выглядеть следующим образом

Add-Member -MemberType NoteProperty -Name ComputerName -Value $os.CSName

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

Вариация этого метода заключается в использовании парамера -PassThru (сокращенно -Pass в листинге 21.5) команды Add-Member. Этот параметр поместит модифицированный объект обратно в конвеер, так что вы сможете передать его на следующую команду и так далее.

Покажем на примере

Листинг 21.4. Создание объекта используя Add-Member с параметром -PassThru

# Наши четыре неизменные четыре команды
$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select –First 1

# создаем объект указав его тип
$obj = New-Object –TypeName PSObject

# создаем свойства
$obj | Add-Member NoteProperty ComputerName $os.CSName –pass |
Add-Member NoteProperty OSVersion $os.version –pass |
Add-Member NoteProperty OSArchitecture $os.osarchitecture –Pass |
Add-Member NoteProperty ProcArchitecture $proc.addresswidth –pass |
Add-Member NoteProperty BIOSSerial $bios.serialnumber –pass |
Add-Member NoteProperty Model $cs.model –pass |
Add-Member NoteProperty Manufacturer $cs.manufacturer
Write-Output $obj

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

вставка переводчика
имеет в виду что отладка легче

21.2.4 Техника 4. Использование декларации типа

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

# Наши четыре неизменные четыре команды
$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select –First 1

$obj = [pscustomobject]@{
                                              OSVersion=$os.version
                                              Model=$cs.model
                                              Manufacturer=$cs.manufacturer
                                              BIOSSerial=$bios.serialnumber
                                              ComputerName=$os.CSName
                                              OSArchitecture=$os.osarchitecture
                                              ProcArchitecture=$proc.addresswidth
                                              }
Write-Output $obj

Вы могли бы продолжать заполнять переменную $props, трюк этой техники в том что порядок свойств в объекте будет сохранен также как будто мы использовали директиву [ordered]

Совет. Тип который мы используем это PSCustomObject. Вы должны использовать этот тип потому что в .NET терминах вы используете конструктор PSObject без параметров. Не пытайтесь сократить код указав вместо PSCustomObject объект PSObject, вы не получите нужного результата.

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

21.2.5 Техника 5. Создание нового класса

Не часто используемая техника. Она дает некоторые преимущества в обработке на конвеере. Может быть оценена как продвинутая техника, не все повершельщики захотят вникать в .NET. Но возможность доступна в виде опции

Листинг 21.7 Создание объекта используя класс

$source=@"
public class MyObject
{
public string ComputerName {get; set;}
public string Model {get; set;}
public string Manufacturer {get; set;}
public string BIOSSerial {get; set;}
public string OSArchitecture {get; set;}
public string OSVersion {get; set;}
public string ProcArchitecture {get; set;}
}
"@
Add-Type -TypeDefinition $source -Language CSharpversion3

# наши четыре команды
$os = Get-WmiObject –Class Win32_OperatingSystem –comp localhost
$cs = Get-WmiObject –Class Win32_ComputerSystem –comp localhost
$bios = Get-WmiObject –Class Win32_BIOS –comp localhost
$proc = Get-WmiObject –Class Win32_Processor –comp localhost | Select –First 1

$props = @{OSVersion=$os.version
Model=$cs.model
Manufacturer=$cs.manufacturer
BIOSSerial=$bios.serialnumber
ComputerName=$os.CSName
OSArchitecture=$os.osarchitecture
ProcArchitecture=$proc.addresswidth}
$obj = New-Object –TypeName MyObject –Property $props
Write-Output $obj

Листинг 21.7 начинается с создания записи содержащей C# код описания класса. Класс имеет имя, MyObj и делает ряд описаний свойств класса. В этом примере свойства указаны как строки, но допускается смешивать типы. И хотя мы не собираемся записывать устанавливать свойства в будущем, определение класса требует записи GET и SET, в противном случае PowerShell выдаст исключение.

Add-Type используется для компиляции класса, после чего мы можем использовать его вместо PSObject. Для установки свойств объекта может быть использована техника представленная здесь и в листинге 21.6:

$obj = [MyObject]@{OSVersion=$os.version
                                   Model=$cs.model
                                   Manufacturer=$cs.manufacturer
                                   BIOSSerial=$bios.serialnumber
                                   ComputerName=$os.CSName
                                   OSArchitecture=$os.osarchitecture
                                   ProcArchitecture=$proc.addresswidth
                                   }

проведем тестирование в Get-Member

PS C:> $obj | get-member
TypeName: MyObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
BIOSSerial Property string BIOSSerial {get;set;}
ComputerName Property string ComputerName {get;set;}
Manufacturer Property string Manufacturer {get;set;}
Model Property string Model {get;set;}
OSArchitecture Property string OSArchitecture {get;set;}
OSVersion Property string OSVersion {get;set;}
ProcArchitecture Property string ProcArchitecture {get;set;}

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

21.2.6 Какие различия???

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

Несколько тонких различий: техника 1, хэш таблица. Как правило самая быстрая, особенно когда вы работаете с несколькими объектами, техника 2 немного медленее, техника 3 может быть значительно медленее.

Хорошая рецензия learn-powershell.net/2010/09/19/custom-powershell-objects-and-performance Скорость создания объектов в PowerShell выполненная MVP Boe Prox. Проводится сравнение скорости работы этих трех методов, работа Add-Member в 10 раз медленее. Так что это плюс к технике 1. Мы не тестировали технику 4 как это делал Boe, но наши тесты показывают что техника 4 быстрее на 10% чем техника 1. Техника 5 должна быть использована в тех случаях когда типизация свойств имеет значение.

Автор: pak-nikolai

Источник

Поделиться новостью

* - обязательные к заполнению поля