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-Object
boruyu 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-Table
ile 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 name
expression
n
e
.
$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-Json
ekledi. 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 scriptblock
aktarı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 $profile
gerekir.
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.
PowerShell