Semua yang ingin Anda ketahui tentang PSCustomObject

PSCustomObject adalah alat yang bagus untuk ditambahkan ke sabuk alat PowerShell Anda. Mari kita mulai dengan dasar-dasar dan bekerja dengan cara kita ke fitur yang lebih canggih. Ide di balik penggunaan PSCustomObject adalah memiliki cara sederhana untuk membuat data terstruktur. Lihat contoh pertama dan Anda akan memiliki gambaran yang lebih baik tentang apa artinya itu.

Catatan

Versi asli artikel ini muncul di blog yang ditulis oleh @KevinMarquette. Tim PowerShell berterima kasih kepada Kevin karena telah membagikan konten ini kepada kami. Silakan lihat blognya di PowerShellExplained.com.

Membuat PSCustomObject

Saya suka menggunakan [PSCustomObject] di PowerShell. Membuat objek yang dapat digunakan tidak pernah lebih mudah. Karena itu, saya akan melewati semua cara lain yang dapat Anda buat objek tetapi saya perlu menyebutkan bahwa sebagian besar contoh ini adalah PowerShell v3.0 dan yang lebih baru.

$myObject = [PSCustomObject]@{
    Name     = 'Kevin'
    Language = 'PowerShell'
    State    = 'Texas'
}

Metode ini bekerja dengan baik untuk saya karena saya menggunakan hashtable untuk hampir semuanya. Tetapi ada kalanya saya ingin PowerShell memperlakukan hashtable lebih seperti objek. Tempat pertama yang Anda perhatikan perbedaannya adalah ketika Anda ingin menggunakan Format-Table atau Export-CSV dan Anda menyadari bahwa hashtable hanyalah kumpulan pasangan kunci/nilai.

Anda kemudian dapat mengakses dan menggunakan nilai seperti objek normal.

$myObject.Name

Mengonversi hashtable

Sementara saya sedang dalam topik, tahukah Anda bahwa Anda bisa melakukan ini:

$myHashtable = @{
    Name     = 'Kevin'
    Language = 'PowerShell'
    State    = 'Texas'
}
$myObject = [pscustomobject]$myHashtable

Saya lebih suka membuat objek dari awal tetapi ada kalanya Anda harus bekerja dengan hashtable terlebih dahulu. Contoh ini berfungsi karena konstruktor mengambil hashtable untuk properti objek. Salah satu catatan penting adalah bahwa meskipun metode ini berfungsi, metode ini tidak sama persis. Perbedaan terbesar adalah urutan properti tidak dipertahankan.

Jika Anda ingin mempertahankan pesanan, lihat Hashtable yang diurutkan.

Pendekatan warisan

Anda mungkin telah melihat orang menggunakan New-Object untuk membuat objek kustom.

$myHashtable = @{
    Name     = 'Kevin'
    Language = 'PowerShell'
    State    = 'Texas'
}

$myObject = New-Object -TypeName PSObject -Property $myHashtable

Cara ini cukup lambat tetapi mungkin merupakan opsi terbaik Anda pada versi awal PowerShell.

Menyimpan ke file

Saya menemukan cara terbaik untuk menyimpan hashtable ke file adalah dengan menyimpannya sebagai JSON. Anda dapat mengimpornya kembali ke [PSCustomObject]

$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path
$myObject = Get-Content -Path $Path | ConvertFrom-Json

Saya membahas lebih banyak cara untuk menyimpan objek ke file di artikel saya tentang Banyak cara untuk membaca dan menulis ke file.

Bekerja dengan properti

Menambahkan properti

Anda masih dapat menambahkan properti baru ke properti Anda PSCustomObject dengan Add-Member.

$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'

$myObject.ID

Hapus properti

Anda juga dapat menghapus properti dari objek.

$myObject.psobject.properties.remove('ID')

.psobject adalah anggota intrinsik yang memberi Anda akses ke metadata objek dasar. Untuk informasi selengkapnya tentang anggota intrinsik, lihat about_Intrinsic_Members.

Menghitung nama properti

Terkadang Anda memerlukan daftar semua nama properti pada objek.

$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name

Kita bisa mendapatkan daftar yang sama ini dari psobject properti juga.

$myobject.psobject.properties.name

Catatan

Get-Member mengembalikan properti dalam urutan alfabet. Menggunakan operator akses anggota untuk menghitung nama properti mengembalikan properti dalam urutan yang ditentukan pada objek.

Mengakses properti secara dinamis

Saya sudah menyebutkan bahwa Anda dapat mengakses nilai properti secara langsung.

$myObject.Name

Anda dapat menggunakan string untuk nama properti dan masih akan berfungsi.

$myObject.'Name'

Kita dapat mengambil satu langkah lagi ini dan menggunakan variabel untuk nama properti.

$property = 'Name'
$myObject.$property

Aku tahu itu terlihat aneh, tapi berhasil.

Mengonversi PSCustomObject menjadi hashtable

Untuk melanjutkan dari bagian terakhir, Anda dapat secara dinamis memanjat properti dan membuat hashtable dari properti tersebut.

$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
    $hashtable[$property] = $myObject.$property
}

Pengujian untuk properti

Jika Anda perlu tahu apakah properti ada, Anda bisa memeriksa properti tersebut untuk memiliki nilai.

if( $null -ne $myObject.ID )

Tetapi jika nilainya bisa Anda $null periksa untuk melihat apakah nilai tersebut ada dengan memeriksanya psobject.properties .

if( $myobject.psobject.properties.match('ID').Count )

Menambahkan metode objek

Jika Anda perlu menambahkan metode skrip ke objek, Anda dapat melakukannya dengan Add-Member dan ScriptBlock. Anda harus menggunakan variabel otomatis mereferensikan this objek saat ini. Berikut adalah scriptblock untuk mengubah objek menjadi hashtable. (kode yang sama membentuk contoh terakhir)

$ScriptBlock = {
    $hashtable = @{}
    foreach( $property in $this.psobject.properties.name )
    {
        $hashtable[$property] = $this.$property
    }
    return $hashtable
}

Kemudian kita menambahkannya ke objek kita sebagai properti skrip.

$memberParam = @{
    MemberType = "ScriptMethod"
    InputObject = $myobject
    Name = "ToHashtable"
    Value = $scriptBlock
}
Add-Member @memberParam

Kemudian kita dapat memanggil fungsi kita seperti ini:

$myObject.ToHashtable()

Jenis objek vs Nilai

Objek dan jenis nilai tidak menangani penetapan variabel dengan cara yang sama. Jika Anda menetapkan jenis nilai satu sama lain, hanya nilai yang disalin ke variabel baru.

$first = 1
$second = $first
$second = 2

Dalam hal ini, $first adalah 1 dan $second adalah 2.

Variabel objek menyimpan referensi ke objek aktual. Saat Anda menetapkan satu objek ke variabel baru, objek tersebut masih mereferensikan objek yang sama.

$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4

Karena $third dan $fourth mereferensikan instans objek yang sama, keduanya $third.key dan $fourth.Key adalah 4.

psobject.copy()

Jika Anda memerlukan salinan objek yang benar, Anda dapat mengkloningnya.

$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4

Kloning membuat salinan objek yang dangkal. Mereka memiliki instans yang berbeda sekarang dan $third.key berjumlah 3 dan $fourth.Key 4 dalam contoh ini.

Saya menyebutnya salinan dangkal karena jika Anda memiliki objek berlapis (objek dengan properti berisi objek lain), hanya nilai tingkat atas yang disalin. Objek anak akan saling mereferensikan.

PSTypeName untuk jenis objek kustom

Sekarang setelah kita memiliki objek, ada beberapa hal lagi yang dapat kita lakukan dengannya yang mungkin tidak hampir sama jelasnya. Hal pertama yang perlu kita lakukan adalah memberinya PSTypeName. Ini adalah cara paling umum saya melihat orang melakukannya:

$myObject.PSObject.TypeNames.Insert(0,"My.Object")

Saya baru-baru ini menemukan cara lain untuk melakukan ini dari posting ini oleh /u/markekraus. Saya melakukan sedikit penggalian dan lebih banyak posting tentang ide dari Adam Bertram dan Mike Shepard di mana mereka berbicara tentang pendekatan ini yang memungkinkan Anda untuk menentukannya sebaris.

$myObject = [PSCustomObject]@{
    PSTypeName = 'My.Object'
    Name       = 'Kevin'
    Language   = 'PowerShell'
    State      = 'Texas'
}

Saya suka betapa baiknya ini hanya cocok dengan bahasa. Sekarang kita memiliki objek dengan nama jenis yang tepat, kita dapat melakukan beberapa hal lagi.

Catatan

Anda juga dapat membuat jenis PowerShell kustom menggunakan kelas PowerShell. Untuk informasi selengkapnya, lihat Gambaran Umum Kelas PowerShell.

Menggunakan DefaultPropertySet (jalan panjang)

PowerShell memutuskan properti apa yang akan ditampilkan secara default. Banyak perintah asli memiliki .ps1xmlfile pemformatan yang melakukan semua pengangkatan berat. Dari posting ini oleh Boe Prox, ada cara lain bagi kita untuk melakukan ini pada objek kustom kita hanya menggunakan PowerShell. Kita bisa memberikannya MemberSet untuk digunakan.

$defaultDisplaySet = 'Name','Language'
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet)
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
$MyObject | Add-Member MemberSet PSStandardMembers $PSStandardMembers

Sekarang ketika objek saya hanya jatuh ke shell, itu hanya akan menunjukkan properti tersebut secara default.

Update-TypeData dengan DefaultPropertySet

Ini bagus tetapi baru-baru ini saya melihat cara yang lebih baik menggunakan Update-TypeData untuk menentukan properti default.

$TypeData = @{
    TypeName = 'My.Object'
    DefaultDisplayPropertySet = 'Name','Language'
}
Update-TypeData @TypeData

Itu cukup sederhana sehingga saya hampir bisa mengingatnya jika saya tidak memiliki posting ini sebagai referensi cepat. Sekarang saya dapat dengan mudah membuat objek dengan banyak properti dan masih memberikan tampilan bersih yang bagus ketika melihatnya dari shell. Jika saya perlu mengakses atau melihat properti lain tersebut, properti tersebut masih ada.

$myObject | Format-List *

Update-TypeData dengan ScriptProperty

Sesuatu yang saya dapatkan dari video itu membuat properti skrip untuk objek Anda. Ini akan menjadi waktu yang tepat untuk menunjukkan bahwa ini juga berfungsi untuk objek yang ada.

$TypeData = @{
    TypeName = 'My.Object'
    MemberType = 'ScriptProperty'
    MemberName = 'UpperCaseName'
    Value = {$this.Name.toUpper()}
}
Update-TypeData @TypeData

Anda dapat melakukan ini sebelum objek Anda dibuat atau setelahnya dan itu akan tetap berfungsi. Inilah yang membuat ini berbeda dari penggunaan Add-Member dengan properti skrip. Ketika Anda menggunakan Add-Member cara saya mereferensikan sebelumnya, itu hanya ada pada instans objek tertentu. Yang satu ini berlaku untuk semua objek dengan ini TypeName.

Parameter fungsi

Anda sekarang dapat menggunakan jenis kustom ini untuk parameter dalam fungsi dan skrip Anda. Anda dapat memiliki satu fungsi membuat objek kustom ini lalu meneruskannya ke fungsi lain.

param( [PSTypeName('My.Object')]$Data )

PowerShell mengharuskan objek adalah jenis yang Anda tentukan. Ini melemparkan kesalahan validasi jika jenis tidak cocok secara otomatis untuk menyimpan langkah pengujian untuk itu dalam kode Anda. Contoh yang bagus untuk membiarkan PowerShell melakukan apa yang terbaik.

OutputType Fungsi

Anda juga dapat menentukan OutputType untuk fungsi lanjutan Anda.

function Get-MyObject
{
    [OutputType('My.Object')]
    [CmdletBinding()]
        param
        (
            ...

Nilai atribut OutputType hanya catatan dokumentasi. Ini tidak berasal dari kode fungsi atau dibandingkan dengan output fungsi aktual.

Alasan utama Anda akan menggunakan jenis output adalah agar informasi meta tentang fungsi Anda mencerminkan niat Anda. Hal-hal seperti Get-Command dan Get-Help yang dapat dimanfaatkan oleh lingkungan pengembangan Anda. Jika Anda menginginkan informasi lebih lanjut, lihat bantuan untuk itu: about_Functions_OutputTypeAttribute.

Dengan demikian, jika Anda menggunakan Pester untuk menyatukan pengujian fungsi Anda maka akan menjadi ide yang baik untuk memvalidasi objek output yang cocok dengan OutputType Anda. Ini bisa menangkap variabel yang hanya jatuh ke pipa ketika mereka seharusnya tidak.

Menutup ide

Konteks ini adalah tentang [PSCustomObject], tetapi banyak informasi ini berlaku untuk objek secara umum.

Saya telah melihat sebagian besar fitur ini dalam melewati sebelumnya tetapi tidak pernah melihat mereka disajikan sebagai kumpulan informasi tentang PSCustomObject. Minggu lalu aku tersandung satu lagi dan terkejut bahwa aku belum pernah melihatnya sebelumnya. Saya ingin menarik semua ide-ide ini bersama-sama sehingga Anda mudah-mudahan dapat melihat gambaran yang lebih besar dan menyadarinya ketika Anda memiliki kesempatan untuk menggunakannya. Saya harap Anda belajar sesuatu dan dapat menemukan cara untuk bekerja ini ke dalam skrip Anda.