Как создать в PowerShell собственный тип для использования в моих сценариях?
-
09-06-2019 - |
Вопрос
Я хотел бы иметь возможность определять и использовать собственный тип в некоторых сценариях PowerShell.Например, давайте представим, что мне нужен объект, имеющий следующую структуру:
Contact
{
string First
string Last
string Phone
}
Как бы мне создать это, чтобы я мог использовать его в следующей функции:
function PrintContact
{
param( [Contact]$contact )
"Customer Name is " + $contact.First + " " + $contact.Last
"Customer Phone is " + $contact.Phone
}
Возможно ли или даже рекомендуется ли что-то подобное в PowerShell?
Решение
Создание пользовательских типов можно выполнить в PowerShell.
У Кирка Манро есть две замечательные статьи, в которых подробно описан процесс.
Книга Windows PowerShell в действии, Мэннинг также есть пример кода для создания предметно-ориентированного языка для создания пользовательских типов.Книга великолепна во всех отношениях, поэтому я ее очень рекомендую.
Если вы просто ищете быстрый способ сделать вышеизложенное, вы можете создать функцию для создания пользовательского объекта, например
function New-Person()
{
param ($FirstName, $LastName, $Phone)
$person = new-object PSObject
$person | add-member -type NoteProperty -Name First -Value $FirstName
$person | add-member -type NoteProperty -Name Last -Value $LastName
$person | add-member -type NoteProperty -Name Phone -Value $Phone
return $person
}
Другие советы
До PowerShell 3
Система расширяемых типов PowerShell изначально не позволяла создавать конкретные типы, которые можно было бы протестировать так, как вы это сделали в своем параметре.Если вам не нужен этот тест, вы можете использовать любой из других методов, упомянутых выше.
Если вам нужен фактический тип, к которому вы можете привести или проверить тип, как в вашем примере сценария...это не могу можно сделать, не записывая его на C# или VB.net и не компилируя.В PowerShell 2 вы можете использовать команду «Add-Type», чтобы сделать это довольно просто:
add-type @"
public struct contact {
public string First;
public string Last;
public string Phone;
}
"@
Историческая справка:В PowerShell 1 было еще сложнее.Пришлось вручную использовать CodeDom, там очень старая функция новая структура скрипт на PoshCode.org, который поможет.Ваш пример становится:
New-Struct Contact @{
First=[string];
Last=[string];
Phone=[string];
}
С использованием Add-Type
или New-Struct
позволит вам действительно протестировать класс в вашем param([Contact]$contact)
и создавать новые, используя $contact = new-object Contact
и так далее...
В PowerShell 3
Если вам не нужен «настоящий» класс, к которому вы можете применить приведение, вам не нужно использовать способ «Добавить член», который Стивен и другие продемонстрировали выше.
Начиная с PowerShell 2, вы можете использовать параметр -Property для New-Object:
$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }
А в PowerShell 3 мы получили возможность использовать PSCustomObject
ускоритель для добавления TypeName:
[PSCustomObject]@{
PSTypeName = "Contact"
First = $First
Last = $Last
Phone = $Phone
}
Вы по-прежнему получаете только один объект, поэтому вам следует создать New-Contact
, чтобы убедиться, что все объекты выглядят одинаково, но теперь вы можете легко убедиться, что параметр «является» одним из этих типов, украсив параметр с помощью PSTypeName
атрибут:
function PrintContact
{
param( [PSTypeName("Contact")]$contact )
"Customer Name is " + $contact.First + " " + $contact.Last
"Customer Phone is " + $contact.Phone
}
В PowerShell 5
В PowerShell 5 все меняется, и мы наконец получили class
и enum
в качестве ключевых слов языка для определения типов (нет struct
но это нормально):
class Contact
{
# Optionally, add attributes to prevent invalid values
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
# optionally, have a constructor to
# force properties to be set:
Contact($First, $Last, $Phone) {
$this.First = $First
$this.Last = $Last
$this.Phone = $Phone
}
}
У нас также появился новый способ создания объектов без использования New-Object
: [Contact]::new()
- на самом деле, если вы сохранили свой класс простым и не определили конструктор, вы можете создавать объекты путем приведения хеш-таблицы (хотя без конструктора не было бы способа обеспечить необходимость установки всех свойств):
class Contact
{
# Optionally, add attributes to prevent invalid values
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
}
$C = [Contact]@{
First = "Joel"
Last = "Bennett"
}
Это сокращенный метод:
$myPerson = "" | Select-Object First,Last,Phone
Ответ Стивена Муравски великолепен, однако мне нравится более короткий (или, скорее, просто более аккуратный объект выбора вместо использования синтаксиса добавления члена):
function New-Person() {
param ($FirstName, $LastName, $Phone)
$person = new-object PSObject | select-object First, Last, Phone
$person.First = $FirstName
$person.Last = $LastName
$person.Phone = $Phone
return $person
}
Удивительно, что никто не упомянул этот простой вариант (по сравнению с 3 или более поздней версией) для создания пользовательских объектов:
[PSCustomObject]@{
First = $First
Last = $Last
Phone = $Phone
}
Типом будет PSCustomObject, а не фактический пользовательский тип.Но это, вероятно, самый простой способ создать собственный объект.
Существует концепция PSObject и Add-Member, которую вы можете использовать.
$contact = New-Object PSObject
$contact | Add-Member -memberType NoteProperty -name "First" -value "John"
$contact | Add-Member -memberType NoteProperty -name "Last" -value "Doe"
$contact | Add-Member -memberType NoteProperty -name "Phone" -value "123-4567"
Это выводит следующее:
[8] » $contact
First Last Phone
----- ---- -----
John Doe 123-4567
Другая альтернатива (о которой я знаю) — определить тип в C#/VB.NET и загрузить эту сборку в PowerShell для непосредственного использования.
Такое поведение определенно приветствуется, поскольку оно позволяет другим сценариям или разделам вашего сценария работать с реальным объектом.
Вот сложный путь создания пользовательских типов и хранения их в коллекции.
$Collection = @()
$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "John"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "123-4567"
$Collection += $Object
$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "Jeanne"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "765-4321"
$Collection += $Object
Write-Ouput -InputObject $Collection