PSCustomObject hakkında bilmek istediğiniz her şey
PSCustomObject, PowerShell araç kemerinize ekleyebileceğiniz harika bir araçtır. Temel bilgilerle başlayalım ve daha gelişmiş özelliklere doğru ilerleyelim. PSCustomObject kullanmanın ardındaki fikir, yapılandırılmış veriler oluşturmanın basit bir yoluna sahip olmaktır. İlk örneğe bakın, bunun ne anlama geldiğini daha iyi anlayacaksınız.
Not
Bu makalenin orijinal versiyonu @KevinMarquette tarafından yazılan blogda yayınlandı. PowerShell ekibi bu içeriği bizimle paylaştığı için Kevin'e teşekkür ediyor. Lütfen PowerShellExplained.com adresindeki bloguna göz atın.
PSCustomObject oluşturma
PowerShell'de [PSCustomObject] kullanmayı seviyorum. Kullanılabilir bir nesne oluşturmak hiç bu kadar kolay olmamıştı. Bu nedenle nesne oluşturmanın diğer tüm yollarını atlayacağım ancak bu örneklerin çoğunun PowerShell v3.0 ve üzeri olduğunu belirtmem gerekiyor.
$myObject = [PSCustomObject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Bu yöntem benim için iyi çalışıyor çünkü hemen hemen her şey için hashtable kullanıyorum. Ancak PowerShell'in karma tabloları daha çok bir nesne gibi ele almasını istediğim zamanlar vardır. Farkı ilk fark ettiğiniz yer, Format-Table veya Export-CSV kullanmak istediğinizde ve hash tablosunun yalnızca anahtar/değer çiftlerinden oluşan bir koleksiyon olduğunu fark ettiğiniz zamandır.
Daha sonra normal bir nesne gibi değerlere erişebilir ve bunları kullanabilirsiniz.
$myObject.Name
Hashtable'ı dönüştürme
Hazır konu açılmışken şunu yapabileceğinizi biliyor muydunuz:
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = [pscustomobject]$myHashtable
Ben nesneyi en baştan yaratmayı tercih ederim ama bazen önce karma tablosuyla çalışmanız gerekir. Bu örnek işe yarar çünkü yapıcı nesne özellikleri için bir hash tablosu alır. Önemli bir not, bu yöntem işe yarasa da tam bir eşdeğer olmadığıdır. En büyük fark özelliklerin sırasının korunmamasıdır.
Sırayı korumak istiyorsanız Sıralı hashtable'lara bakın.
Eski yaklaşım
İnsanların özel nesneler oluşturmak için New-Object kullandığını görmüş olabilirsiniz.
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = New-Object -TypeName PSObject -Property $myHashtable
Bu yöntem biraz daha yavaştır ancak PowerShell'in ilk sürümlerinde en iyi seçeneğiniz olabilir.
Bir dosyaya kaydetme
Bir hash tablosunu bir dosyaya kaydetmenin en iyi yolunun onu JSON olarak kaydetmek olduğunu düşünüyorum. Bunu bir [PSCustomObject] dosyasına geri aktarabilirsiniz
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path
$myObject = Get-Content -Path $Path | ConvertFrom-Json
Dosyaları okumanın ve yazmanın birçok yolu başlıklı makalemde nesneleri bir dosyaya kaydetmenin daha fazla yolunu ele alıyorum.
Özelliklerle çalışma
Özellikler ekleme
Add-Member ile PSCustomObject öğenize hâlâ yeni özellikler ekleyebilirsiniz.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'
$myObject.ID
Özellikleri kaldır
Ayrıca bir nesnenin özelliklerini de kaldırabilirsiniz.
$myObject.psobject.properties.remove('ID')
.psobject, temel nesne meta verilerine erişmenizi sağlayan gerçek bir üyedir. İçsel üyeler hakkında daha fazla bilgi için bkz. about_Intrinsic_Members.
Özellik adlarının numaralandırılması
Bazen bir nesnedeki tüm özellik adlarının bir listesine ihtiyaç duyarsınız.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
Aynı listeyi psobject özelliğinden de alabiliriz.
$myobject.psobject.properties.name
Not
Get-Member özellikleri alfabetik sıraya göre döndürür. Özellik adlarını numaralandırmak için üye erişim operatörünün kullanılması, özellikleri nesnede tanımlandıkları sıraya göre döndürür.
Özelliklere dinamik olarak erişme
Özellik değerlerine doğrudan erişebileceğinizi daha önce belirtmiştim.
$myObject.Name
Özellik adı için bir dize kullanabilirsiniz; yine de çalışacaktır.
$myObject.'Name'
Bunu bir adım daha atıp özellik adı için bir değişken kullanabiliriz.
$property = 'Name'
$myObject.$property
Bunun garip göründüğünü biliyorum ama işe yarıyor.
PSCustomObject'i hash tablosuna dönüştürün
Son bölümden devam etmek için özellikleri dinamik olarak inceleyebilir ve onlardan bir karma tablosu oluşturabilirsiniz.
$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
$hashtable[$property] = $myObject.$property
}
Özellikler için test etme
Bir özelliğin mevcut olup olmadığını bilmeniz gerekiyorsa, o özelliğin bir değere sahip olup olmadığını kontrol edebilirsiniz.
if( $null -ne $myObject.ID )
Ancak değer $null olabilirse, psobject.properties dosyasını kontrol ederek var olup olmadığını kontrol edebilirsiniz.
if( $myobject.psobject.properties.match('ID').Count )
Nesne yöntemleri ekleme
Bir nesneye komut dosyası yöntemi eklemeniz gerekiyorsa bunu Add-Member ve ScriptBlock ile yapabilirsiniz. Geçerli nesneye referans veren this otomatik değişkenini kullanmanız gerekir. Burada bir nesneyi hash tablosuna dönüştürecek bir scriptblock bulunmaktadır. (son örnekteki kodun aynısı)
$ScriptBlock = {
$hashtable = @{}
foreach( $property in $this.psobject.properties.name )
{
$hashtable[$property] = $this.$property
}
return $hashtable
}
Daha sonra bunu bir script özelliği olarak nesnemize ekliyoruz.
$memberParam = @{
MemberType = "ScriptMethod"
InputObject = $myobject
Name = "ToHashtable"
Value = $scriptBlock
}
Add-Member @memberParam
Daha sonra fonksiyonumuzu şu şekilde çağırabiliriz:
$myObject.ToHashtable()
Nesneler ve Değer türleri
Nesneler ve değer türleri değişken atamalarını aynı şekilde işlemez. Değer türlerini birbirine atarsanız yalnızca değer yeni değişkene kopyalanır.
$first = 1
$second = $first
$second = 2
Bu durumda $first 1'dir ve $second 2'dir.
Nesne değişkenleri gerçek nesneye bir referans tutar. Bir nesneyi yeni bir değişkene atadığınızda, bunlar yine de aynı nesneye referans verir.
$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4
$third ve $fourth bir nesnenin aynı örneğine referans verdiğinden, hem $third.key hem de $fourth.Key kodu > 4'tür.
psobject.copy()
Bir nesnenin gerçek bir kopyasına ihtiyacınız varsa onu klonlayabilirsiniz.
$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4
Klon, nesnenin yüzeysel bir kopyasını oluşturur. Artık farklı örnekleri var ve bu örnekte $third.key 3 ve $fourth.Key 4'tür.
Buna yüzeysel kopya diyorum çünkü iç içe geçmiş nesneleriniz varsa (özellikleri olan nesneler başka nesneler içerir), yalnızca üst düzey değerler kopyalanır. Alt nesneler birbirine referans verecektir.
Özel nesne türleri için PSTypeName
Artık bir nesnemiz olduğuna göre, onunla yapabileceğimiz, o kadar da belirgin olmayabilecek birkaç şey daha var. Yapmamız gereken ilk şey ona bir PSTypeName vermek. İnsanların bunu yaptığını gördüğüm en yaygın yol budur:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Yakın zamanda Redditor u/markekraus'ta bunu yapmanın başka bir yolunu keşfettim. Satır içi tanımlamanıza olanak tanıyan bu yaklaşımdan bahsediyor.
$myObject = [PSCustomObject]@{
PSTypeName = 'My.Object'
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
Bunun dile ne kadar güzel uyduğunu seviyorum. Artık uygun tip ismine sahip bir nesnemiz olduğuna göre, başka şeyler de yapabiliriz.
Not
PowerShell sınıflarını kullanarak özel PowerShell türleri de oluşturabilirsiniz. Daha fazla bilgi için bkz. PowerShell Sınıfına Genel Bakış.
DefaultPropertySet'i kullanma (uzun yol)
PowerShell, varsayılan olarak hangi özelliklerin görüntüleneceğine bizim için karar verir. Yerel komutların çoğunda, tüm ağır işleri yapan bir .ps1xml biçimlendirme dosyası bulunur. Boe Prox'un bu gönderisinden, bunu yalnızca PowerShell kullanarak özel nesnemizde yapmanın başka bir yolu var. Kullanması için ona bir MemberSet verebiliriz.
$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
Artık nesnem kabuğa düştüğünde, varsayılan olarak yalnızca bu özellikleri gösterecek.
DefaultPropertySet ile TypeData'yı Güncelle
Bu hoş ama yakın zamanda varsayılan özellikleri belirlemek için Update-TypeData'yı kullanmanın daha iyi bir yolunu gördüm.
$TypeData = @{
TypeName = 'My.Object'
DefaultDisplayPropertySet = 'Name','Language'
}
Update-TypeData @TypeData
Bu, hızlı bir referans olarak bu yazıya sahip olmasaydım neredeyse hatırlayabileceğim kadar basit. Artık birçok özelliğe sahip nesneleri kolayca oluşturabiliyorum ve ona kabuktan bakarken yine de güzel ve temiz bir görünüm sunabiliyorum. Diğer özelliklere erişmem veya onları görmem gerekirse, bunlar hâlâ oradadır.
$myObject | Format-List *
ScriptProperty ile TypeData'yı Güncelle
Bu videodan anladığım başka bir şey de nesneleriniz için komut dosyası özellikleri oluşturmaktı. Bu, bunun mevcut nesneler için de işe yaradığını belirtmek için iyi bir zaman olacaktır.
$TypeData = @{
TypeName = 'My.Object'
MemberType = 'ScriptProperty'
MemberName = 'UpperCaseName'
Value = {$this.Name.toUpper()}
}
Update-TypeData @TypeData
Bunu nesneniz oluşturulmadan önce veya oluşturulduktan sonra yapabilirsiniz; yine de çalışmaya devam edecektir. Bunu Üye Ekle'yi bir komut dosyası özelliğiyle kullanmaktan farklı kılan da budur. Üye Ekle'yi daha önce bahsettiğim şekilde kullandığınızda, bu yalnızca nesnenin belirli bir örneğinde bulunur. Bu, bu TypeName'e sahip tüm nesneler için geçerlidir.
Fonksiyon parametreleri
Artık bu özel türleri, işlevlerinizdeki ve komut dosyalarınızdaki parametreler için kullanabilirsiniz. Bir işlevin bu özel nesneleri oluşturmasını ve ardından bunları diğer işlevlere aktarmasını sağlayabilirsiniz.
param( [PSTypeName('My.Object')]$Data )
PowerShell, nesnenin belirttiğiniz türde olmasını gerektirir. Türün otomatik olarak eşleşmemesi durumunda, kodunuzda test etme adımını kaydetmeniz için bir doğrulama hatası atar. PowerShell'in en iyi yaptığı şeyi yapmasına izin vermenin harika bir örneği.
İşlev Çıkış Türü
Gelişmiş işlevleriniz için bir OutputType da tanımlayabilirsiniz.
function Get-MyObject
{
[OutputType('My.Object')]
[CmdletBinding()]
param
(
...
OutputType özelliğinin değeri yalnızca bir belge notudur. İşlev kodundan türetilmemiştir veya gerçek işlev çıktısıyla karşılaştırılmamıştır.
Bir çıktı türü kullanmanızın ana nedeni, işleviniz hakkındaki meta bilgilerin niyetinizi yansıtmasıdır. Geliştirme ortamınızın yararlanabileceği Get-Command ve Get-Help gibi şeyler. Daha fazla bilgi istiyorsanız yardıma bakın: about_Functions_OutputTypeAttribute.
Bununla birlikte, eğer işlevlerinizi birim test etmek için Pester kullanıyorsanız çıktı nesnelerinin OutputType'ınızla eşleştiğini doğrulamak iyi bir fikir olacaktır. Bu, olmaması gerektiği halde boruya düşen değişkenleri yakalayabilir.
Düşünceleri kapatmak
Bunun bağlamı tamamen [PSCustomObject] ile ilgiliydi, ancak bu bilgilerin çoğu genel olarak nesneler için geçerlidir.
Bu özelliklerin çoğunu daha önce de görmüştüm ancak bunların PSCustomObject'te bir bilgi koleksiyonu olarak sunulduğunu hiç görmemiştim. Daha geçen hafta başka bir tanesine rastladım ve onu daha önce görmediğime şaşırdım. Büyük resmi görebilmeniz ve bunları kullanma fırsatınız olduğunda bunların farkına varabilmeniz için tüm bu fikirleri bir araya getirmek istedim. Umarım bir şeyler öğrenmişsinizdir ve bunu senaryolarınızda kullanmanın bir yolunu bulabilirsiniz.