До 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
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
Contact($First, $Last, $Phone) {
$this.First = $First
$this.Last = $Last
$this.Phone = $Phone
}
}
У нас также появился новый способ создания объектов без использования New-Object
: [Contact]::new()
- на самом деле, если вы сохраните свой класс простым и не определяете конструктор, вы можете создавать объекты, приводя хэш-таблицу (хотя без конструктора не было бы возможности для обеспечения того, чтобы все свойства были установлены):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
}
$C = [Contact]@{
First = "Joel"
Last = "Bennett"
}
Add-Type
? Кажется, работает в PowerShell 2 на Win 2008 R2. Скажем , я определяю ,contact
используя ,Add-Type
как в ответе , а затем создать экземпляр:$con = New-Object contact -Property @{ First="a"; Last="b"; Phone="c" }
. Затем вызова эта функция работает:function x([contact]$c) { Write-Host ($c | Out-String) $c.GetType() }
, но вызов этой функции не удается,x([doesnotexist]$c) { Write-Host ($c | Out-String) $c.GetType() }
. Вызовx 'abc'
также не выполняется с соответствующим сообщением об ошибке приведения типов. Тестировался на PS 2 и 4.Add-Type
@ jpmc26, я сказал, что вы не можете сделать это без компиляции (т.е. без написания на C # и вызоваAdd-Type
). Конечно, с PS3 вы можете - есть[PSTypeName("...")]
атрибут, который позволяет вам указать тип в виде строки, который поддерживает тестирование с использованием PSCustomObjects с установленным PSTypeNames ...Создавать собственные типы можно в PowerShell.
У Кирка Манро есть два замечательных поста, в которых подробно описывается процесс.
В книге « Windows PowerShell In Action» Мэннинга также есть образец кода для создания специфичного для предметной области языка для создания настраиваемых типов. Книга отличная во всех отношениях, поэтому очень рекомендую.
Если вы просто ищете быстрый способ сделать это, вы можете создать функцию для создания настраиваемого объекта, например
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 }
источник
Это метод быстрого доступа:
$myPerson = "" | Select-Object First,Last,Phone
источник
$myPerson = 1 | Select First,Last,Phone
NoteProperty
изstring
типа, этоProperty
любого типа вы назначили в объекте. Это быстро и работает.Ответ Стивена Муравски великолепен, однако мне нравится более короткий (или, скорее, более аккуратный объект выбора вместо использования синтаксиса добавления члена):
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 }
источник
New-Object
даже не нужен. Это будет делать то же самое:... = 1 | select-object First, Last, Phone
int
способа очевидны : 1) работает быстрее, ненамного, но для данной функцииNew-Person
разница составляет 20%; 2) набирать видимо легче. В то же время, используя такой подход практически везде, я никогда не видел недостатков. Но я согласен: могут быть некоторые редкие случаи, когда PSCustomObject лучше.Удивленный, никто не упомянул этот простой вариант (vs 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
источник
Вот еще один вариант, в котором используется идея, аналогичная решению PSTypeName, упомянутому Джайкулом (и, следовательно, также требуется PSv3 или выше).
пример
Person.Types.ps1xml
:<?xml version="1.0" encoding="utf-8" ?> <Types> <Type> <Name>StackOverflow.Example.Person</Name> <Members> <ScriptMethod> <Name>Initialize</Name> <Script> Param ( [Parameter(Mandatory = $true)] [string]$GivenName , [Parameter(Mandatory = $true)] [string]$Surname ) $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName $this | Add-Member -MemberType 'NoteProperty' -Name 'Surname' -Value $Surname </Script> </ScriptMethod> <ScriptMethod> <Name>SetGivenName</Name> <Script> Param ( [Parameter(Mandatory = $true)] [string]$GivenName ) $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName -Force </Script> </ScriptMethod> <ScriptProperty> <Name>FullName</Name> <GetScriptBlock>'{0} {1}' -f $this.GivenName, $this.Surname</GetScriptBlock> </ScriptProperty> <!-- include properties under here if we don't want them to be visible by default <MemberSet> <Name>PSStandardMembers</Name> <Members> </Members> </MemberSet> --> </Members> </Type> </Types>
Update-TypeData -AppendPath .\Person.Types.ps1xml
$p = [PSCustomType]@{PSTypeName='StackOverflow.Example.Person'}
$p.Initialize('Anne', 'Droid')
$p | Format-Table -AutoSize
$p.SetGivenName('Dan')
$p | Format-Table -AutoSize
Объяснение
PS1XML
илиAdd-Member
ограниченыNoteProperty
,AliasProperty
,ScriptProperty
,CodeProperty
,ScriptMethod
, иCodeMethod
(илиPropertySet
/MemberSet
; хотя те могут быть теми же ограничениями). Все эти свойства доступны только для чтения.ScriptMethod
мы можем обмануть указанное выше ограничение. Например, мы можем определить метод (напримерInitialize
), который создает новые свойства, устанавливая их значения для нас; таким образом гарантируя, что наш объект имеет все свойства, необходимые для работы других наших скриптов.SetGivenName
.Этот подход не идеален для всех сценариев; но полезен для добавления классового поведения к пользовательским типам / может использоваться в сочетании с другими методами, упомянутыми в других ответах. Например, в реальном мире я бы, вероятно, только определил
FullName
свойство в PS1XML, а затем использовал бы функцию для создания объекта с необходимыми значениями, например:Больше информации
Взгляните на документацию или файл типа OOTB
Get-Content $PSHome\types.ps1xml
для вдохновения.# have something like this defined in my script so we only try to import the definition once. # the surrounding if statement may be useful if we're dot sourcing the script in an existing # session / running in ISE / something like that if (!(Get-TypeData 'StackOverflow.Example.Person')) { Update-TypeData '.\Person.Types.ps1xml' } # have a function to create my objects with all required parameters # creating them from the hash table means they're PROPERties; i.e. updatable without calling a # setter method (note: recall I said above that in this scenario I'd remove their definition # from the PS1XML) function New-SOPerson { [CmdletBinding()] [OutputType('StackOverflow.Example.Person')] Param ( [Parameter(Mandatory)] [string]$GivenName , [Parameter(Mandatory)] [string]$Surname ) ([PSCustomObject][Ordered]@{ PSTypeName = 'StackOverflow.Example.Person' GivenName = $GivenName Surname = $Surname }) } # then use my new function to generate the new object $p = New-SOPerson -GivenName 'Simon' -Surname 'Borg' # and thanks to the type magic... FullName exists :) Write-Information "$($p.FullName) was created successfully!" -InformationAction Continue
источник