Как создать пользовательский тип в PowerShell для использования моими сценариями?


Я хотел бы иметь возможность определять и использовать пользовательский тип в некоторых из моих сценариев 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?

7 61

7 ответов:

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

книги Windows PowerShell в действии от Manning также есть пример кода для создания доменного языка для создания пользовательских типов. Книга превосходна всем вокруг, так что я действительно рекомендую его.

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

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, есть очень старая функция new-struct скрипт включен PoshCode.org и это поможет. Ваш пример становится:

New-Struct Contact @{
    First=[string];
    Last=[string];
    Phone=[string];
}

используя Add-Type или New-Struct позволит вам на деле проверить класс param([Contact]$contact) и сделать новые с помощью $contact = new-object Contact и так на...

В PowerShell 3

Если вам не нужен "реальный" класс, который вы можете привести, вам не нужно использовать метод Add-Member, который Стивен и другие продемонстрировали выше.

начиная с PowerShell 2 Вы можете использовать параметр-Property для New-Object:

$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }

и в PowerShell 3, мы получили возможность использовать PSCustomObject ускоритель для добавления имени типа:

[PSCustomObject]@{
    PSTypeName = "Contact"
    First = $First
    Last = $Last
    Phone = $Phone
}

вы все еще только один объект, так что вы должны сделать New-Contact функции, чтобы убедиться, что каждый объект выходит то же самое, но теперь вы можете легко проверить параметр "является" одним из тех типов, украшая параметр с :

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

ответ Стивена Муравски велик, однако мне нравится более короткий (или, скорее, просто более аккуратный select-object вместо использования синтаксиса add-member):

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
}

существует концепция 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 для непосредственного использования.

это поведение определенно рекомендуется, потому что оно позволяет другим сценариям или разделам вашего сценария работать с фактическим объектом.

удивлен, что никто не упомянул этот простой вариант (vs 3 или более поздней версии) для создания пользовательских объектов:

[PSCustomObject]@{
    First = $First
    Last = $Last
    Phone = $Phone
}

тип будет PSCustomObject, а не фактический пользовательский тип. Но это, вероятно, самый простой способ создать пользовательский объект.

вот жесткий путь для создания пользовательских типов и хранения их в коллекции.

$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