Sebelum PowerShell 3
Sistem Jenis Dapat Diperluas PowerShell awalnya tidak memungkinkan Anda membuat jenis konkret yang dapat Anda uji dengan cara yang Anda lakukan di parameter Anda. Jika Anda tidak memerlukan tes itu, Anda baik-baik saja dengan metode lain yang disebutkan di atas.
Jika Anda menginginkan tipe aktual yang dapat Anda transmisikan atau gunakan pemeriksaan ketik, seperti dalam contoh skrip Anda ... itu tidak dapat dilakukan tanpa menuliskannya di C # atau VB.net dan kompilasi. Di PowerShell 2, Anda dapat menggunakan perintah "Add-Type" untuk melakukannya dengan cukup sederhana:
add-type @"
public struct contact {
public string First;
public string Last;
public string Phone;
}
"@
Catatan Sejarah : Di PowerShell 1 bahkan lebih sulit. Anda harus menggunakan CodeDom secara manual, ada fungsiskrip new-struct yang sangat lamadi PoshCode.org yang akan membantu. Contoh Anda menjadi:
New-Struct Contact @{
First=[string];
Last=[string];
Phone=[string];
}
Menggunakan Add-Type
atau New-Struct
akan membiarkan Anda benar-benar menguji kelas di Anda param([Contact]$contact)
dan membuat yang baru menggunakan $contact = new-object Contact
dan seterusnya ...
Di PowerShell 3
Jika Anda tidak memerlukan kelas "nyata" yang dapat Anda gunakan untuk melakukan cast, Anda tidak harus menggunakan cara Tambah Anggota seperti yang ditunjukkan Steven dan orang lain di atas.
Sejak PowerShell 2 Anda dapat menggunakan parameter -Property untuk New-Object:
$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }
Dan di PowerShell 3, kami mendapatkan kemampuan untuk menggunakan PSCustomObject
akselerator untuk menambahkan TypeName:
[PSCustomObject]@{
PSTypeName = "Contact"
First = $First
Last = $Last
Phone = $Phone
}
Anda masih hanya mendapatkan satu objek, jadi Anda harus membuat New-Contact
fungsi untuk memastikan bahwa setiap objek keluar sama, tetapi sekarang Anda dapat dengan mudah memverifikasi parameter "adalah" salah satu dari jenis itu dengan menghias parameter dengan PSTypeName
atribut:
function PrintContact
{
param( [PSTypeName("Contact")]$contact )
"Customer Name is " + $contact.First + " " + $contact.Last
"Customer Phone is " + $contact.Phone
}
Di PowerShell 5
Di PowerShell 5 semuanya berubah, dan kami akhirnya mendapatkan class
dan enum
sebagai kata kunci bahasa untuk menentukan jenis (tidak ada struct
tapi tidak apa-apa):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
Contact($First, $Last, $Phone) {
$this.First = $First
$this.Last = $Last
$this.Phone = $Phone
}
}
Kami juga mendapatkan cara baru untuk membuat objek tanpa menggunakan New-Object
: [Contact]::new()
- pada kenyataannya, jika Anda membuat kelas Anda tetap sederhana dan tidak mendefinisikan konstruktor, Anda dapat membuat objek dengan mentransmisikan hashtable (meskipun tanpa konstruktor, tidak mungkin untuk menegakkan bahwa semua properti harus disetel):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
}
$C = [Contact]@{
First = "Joel"
Last = "Bennett"
}
Add-Type
? Tampaknya berfungsi di PowerShell 2 pada Win 2008 R2. Katakanlah saya mendefinisikancontact
menggunakanAdd-Type
seperti dalam jawaban Anda dan kemudian membuat sebuah contoh:$con = New-Object contact -Property @{ First="a"; Last="b"; Phone="c" }
. Kemudian memanggil fungsi ini berfungsi:,function x([contact]$c) { Write-Host ($c | Out-String) $c.GetType() }
tetapi pemanggilan fungsi ini gagalx([doesnotexist]$c) { Write-Host ($c | Out-String) $c.GetType() }
,. Panggilanx 'abc'
juga gagal dengan pesan kesalahan yang sesuai tentang transmisi. Diuji di PS 2 dan 4.Add-Type
@ jpmc26, apa yang saya katakan adalah Anda tidak dapat melakukannya tanpa kompilasi (yaitu: tanpa menuliskannya di C # dan memanggilAdd-Type
). Tentu saja, dari PS3 Anda bisa - ada[PSTypeName("...")]
atribut yang memungkinkan Anda untuk menentukan jenis sebagai string, yang mendukung pengujian terhadap PSCustomObjects dengan PSTypeNames set ...Membuat tipe kustom dapat dilakukan di PowerShell.
Kirk Munro sebenarnya memiliki dua pos hebat yang merinci prosesnya secara menyeluruh.
Buku Windows PowerShell In Action by Manning juga memiliki contoh kode untuk membuat bahasa khusus domain untuk membuat tipe kustom. Buku ini sangat bagus secara keseluruhan, jadi saya sangat merekomendasikannya.
Jika Anda hanya mencari cara cepat untuk melakukan hal di atas, Anda dapat membuat fungsi untuk membuat objek khusus seperti
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 }
sumber
Ini adalah metode pintas:
$myPerson = "" | Select-Object First,Last,Phone
sumber
$myPerson = 1 | Select First,Last,Phone
NoteProperty
daristring
jenis, itu adalahProperty
dari jenis apa pun yang Anda telah ditugaskan dalam objek. Ini cepat dan berhasil.Jawaban Steven Murawski bagus, namun saya suka yang lebih pendek (atau lebih tepatnya hanya objek-pilih yang lebih rapi daripada menggunakan sintaks anggota tambahan):
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 }
sumber
New-Object
bahkan tidak dibutuhkan. Ini akan melakukan hal yang sama:... = 1 | select-object First, Last, Phone
int
cara: 1) bekerja lebih cepat, tidak banyak, tetapi untuk fungsi khusus iniNew-Person
perbedaannya adalah 20%; 2) tampaknya lebih mudah untuk mengetik. Pada saat yang sama, menggunakan pendekatan ini pada dasarnya di mana-mana, saya belum pernah melihat kekurangannya. Tapi saya setuju: mungkin ada beberapa kasus yang jarang terjadi saat PSCustomObject lebih baik.Terkejut tidak ada yang menyebutkan opsi sederhana ini (vs 3 atau lebih baru) untuk membuat objek khusus:
[PSCustomObject]@{ First = $First Last = $Last Phone = $Phone }
Jenisnya adalah PSCustomObject, bukan jenis kustom sebenarnya. Tapi ini mungkin cara termudah untuk membuat objek kustom.
sumber
Ada konsep PSObject dan Add-Member yang bisa Anda gunakan.
$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"
Output ini seperti:
[8] » $contact First Last Phone ----- ---- ----- John Doe 123-4567
Alternatif lain (yang saya ketahui) adalah untuk menentukan tipe di C # / VB.NET dan memuat rakitan itu ke PowerShell untuk digunakan secara langsung.
Perilaku ini sangat dianjurkan karena memungkinkan skrip atau bagian lain dari skrip Anda bekerja dengan objek yang sebenarnya.
sumber
Berikut adalah cara yang sulit untuk membuat jenis kustom dan menyimpannya dalam koleksi.
$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
sumber
Berikut satu opsi lagi, yang menggunakan ide serupa dengan solusi PSTypeName yang disebutkan oleh Jaykul (dan karenanya juga memerlukan PSv3 atau lebih tinggi).
Contoh
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
Penjelasan
PS1XML
atauAdd-Member
dibatasi untukNoteProperty
,AliasProperty
,ScriptProperty
,CodeProperty
,ScriptMethod
, danCodeMethod
(atauPropertySet
/MemberSet
; meskipun mereka tunduk pada pembatasan yang sama). Semua properti ini hanya baca.ScriptMethod
kita bisa menipu batasan di atas. Misalnya, kita dapat mendefinisikan metode (misalnyaInitialize
) yang membuat properti baru, menyetel nilainya untuk kita; sehingga memastikan objek kami memiliki semua properti yang kami butuhkan agar skrip kami yang lain berfungsi.SetGivenName
.Pendekatan ini tidak ideal untuk semua skenario; tetapi berguna untuk menambahkan perilaku seperti kelas ke tipe khusus / dapat digunakan bersama dengan metode lain yang disebutkan dalam jawaban lain. Misalnya di dunia nyata, saya mungkin hanya mendefinisikan
FullName
properti di PS1XML, lalu menggunakan fungsi untuk membuat objek dengan nilai yang diperlukan, seperti:Info lebih lanjut
Lihatlah dokumentasi , atau file tipe OOTB
Get-Content $PSHome\types.ps1xml
untuk inspirasi.# 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
sumber