Share via


Karma tablolarla ilgili bilmek istediğiniz her şey

Bir adım geri gidip hashtable'lar hakkında konuşmak istiyorum. Artık her zaman kullanıyorum. Dün geceki kullanıcı grubu toplantımızdan sonra birine bu konuda ders veriyordum ve onunkiyle aynı kafa karışıklığını yaşadığımı fark ettim. Hashtable'lar PowerShell'de gerçekten önemlidir, bu nedenle bunları iyi anlamak iyidir.

Not

Bu makalenin özgün sürümü, @KevinMarquette tarafından yazılan blogda yer almıştır. PowerShell ekibi, bu içeriği bizimle paylaştığı için Kevin'e teşekkür ederiz. Lütfen PowerShellExplained.com'daki blogunu inceleyin.

Bir şeyler koleksiyonu olarak Hashtable

İlk olarak karma tablo'nun geleneksel tanımında bir Hashtable'ı koleksiyon olarak görmenizi istiyorum. Bu tanım, daha sonra daha gelişmiş şeyler için kullanıldıklarında nasıl çalıştıklarını temel bir şekilde anlamanızı sağlar. Bu anlayışın atlanması genellikle kafa karışıklığının kaynağıdır.

Dizi nedir?

Hashtable'ın ne olduğuna geçmeden önce dizilerden bahsetmem gerekiyor. Bu tartışmanın amacı doğrultusunda, dizi bir değer veya nesne listesi veya koleksiyonudur.

$array = @(1,2,3,5,7,11)

Öğelerinizi bir diziye ekledikten sonra, listeyi yinelemek için kullanabilir foreach veya dizideki tek tek öğelere erişmek için bir dizin kullanabilirsiniz.

foreach($item in $array)
{
    Write-Output $item
}

Write-Output $array[3]

Değerleri aynı şekilde bir dizin kullanarak da güncelleştirebilirsiniz.

$array[2] = 13

Dizilerdeki yüzeyi kazıdım ama bu onları karma tablolara ilerledikçe doğru bağlama yerleştirmeli.

Karma tablo nedir?

PowerShell'in bunları kullandığı diğer yöntemlere geçmeden önce genel anlamda karma tablolarının ne olduğu hakkında temel bir teknik açıklamayla başlayacağım.

Karma tablo, bir diziye çok benzeyen bir veri yapısıdır, ancak her değeri (nesne) bir anahtar kullanarak depolarsınız. Temel bir anahtar/değer deposu. İlk olarak boş bir karma tablo oluşturacağız.

$ageList = @{}

Bir karma tablo tanımlamak için ayraçlar yerine ayraçların kullanıldığına dikkat edin. Ardından aşağıdaki gibi bir anahtar kullanarak bir öğe ekleriz:

$key = 'Kevin'
$value = 36
$ageList.add( $key, $value )

$ageList.add( 'Alex', 9 )

Kişinin adı anahtar, yaşı ise kaydetmek istediğim değer.

Erişim için köşeli ayraçları kullanma

Değerlerinizi karma tabloya ekledikten sonra, aynı anahtarı kullanarak (dizi için sahip olacağınız gibi sayısal bir dizin kullanmak yerine) bunları geri çekebilirsiniz.

$ageList['Kevin']
$ageList['Alex']

Kevin'ın yaşını istersem, ona erişmek için adını kullanırım. Bu yaklaşımı karma tabloya değer eklemek veya güncelleştirmek için de kullanabiliriz. Bu, yukarıdaki işlevi kullanmak add() gibidir.

$ageList = @{}

$key = 'Kevin'
$value = 36
$ageList[$key] = $value

$ageList['Alex'] = 9

Daha sonraki bir bölümde ele alacağım değerlere erişmek ve bunları güncelleştirmek için kullanabileceğiniz başka bir söz dizimi var. PowerShell'e başka bir dilden geliyorsanız, bu örnekler daha önce karma tablolarını nasıl kullandığınıza uygun olmalıdır.

Değerlerle karma tablo oluşturma

Şu ana kadar bu örnekler için boş bir karma tablo oluşturdum. Anahtarları ve değerleri oluştururken önceden doldurabilirsiniz.

$ageList = @{
    Kevin = 36
    Alex  = 9
}

Arama tablosu olarak

Bu tür bir karma tablo için gerçek değer, bunları arama tablosu olarak kullanabilmenizdir. Aşağıda basit bir örnek verilmiştir.

$environments = @{
    Prod = 'SrvProd05'
    QA   = 'SrvQA02'
    Dev  = 'SrvDev12'
}

$server = $environments[$env]

Bu örnekte değişken için $env bir ortam belirtirsiniz ve bu ortam doğru sunucuyu seçer. Bunun gibi bir seçim için bir switch($env){...} kullanabilirsiniz, ancak karma tablo iyi bir seçenektir.

Daha sonra kullanmak üzere arama tablosunu dinamik olarak derlediğinizde bu daha da iyi hale gelir. Bu nedenle, bir şeye çapraz başvurmanız gerektiğinde bu yaklaşımı kullanmayı düşünün. PowerShell ile Where-Objectboruyu filtrelemede o kadar iyi olmasaydı bunu daha da fazla göreceğimizi düşünüyorum. Performansın önemli olduğu bir durumdaysanız bu yaklaşımın dikkate alınması gerekir.

Daha hızlı olduğunu söyleyemem ama performans önemliyse test et kuralına uyuyor.

Çoklu bölüm

Genel olarak, bir hashtable'ı bir anahtar/değer çifti olarak düşünür ve burada bir anahtar sağlarsınız ve bir değer alırsınız. PowerShell, birden çok değer almak için bir dizi anahtar sağlamanıza olanak tanır.

$environments[@('QA','DEV')]
$environments[('QA','DEV')]
$environments['QA','DEV']

Bu örnekte, yukarıdan aynı arama karma tablolarını kullanıyorum ve eşleşmeleri almak için üç farklı dizi stili sağlıyorum. Bu, PowerShell'de çoğu kişinin farkında olmayan gizli bir mücevherdir.

Karma tablo yineleme

Karma tablo bir anahtar/değer çiftleri koleksiyonu olduğundan, bir dizi veya normal bir öğe listesi için yaptığınızdan farklı bir şekilde yineleme yaparsınız.

Fark edilmesi gereken ilk şey, karma tablonuzun kanalını oluşturursanız, borunun bunu tek bir nesne gibi ele alır.

PS> $ageList | Measure-Object
count : 1

Özelliği size kaç değer içerdiğini bildirse .count de.

PS> $ageList.count
2

İhtiyacınız olan tek şey yalnızca değerlerse özelliğini kullanarak .values bu sorunu çözebilirsiniz.

PS> $ageList.values | Measure-Object -Average
Count   : 2
Average : 22.5

Genellikle anahtarları listelemek ve değerlere erişmek için kullanmak daha yararlıdır.

PS> $ageList.keys | ForEach-Object{
    $message = '{0} is {1} years old!' -f $_, $ageList[$_]
    Write-Output $message
}
Kevin is 36 years old
Alex is 9 years old

Aşağıda bir döngü ile aynı örnek verilmiştir foreach(){...} .

foreach($key in $ageList.keys)
{
    $message = '{0} is {1} years old' -f $key, $ageList[$key]
    Write-Output $message
}

Karma tablodaki her anahtarı yürüyoruz ve ardından değere erişmek için bu anahtarı kullanıyoruz. Bu, karma tablolarla koleksiyon olarak çalışırken yaygın olarak kullanılan bir desendir.

GetEnumerator()

Bu da bizi hashtable'ımız üzerinde yinelemeye GetEnumerator() götürür.

$ageList.GetEnumerator() | ForEach-Object{
    $message = '{0} is {1} years old!' -f $_.key, $_.value
    Write-Output $message
}

Numaralandırıcı size her anahtar/değer çiftini birer birer verir. Bu kullanım örneği için özel olarak tasarlanmıştır. Mark Kraus'a bunu hatırlattın diye teşekkür ederim.

BadEnumeration

Önemli ayrıntılardan biri, bir karma tablo numaralandırılırken değiştirilemeyecek olmasıdır. Temel $environments örneğimizle başlıyorsak:

$environments = @{
    Prod = 'SrvProd05'
    QA   = 'SrvQA02'
    Dev  = 'SrvDev12'
}

Ve her anahtarı aynı sunucu değerine ayarlamaya çalışmak başarısız olur.

$environments.Keys | ForEach-Object {
    $environments[$_] = 'SrvDev03'
}

An error occurred while enumerating through a collection: Collection was modified;
enumeration operation may not execute.
+ CategoryInfo          : InvalidOperation: tableEnumerator:HashtableEnumerator) [],
 RuntimeException
+ FullyQualifiedErrorId : BadEnumeration

Bu, aynı zamanda iyi gibi görünmesine rağmen de başarısız olur:

foreach($key in $environments.keys) {
    $environments[$key] = 'SrvDev03'
}

Collection was modified; enumeration operation may not execute.
    + CategoryInfo          : OperationStopped: (:) [], InvalidOperationException
    + FullyQualifiedErrorId : System.InvalidOperationException

Bu durumun püf noktası, numaralandırmayı yapmadan önce anahtarları kopyalamaktır.

$environments.Keys.Clone() | ForEach-Object {
    $environments[$_] = 'SrvDev03'
}

Özellik koleksiyonu olarak Hashtable

Şimdiye kadar karma tablomuza yerleştirdiğimiz nesne türlerinin tümü aynı nesne türündeydi. Tüm bu örneklerde yaşları kullandım ve anahtar kişinin adıydı. Bu, her nesne koleksiyonunuzun bir adı olduğunda buna bakmanın harika bir yoludur. PowerShell'de karma tablo kullanmanın bir diğer yaygın yolu, anahtarı özelliğin adı olan bir özellik koleksiyonunu tutmaktır. Sonraki örnekte bu fikre adım atacağım.

Özellik tabanlı erişim

Özellik tabanlı erişimin kullanılması, karma tablo dinamiklerini ve bunları PowerShell'de nasıl kullanabileceğinizi değiştirir. Aşağıda yukarıdan anahtarlara özellik olarak davranan olağan örneğimiz verilmiştir.

$ageList = @{}
$ageList.Kevin = 35
$ageList.Alex = 9

Yukarıdaki örneklerde olduğu gibi, bu örnek de karma tablo içinde yoksa bu anahtarları ekler. Anahtarlarınızı nasıl tanımladığınıza ve değerlerinizin ne olduğuna bağlı olarak, bu biraz garip veya mükemmel bir uyumdur. Yaş listesi örneği bu noktaya kadar çok çalıştı. İleriye doğru gidebilmek için yeni bir örne ihtiyacımız var.

$person = @{
    name = 'Kevin'
    age  = 36
}

Bunun gibi öznitelikler $person ekleyebilir ve bunlara erişebiliriz.

$person.city = 'Austin'
$person.state = 'TX'

Aniden bu karma tablo bir nesne gibi hissetmeye ve hareket etmeye başlar. Hala bir şeyler koleksiyonu olduğundan yukarıdaki tüm örnekler geçerli olmaya devam eder. Sadece farklı bir bakış açısıyla yaklaşıyoruz.

Anahtarlar ve değerler denetleniyor

Çoğu durumda, değeri şu şekilde test edebilirsiniz:

if( $person.age ){...}

Basit ama benim için birçok hatanın kaynağı oldu çünkü mantığımdaki önemli bir ayrıntıyı gözden kaçırıyorum. Anahtarın mevcut olup olmadığını test etmek için kullanmaya başladım. Değer veya sıfır olduğunda $false , bu deyim beklenmedik bir şekilde döndürüldü $false .

if( $person.age -ne $null ){...}

Bu, sıfır değerler için bu soruna geçici bir çözümdür, ancak $null ve var olmayan anahtarlar için geçerli değildir. Çoğu zaman bu ayrımı yapmanız gerekmez, ancak bunu yaptığınızda işlevleri vardır.

if( $person.ContainsKey('age') ){...}

Ayrıca anahtarı bilmeden veya koleksiyonun tamamını yinelemeden bir değeri test etmeniz gereken durum için de bir örneğimiz vardır ContainsValue() .

Anahtarları kaldırma ve temizleme

İşlevle .Remove() anahtarları kaldırabilirsiniz.

$person.remove('age')

Onlara bir $null değer atamak, sizi değeri olan bir $null anahtarla bırakır.

Karma tablo temizlemenin yaygın bir yolu, bunu yalnızca boş bir karma tabloya başlatmaktır.

$person = @{}

Bu işe yarasa da, bunun yerine işlevini kullanmayı clear() deneyin.

$person.clear()

Bu, işlevinin kullanılması kendi kendine belgeleme kodu oluşturduğu ve kodun amaçlarını çok temiz hale getirdiği örneklerden biridir.

Tüm eğlenceli şeyler

Sıralı karma tablo

Karma tablo varsayılan olarak sıralanmamıştır (veya sıralanmamıştır). Geleneksel bağlamda, değerlere erişmek için her zaman bir anahtar kullandığınızda sıra önemli değildir. Özelliklerin tanımladığınız sırada kalmasını istediğinizi fark edebilirsiniz. Neyse ki bunu anahtar sözcükle gerçekleştirmenin ordered bir yolu var.

$person = [ordered]@{
    name = 'Kevin'
    age  = 36
}

Artık anahtarları ve değerleri numaralandırdığınızda, bunlar bu sırada kalır.

Satır içi karma tablo

Bir satırda karma tablo tanımlarken anahtar/değer çiftlerini noktalı virgülle ayırabilirsiniz.

$person = @{ name = 'kevin'; age = 36; }

Bunları boruda oluşturuyorsanız bu kullanışlı olacaktır.

Ortak işlem hattı komutlarında özel ifadeler

Özel veya hesaplanmış özellikler oluşturmak için karma tablo kullanımını destekleyen birkaç cmdlet vardır. Bunu genellikle ve Format-Tableile Select-Object görürsünüz. Karma tablolarda, tam olarak genişletildiğinde şuna benzer özel bir söz dizimi vardır.

$property = @{
    name = 'totalSpaceGB'
    expression = { ($_.used + $_.free) / 1GB }
}

name cmdlet'inin bu sütunu etiketlediğini gösterir. , expression yürütülen bir betik bloğudur ve burada $_ kanaldaki nesnenin değeridir. İşte bu betik çalışıyor:

$drives = Get-PSDrive | Where Used
$drives | Select-Object -Property name, $property

Name     totalSpaceGB
----     ------------
C    238.472652435303

Bunu bir değişkene yerleştirdim ama satır içinde kolayca tanımlanabilir ve siz bu değişkene kadar kısaltabilirsiniz nameexpressionne.

$drives | Select-Object -property name, @{n='totalSpaceGB';e={($_.used + $_.free) / 1GB}}

Bunun komutlar oluşturması ve genellikle benim girmeyeceğim bazı kötü davranışları teşvik etmelerinden şahsen hoşlanmıyorum. Betiklerde bu yaklaşımı kullanmak yerine yeni bir karma tablo veya pscustomobject istediğim tüm alan ve özelliklerle oluşturma olasılığım daha yüksektir. Ama bunu yapmak için çok fazla kod var. Daha sonra bir pscustomobject şey oluşturmaktan bahsediyorum.

Özel sıralama ifadesi

Nesnelerde sıralamak istediğiniz veriler varsa, bir koleksiyonu sıralamak kolaydır. Verileri sıralamadan önce nesnesine ekleyebilir veya için Sort-Objectözel bir ifade oluşturabilirsiniz.

Get-ADUser | Sort-Object -Property @{ e={ Get-TotalSales $_.Name } }

Bu örnekte kullanıcıların listesini alıyorum ve yalnızca sıralama için ek bilgi almak için bazı özel cmdlet'leri kullanıyorum.

Karma Tablo listesini sıralama

Sıralamak istediğiniz karma tablolarınızın bir listesi varsa anahtarlarınızı özellik olarak işlemediğini Sort-Object görürsünüz. Özel bir sıralama ifadesi kullanarak bunu yuvarlayabiliriz.

$data = @(
    @{name='a'}
    @{name='c'}
    @{name='e'}
    @{name='f'}
    @{name='d'}
    @{name='b'}
)

$data | Sort-Object -Property @{e={$_.name}}

Cmdlet'lere karma tablo ekleme

Bu, birçok kişinin erken saatlerde keşfetmediğim karma tablolarla ilgili en sevdiğim şeylerden biridir. Burada fikir, tüm özellikleri tek bir satırdaki bir cmdlet'e sağlamak yerine bunları önce bir karma tabloya paketleyebileceğinizdir. Ardından hashtable'ı işleve özel bir şekilde verebilirsiniz. Aşağıda, normal şekilde bir DHCP kapsamı oluşturma örneği verilmiştir.

Add-DhcpServerV4Scope -Name 'TestNetwork' -StartRange '10.0.0.2' -EndRange '10.0.0.254' -SubnetMask '255.255.255.0' -Description 'Network for testlab A' -LeaseDuration (New-TimeSpan -Days 8) -Type "Both"

Sıçrama kullanılmadan, tüm bu öğelerin tek bir satırda tanımlanması gerekir. Ekrandan kaydırılır veya göründüğü yere kaydırılır. Şimdi bunu, sıçrama kullanan bir komutla karşılaştırın.

$DHCPScope = @{
    Name          = 'TestNetwork'
    StartRange    = '10.0.0.2'
    EndRange      = '10.0.0.254'
    SubnetMask    = '255.255.255.0'
    Description   = 'Network for testlab A'
    LeaseDuration = (New-TimeSpan -Days 8)
    Type          = "Both"
}
Add-DhcpServerV4Scope @DHCPScope

yerine işaretinin @$ kullanılması, splat işlemini çağıran işlemdir.

Bu örneğin ne kadar kolay okunduğunu takdir etmek için biraz zaman ayırın. Bunlar, tüm aynı değerlerle tam olarak aynı komutlardır. İkincisini anlamak ve ileriye doğru devam etmek daha kolaydır.

Komutun çok uzun olduğu her zaman sıçramayı kullanıyorum. Penceremin sağa kaymasına neden olacak kadar uzun bir süre tanımladım. Bir işlevin üç özelliğine isabet edersem, bunu bir sıçramış karma tablo kullanarak yeniden yazma olasılığım vardır.

İsteğe bağlı parametreler için sıçrama

Sıçratmak için kullandığım en yaygın yollardan biri, betiğimde başka bir yerden gelen isteğe bağlı parametrelerle ilgilenmektir. İsteğe bağlı $Credential bağımsız değişkeni olan bir Get-CIMInstance çağrıyı sarmalayan bir işlevim olduğunu varsayalım.

$CIMParams = @{
    ClassName = 'Win32_Bios'
    ComputerName = $ComputerName
}

if($Credential)
{
    $CIMParams.Credential = $Credential
}

Get-CIMInstance @CIMParams

Karma tablomu ortak parametrelerle oluşturarak başlıyorum. Sonra varsa öğesini $Credential ekliyorum. Burada sıçrama kullandığım için kodumda çağrısının Get-CIMInstance yalnızca bir kez olması gerekiyor. Bu tasarım deseni çok temizdir ve çok sayıda isteğe bağlı parametreyi kolayca işleyebilir.

Adil olmak gerekirse, parametrelerin değerlerine izin $null vermek için komutlarınızı yazabilirsiniz. Yalnızca çağırdığınız diğer komutlar üzerinde her zaman denetiminiz yoktur.

Birden çok platform

Aynı cmdlet'e birden çok karma tablo ekleyebilirsiniz. Özgün sıçrayan örneğimizi yeniden ziyaret edersek:

$Common = @{
    SubnetMask  = '255.255.255.0'
    LeaseDuration = (New-TimeSpan -Days 8)
    Type = "Both"
}

$DHCPScope = @{
    Name        = 'TestNetwork'
    StartRange  = '10.0.0.2'
    EndRange    = '10.0.0.254'
    Description = 'Network for testlab A'
}

Add-DhcpServerv4Scope @DHCPScope @Common

Çok sayıda komutla geçirmekte olduğum ortak bir parametre kümesine sahip olduğumda bu yöntemi kullanacağım.

Temiz kod için sıçrama

Kod temizlemenizi sağlarsa tek bir parametreyi sıçratmanızda bir sorun yoktur.

$log = @{Path = '.\logfile.log'}
Add-Content "logging this command" @log

Yürütülebilir dosyaları splatlama

Splatting, söz dizimi kullanan /param:value bazı yürütülebilir dosyalarda da çalışır. Robocopy.exeörneğin, bunun gibi bazı parametreleri vardır.

$robo = @{R=1;W=1;MT=8}
robocopy source destination @robo

Bunun o kadar yararlı olduğunu bilmiyorum ama ilginç buldum.

Karma tablo ekleme

Karmatable'lar, iki karmatable'ı birleştirmek için ekleme işlecini destekler.

$person += @{Zip = '78701'}

Bu yalnızca iki karma tablo bir anahtarı paylaşmazsa çalışır.

İç içe karma tablo

Karma tablo içinde değer olarak karma tablo kullanabiliriz.

$person = @{
    name = 'Kevin'
    age  = 36
}
$person.location = @{}
$person.location.city = 'Austin'
$person.location.state = 'TX'

İki anahtar içeren temel bir karma tabloyla başladım. Adlı location bir anahtarı boş bir karma tabloyla ekledim. Sonra bu karma tabloya son iki öğeyi location ekledim. Tüm bunları satır içinde de yapabiliriz.

$person = @{
    name = 'Kevin'
    age  = 36
    location = @{
        city  = 'Austin'
        state = 'TX'
    }
}

Bu, yukarıda gördüğümüz karmatable'ın aynısını oluşturur ve özelliklere aynı şekilde erişebilir.

$person.location.city
Austin

Nesnelerinizin yapısına yaklaşmanın birçok yolu vardır. İç içe karma tabloya bakmanın ikinci bir yolu aşağıdadır.

$people = @{
    Kevin = @{
        age  = 36
        city = 'Austin'
    }
    Alex = @{
        age  = 9
        city = 'Austin'
    }
}

Bu, karma tablolarını bir nesne koleksiyonu ve bir özellik koleksiyonu olarak kullanma kavramını karıştırır. Tercih ettiğiniz yaklaşımı kullanarak iç içe yerleştirilmiş olsalar bile değerlere kolayca erişebilirsiniz.

PS> $people.kevin.age
36
PS> $people.kevin['city']
Austin
PS> $people['Alex'].age
9
PS> $people['Alex']['City']
Austin

Dot özelliğini bir özellik gibi davranırken kullanma eğilimindeyim. Bunlar genellikle kodumda statik olarak tanımladığım şeylerdir ve bunları kafamın en üstünden tanıyorum. Listede gezinmem veya anahtarlara program aracılığıyla erişmem gerekirse anahtar adını sağlamak için köşeli ayraçları kullanıyorum.

foreach($name in $people.keys)
{
    $person = $people[$name]
    '{0}, age {1}, is in {2}' -f $name, $person.age, $person.city
}

Karma tablo iç içe yerleştirme özelliğine sahip olmak size birçok esneklik ve seçenek sunar.

İç içe karma tablolara bakma

Hashtable'ları iç içe yerleştirmeye başladığınızda bunları konsoldan kolayca incelemeniz gerekir. Son hashtable'ı alırsam şuna benzer bir çıkış elde ederim ve yalnızca bu kadar derine gider:

PS> $people
Name                           Value
----                           -----
Kevin                          {age, city}
Alex                           {age, city}

Bu tür şeylere ConvertTo-JSON bakmak için komutuma gidiyorum çünkü çok temiz ve diğer konularda sık sık JSON kullanıyorum.

PS> $people | ConvertTo-Json
{
    "Kevin":  {
                "age":  36,
                "city":  "Austin"
            },
    "Alex":  {
                "age":  9,
                "city":  "Austin"
            }
}

JSON'ı bilmeseniz bile aradığınızı görebilmeniz gerekir. Bunun gibi yapılandırılmış veriler için bir Format-Custom komut vardır ancak JSON görünümünü yine de daha çok beğeniyorum.

Nesne oluşturma

Bazen yalnızca bir nesneye sahip olmanız gerekir ve özellikleri tutmak için karma tablo kullanmak işi halletmez. En yaygın olarak anahtarları sütun adları olarak görmek istersiniz. A pscustomobject bunu kolaylaştırır.

$person = [pscustomobject]@{
    name = 'Kevin'
    age  = 36
}

$person

name  age
----  ---
Kevin  36

Başlangıçta bir olarak pscustomobject oluşturmasanız bile, gerektiğinde daha sonra istediğiniz zaman yayınlayabilirsiniz.

$person = @{
    name = 'Kevin'
    age  = 36
}

[pscustomobject]$person

name  age
----  ---
Kevin  36

Bundan sonra okumanız gereken pscustomobject için ayrıntılı bir yazma işlemi yaptım. Burada öğrenilen birçok şey üzerine inşa eder.

Dosyaya karma tablo okuma ve yazma

CSV'ye kaydetme

CSV'ye kaydetmek için karma tablo almakta zorlanıyor olmak, yukarıda değindiğim zorluklardan biridir. Karma tablonuzu bir'e pscustomobject dönüştürdüğünüzde doğru şekilde CSV'ye kaydedilir. Sütun sırasının korunması için bir pscustomobject ile başlamanıza yardımcı olur. Ancak gerekirse satır içi bir pscustomobject satıra dönüştürebilirsiniz.

$person | ForEach-Object{ [pscustomobject]$_ } | Export-CSV -Path $path

Bir kez daha pscustomobject kullanma ile ilgili yazmama göz atın.

İç içe hashtable'ı dosyaya kaydetme

bir dosyaya iç içe karma tablo kaydetmem ve yeniden okumam gerekirse, bunu yapmak için JSON cmdlet'lerini kullanıyorum.

$people | ConvertTo-JSON | Set-Content -Path $path
$people = Get-Content -Path $path -Raw | ConvertFrom-JSON

Bu yöntemle ilgili iki önemli nokta vardır. İlk olarak, JSON çok satırlı olarak yazılmıştır, bu nedenle tek bir dizede yeniden okumak için seçeneğini kullanmam -Raw gerekir. İkincisi, içeri aktarılan nesnenin artık bir [hashtable]olmamasıdır. Artık bir [pscustomobject] ve bu, beklemediğiniz takdirde sorunlara neden olabilir.

İç içe yerleştirilmiş karma tablolara dikkat edin. JSON'a dönüştürdüğünüzde beklediğiniz sonuçları alamayabilirsiniz.

@{ a = @{ b = @{ c = @{ d = "e" }}}} | ConvertTo-Json

{
  "a": {
    "b": {
      "c": "System.Collections.Hashtable"
    }
  }
}

İç içe karma tablolarının tümünü genişlettiklerinden emin olmak için Depth parametresini kullanın.

@{ a = @{ b = @{ c = @{ d = "e" }}}} | ConvertTo-Json -Depth 3

{
  "a": {
    "b": {
      "c": {
        "d": "e"
      }
    }
  }
}

İçeri aktarmada olması [hashtable] gerekiyorsa ve Import-CliXml komutlarını Export-CliXml kullanmanız gerekir.

JSON'ı Karma Tabloya Dönüştürme

JSON'u '[hashtable]a dönüştürmeniz gerekiyorsa, bunu .NET'teki JavaScriptSerializer ile yapmak için bildiğim bir yol var.

[Reflection.Assembly]::LoadWithPartialName("System.Web.Script.Serialization")
$JSSerializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new()
$JSSerializer.Deserialize($json,'Hashtable')

PowerShell v6 sürümünden itibaren JSON desteği NewtonSoft JSON.NET kullanır ve karma tablo desteği ekler.

'{ "a": "b" }' | ConvertFrom-Json -AsHashtable

Name      Value
----      -----
a         b

PowerShell 6.2, derinlik parametresini öğesine ConvertFrom-Jsonekledi. Varsayılan Derinlik 1024'dür.

Doğrudan bir dosyadan okuma

PowerShell söz dizimi kullanarak karma tablo içeren bir dosyanız varsa, doğrudan içeri aktarmanın bir yolu vardır.

$content = Get-Content -Path $Path -Raw -ErrorAction Stop
$scriptBlock = [scriptblock]::Create( $content )
$scriptBlock.CheckRestrictedLanguage( $allowedCommands, $allowedVariables, $true )
$hashtable = ( & $scriptBlock )

Dosyanın içeriğini içine scriptblockaktarır, ardından yürütmeden önce içinde başka PowerShell komutu olmadığından emin olmak için denetler.

Bu notta, modül bildiriminin (psd1 dosyası) yalnızca bir karma tablo olduğunu biliyor muydunuz?

Anahtarlar herhangi bir nesne olabilir

Çoğu zaman anahtarlar yalnızca dizelerdir. Böylece her şeyi tırnak içine alıp anahtar haline getirebiliyoruz.

$person = @{
    'full name' = 'Kevin Marquette'
    '#' = 3978
}
$person['full name']

Yapabileceğinizi fark etmeyebileceğiniz bazı garip şeyler yapabilirsiniz.

$person.'full name'

$key = 'full name'
$person.$key

Bir şey yapasın diye, yapman gerektiği anlamına gelmez. Bu sonuncusu, gerçekleşmeyi bekleyen bir hata gibi görünür ve kodunuzu okuyan herkes tarafından kolayca yanlış anlaşılır.

Teknik olarak anahtarınızın bir dize olması gerekmez, ancak yalnızca dizeleri kullanıyorsanız bunları düşünmek daha kolaydır. Ancak, dizin oluşturma karmaşık anahtarlarla iyi çalışmaz.

$ht = @{ @(1,2,3) = "a" }
$ht

Name                           Value
----                           -----
{1, 2, 3}                      a

Karma tablodaki bir değere anahtarıyla erişmek her zaman işe yaramaz. Örneğin:

$key = $ht.keys[0]
$ht.$($key)
a
$ht[$key]
a

Anahtar bir dizi olduğunda, değişkeni üye erişimi (.) gösterimiyle kullanılabilmesi için bir alt ifadeye sarmalamanız $key gerekir. İsterseniz dizi dizini ([]) gösterimini de kullanabilirsiniz.

Otomatik değişkenlerde kullanma

$PSBoundParameters

$PSBoundParameters, yalnızca bir işlevin bağlamında bulunan otomatik bir değişkendir. İşlevin çağrıldığı tüm parametreleri içerir. Bu tam olarak bir karma tablo değildir, ancak bir karma tablo gibi davranabileceğiniz kadar yakın.

Buna anahtarların kaldırılması ve diğer işlevlere sıçraması dahildir. Ara sunucu işlevleri yazdığınızı fark ederseniz, buna daha yakından bakın.

Daha fazla bilgi için bkz . about_Automatic_Variables .

PSBoundParameters gotcha

Unutmamanız gereken önemli bir şey, bunun yalnızca parametre olarak geçirilen değerleri içerdiğidir. Varsayılan değerlere sahip parametreleriniz de varsa ancak çağıran tarafından geçirilmediyse, $PSBoundParameters bu değerleri içermez. Bu genellikle göz ardı edilir.

$PSDefaultParameterValues

Bu otomatik değişken, cmdlet'ini değiştirmeden herhangi bir cmdlet'e varsayılan değerler atamanızı sağlar. Bu örneğe göz atın.

$PSDefaultParameterValues["Out-File:Encoding"] = "UTF8"

Bu, parametre için varsayılan değer olarak ayarlayan UTF8 karma tabloya Out-File -Encoding bir girdi $PSDefaultParameterValues ekler. Bu oturuma özgüdür, bu nedenle öğesininize yerleştirmeniz $profilegerekir.

Bunu sık sık yazdığım değerleri önceden atamak için kullanıyorum.

$PSDefaultParameterValues[ "Connect-VIServer:Server" ] = 'VCENTER01.contoso.local'

Bu, değerleri toplu olarak ayarlayabilmeniz için joker karakterleri de kabul eder. Bunu kullanmanın bazı yolları şunlardır:

$PSDefaultParameterValues[ "Get-*:Verbose" ] = $true
$PSDefaultParameterValues[ "*:Credential" ] = Get-Credential

Daha ayrıntılı bir döküm için Michael Sorens'ın Otomatik Varsayılanlar hakkındaki bu harika makalesine bakın.

Regex $Matches

işlecini -match kullandığınızda, eşleşmenin sonuçlarıyla birlikte adlı $matches bir otomatik değişken oluşturulur. Reex'inizde herhangi bir alt ifade varsa, bu alt eşleşmeler de listelenir.

$message = 'My SSN is 123-45-6789.'

$message -match 'My SSN is (.+)\.'
$Matches[0]
$Matches[1]

Adlandırılmış eşleşmeler

Bu, çoğu kişinin bilmediği en sevdiğim özelliklerden biridir. Adlandırılmış bir regex eşleşmesi kullanıyorsanız, bu eşleşmeye eşleşmelerde ada göre erişebilirsiniz.

$message = 'My Name is Kevin and my SSN is 123-45-6789.'

if($message -match 'My Name is (?<Name>.+) and my SSN is (?<SSN>.+)\.')
{
    $Matches.Name
    $Matches.SSN
}

Yukarıdaki örnekte, (?<Name>.*) adlandırılmış bir alt ifadedir. Bu değer daha sonra özelliğine $Matches.Name yerleştirilir.

Group-Object -AsHashtable

Bilinen küçük bir özelliği Group-Object , bazı veri kümelerini sizin için bir karma tabloya dönüştürebileceğidir.

Import-CSV $Path | Group-Object -AsHashtable -Property email

Bu işlem her satırı bir karma tabloya ekler ve erişim anahtarı olarak belirtilen özelliği kullanır.

Karma Tablo Kopyalama

Bilinmesi gereken önemli bir şey, karma tablolarının nesneler olduğudur. Her değişken yalnızca bir nesneye başvurudur. Başka bir deyişle, karma tabloya ait geçerli bir kopya oluşturmak daha fazla çalışma gerektirebilir.

Başvuru türleri atama

Bir karma tablonuz olduğunda ve bunu ikinci bir değişkene atadığınızda, her iki değişken de aynı karma tabloya işaret eder.

PS> $orig = @{name='orig'}
PS> $copy = $orig
PS> $copy.name = 'copy'
PS> 'Copy: [{0}]' -f $copy.name
PS> 'Orig: [{0}]' -f $orig.name

Copy: [copy]
Orig: [copy]

Bu, birindeki değerlerin değiştirilmesi diğerindeki değerleri de değiştireceği için bunların aynı olduğunu vurgular. Bu, karma tablolarını diğer işlevlere geçirirken de geçerlidir. Bu işlevler bu karma tablo üzerinde değişiklik yaparsa, özgün işleviniz de değiştirilir.

Sığ kopyalar, tek düzey

Yukarıdaki örneğimiz gibi basit bir karma tablomuz varsa, basit bir kopya oluşturmak için kullanabiliriz .Clone() .

PS> $orig = @{name='orig'}
PS> $copy = $orig.Clone()
PS> $copy.name = 'copy'
PS> 'Copy: [{0}]' -f $copy.name
PS> 'Orig: [{0}]' -f $orig.name

Copy: [copy]
Orig: [orig]

Bu, birinde diğerini etkilemeyen bazı temel değişiklikler yapmamıza olanak sağlar.

İç içe yerleştirilmiş sığ kopyalar

Basit kopya olarak adlandırılıyor olmasının nedeni, yalnızca temel düzey özelliklerini kopyalamasıdır. Bu özelliklerden biri bir başvuru türüyse (başka bir karma tablo gibi), iç içe nesneler yine de birbirini gösterir.

PS> $orig = @{
        person=@{
            name='orig'
        }
    }
PS> $copy = $orig.Clone()
PS> $copy.person.name = 'copy'
PS> 'Copy: [{0}]' -f $copy.person.name
PS> 'Orig: [{0}]' -f $orig.person.name

Copy: [copy]
Orig: [copy]

Yani karma tablo kopyalamış olsam da başvurusunun person kopyalanmıyor olduğunu görebilirsiniz. İlkine bağlı olmayan ikinci bir karma tabloya gerçekten sahip olmak için derin bir kopya yapmamız gerekir.

Derin kopyalar

Karma tablonun derin bir kopyasını oluşturmanın (ve karma tablo olarak tutmanın) birkaç yolu vardır. Aşağıda, powershell kullanarak özyinelemeli olarak derin bir kopya oluşturan bir işlev yer alır:

function Get-DeepClone
{
    [CmdletBinding()]
    param(
        $InputObject
    )
    process
    {
        if($InputObject -is [hashtable]) {
            $clone = @{}
            foreach($key in $InputObject.keys)
            {
                $clone[$key] = Get-DeepClone $InputObject[$key]
            }
            return $clone
        } else {
            return $InputObject
        }
    }
}

Diğer başvuru türlerini veya dizileri işlemez, ancak iyi bir başlangıç noktasıdır.

Bir diğer yol da şu işlevdeki gibi CliXml kullanarak seri durumdan çıkarmak için .Net kullanmaktır:

function Get-DeepClone
{
    param(
        $InputObject
    )
    $TempCliXmlString = [System.Management.Automation.PSSerializer]::Serialize($obj, [int32]::MaxValue)
    return [System.Management.Automation.PSSerializer]::Deserialize($TempCliXmlString)
}

Son derece büyük karma tablolarda, seri durumdan çıkarma işlevi ölçeği genişletildikçe daha hızlı olur. Ancak, bu yöntemi kullanırken dikkate alınması gereken bazı şeyler vardır. CliXml kullandığından bellek yoğundur ve büyük karma tablo kopyalanıyorsanız bu bir sorun olabilir. CliXml'nin bir diğer sınırlaması da 48 derinlik sınırlaması olmasıdır. Başka bir deyişle, iç içe yerleştirilmiş karma tablolardan oluşan 48 katmanı olan bir karma tablonuz varsa kopyalama başarısız olur ve hiç karma tablo çıkışı olmaz.

Başka birşey var mı?

Çok hızlı bir şekilde bir sürü yer kapladım. Umudum, bunu her okuduğunda yeni bir şeyler ya da daha iyi anlamak için çekip gitmen. Bu özelliğin tüm yelpazesini kapsadığım için, şu anda sizin için geçerli olmayabilir. Bu tamamen tamamdır ve PowerShell ile ne kadar çalıştığınıza bağlı olarak beklenen bir durumdur.