Minden, amit tudni akart a kivonattáblákról

Szeretnék visszalépni, és beszélni a kivonattáblákról. Mindig használom őket. Tanítottam valakit róluk a felhasználói csoport tegnap esti találkozója után, és rájöttem, hogy ugyanolyan zavart voltam velük kapcsolatban, mint ő. A kivonattáblák nagyon fontosak a PowerShellben, ezért jó, ha alapos ismereteket szerzünk róluk.

Megjegyzés

A cikk eredeti verziója@KevinMarquette által írt blogon jelent meg. A PowerShell csapata köszönjük Kevinnek, hogy megosztotta velünk ezt a tartalmat. Kérjük, nézd meg a blog PowerShellExplained.com.

Kivonattábla mint dolgok gyűjteménye

Azt akarom, hogy először egy kivonattáblát tekintsen meg gyűjteményként a kivonattáblák hagyományos definíciójában. Ez a definíció alapvető ismereteket nyújt arról, hogyan működnek, amikor később fejlettebb dolgokhoz használják őket. Ennek a megértésnek a kihagyása gyakran félreértések forrása.

Mi a tömb?

Mielőtt belevágnék a hashtable-ba , először meg kell említenem a tömböket . A vitafórum céljaira a tömb értékek vagy objektumok listája vagy gyűjteménye.

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

Miután az elemeket egy tömbbe tette, foreach a lista iterálásával vagy index használatával hozzáférhet a tömb egyes elemeihez.

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

Write-Output $array[3]

Az értékeket index használatával is ugyanúgy frissítheti.

$array[2] = 13

Csak megkarcoltam a felületet a tömbökön, de ez a megfelelő kontextusba helyezi őket, amikor a kivonattáblákra lépek.

Mi az a kivonattábla?

Az általános értelemben vett kivonattáblák alapvető technikai leírásával kezdem, mielőtt a PowerShell más felhasználási módjaira váltanék.

A kivonattábla egy tömbhöz hasonló adatstruktúra, kivéve, ha minden értéket (objektumot) kulcs használatával tárol. Ez egy alapszintű kulcs/érték tároló. Először létrehozunk egy üres kivonattáblát.

$ageList = @{}

Figyelje meg, hogy zárójelek helyett zárójelek használatával határozhatók meg a kivonattáblák. Ezután hozzáadunk egy elemet az alábbihoz hasonló kulccsal:

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

$ageList.add( 'Alex', 9 )

A személy neve a kulcs, az életkora pedig az az érték, amelyet meg szeretnék menteni.

Szögletes zárójelek használata a hozzáféréshez

Miután hozzáadta az értékeket a kivonattáblához, ugyanezzel a kulccsal húzhatja vissza őket (ahelyett, hogy numerikus indexet használna, mint egy tömb esetében).

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

Ha azt akarom, hogy Kevin kora legyen, az ő nevével férek hozzá. Ezzel a módszerrel értékeket adhat hozzá vagy frissíthet a kivonattáblában. Ez ugyanúgy működik, mint a add() fenti függvény.

$ageList = @{}

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

$ageList['Alex'] = 9

Egy másik szintaxist is használhat az értékek eléréséhez és frissítéséhez, amelyeket egy későbbi szakaszban fogok tárgyalni. Ha egy másik nyelvről érkezik a PowerShellbe, ezeknek a példáknak illeszkedniük kell ahhoz, hogy korábban hogyan használta a kivonattáblákat.

Értékeket tartalmazó kivonattáblák létrehozása

Eddig egy üres kivonattáblát hoztam létre ezekhez a példákhoz. Létrehozásukkor előre kitöltheti a kulcsokat és az értékeket.

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

Keresési táblaként

Az ilyen típusú kivonattáblák valódi értéke az, hogy keresési táblaként használhatja őket. Íme egy egyszerű példa.

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

$server = $environments[$env]

Ebben a példában egy környezetet ad meg a $env változóhoz, és az kiválasztja a megfelelő kiszolgálót. Használhat egy switch($env){...} ilyen kijelölést, de a kivonattábla jó választás.

Ez még jobb lesz, ha dinamikusan hozza létre a keresési táblát, hogy később használni tudja. Ezért akkor érdemes ezt a megközelítést használni, ha kereszthivatkozásra van szüksége. Azt hiszem, ezt még jobban látnánk, ha a PowerShell nem lenne olyan jó a cső Where-Objectszűrésében. Ha valaha is olyan helyzetben van, amikor a teljesítmény számít, ezt a megközelítést kell figyelembe venni.

Nem mondom, hogy gyorsabb, de beleillik a szabályba, ha a teljesítmény számít, teszteld.

Többszörös kijelölés

A kivonattáblák általában kulcs/érték párnak tekinthetők, ahol egy kulcsot ad meg, és egy értéket kap. A PowerShell lehetővé teszi több érték lekéréséhez szükséges kulcsok tömbjének megadását.

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

Ebben a példában ugyanazt a fenti keresési kivonattáblát használom, és három különböző tömbstílust adok meg az egyezések lekéréséhez. Ez egy rejtett gyöngyszem a PowerShellben, amelyről a legtöbben nem tudnak.

Kivonattáblák iterálása

Mivel a kivonattáblák kulcs-érték párok gyűjteményei, az iterálás másként történik, mint egy tömb vagy egy normál elemlista esetében.

Az első dolog, hogy figyelje meg, hogy ha a cső a kivonattáblát, a cső kezeli, mint egy objektum.

PS> $ageList | Measure-Object
count : 1

Annak ellenére, hogy a .count tulajdonság megmutatja, hogy hány értéket tartalmaz.

PS> $ageList.count
2

Ha csak az értékekre van szüksége, a .values tulajdonság használatával megkerülheti ezt a problémát.

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

Gyakran hasznosabb a kulcsok számbavétele és használata az értékek eléréséhez.

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

Íme ugyanez a példa egy foreach(){...} hurokkal.

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

A kivonattáblában végigsétáljuk az egyes kulcsokat, majd azt használjuk az érték eléréséhez. Ez gyakori minta a kivonattáblák gyűjteményként való használatakor.

GetEnumerator()

Ez elvezet minket a GetEnumerator() kivonattáblán való iteráláshoz.

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

Az enumerátor egymás után adja meg az egyes kulcs-érték párokat. Kifejezetten erre a használati esetre tervezték. Köszönöm Mark Krausnak , hogy emlékeztetett erre.

BadEnumeration

Az egyik fontos részlet az, hogy a számbavétel során a kivonattáblák nem módosíthatók. Ha az alapszintű $environments példával kezdjük:

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

És ha minden kulcsot ugyanarra a kiszolgálóértékre próbál beállítani, az sikertelen lesz.

$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

Ez akkor is sikertelen lesz, ha úgy tűnik, hogy ez is rendben van:

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

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

Ebben a helyzetben az a trükk, hogy klónozza a kulcsokat az enumerálás előtt.

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

Kivonattábla tulajdonságok gyűjteményeként

Eddig a kivonattáblába helyezett objektumok típusa ugyanaz volt. Az összes példában életkorokat használtam, és a kulcs a személy neve volt. Ez nagyszerű módja annak, hogy megtekintse, ha az objektumgyűjteménynek van egy-egy neve. A kivonattáblák PowerShellben való használatának egy másik gyakori módja a tulajdonságok gyűjteménye, ahol a kulcs a tulajdonság neve. A következő példában ezt az ötletet mutatom be.

Tulajdonságalapú hozzáférés

A tulajdonságalapú hozzáférés használata megváltoztatja a kivonattáblák dinamikáját, és azt, hogy hogyan használhatja őket a PowerShellben. Íme a fentebbi szokásos példa, amely tulajdonságokként kezeli a kulcsokat.

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

A fenti példákhoz hasonlóan ez a példa is hozzáadja ezeket a kulcsokat, ha még nem léteznek a kivonattáblában. Attól függően, hogy hogyan definiálta a kulcsokat, és hogy mik az értékei, ez vagy egy kicsit furcsa, vagy tökéletes választás. A korlista-példa eddig jól működött. Ehhez egy új példára van szükségünk ahhoz, hogy a jövőben is jól érezzük magunkat.

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

Emellett az ehhez hasonló attribútumokat $person is hozzáadhatjuk és elérhetjük.

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

Hirtelen ez a kivonattábla kezd úgy érezni és viselkedni, mint egy objektum. Ez még mindig a dolgok gyűjteménye, így a fenti példák továbbra is érvényesek. Csak egy másik nézőpontból közelítjük meg.

Kulcsok és értékek keresése

A legtöbb esetben egyszerűen tesztelheti az értéket az alábbihoz hasonló módon:

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

Ez egyszerű, de már a forrása sok hiba számomra, mert én figyelmen kívül hagyott egy fontos részletet a logikát. Elkezdtem használni, hogy tesztelje, van-e kulcs. Ha az érték nulla volt $false , az utasítás váratlanul visszaadja $false .

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

Ez megkerüli ezt a problémát nulla érték esetén, de nem $null és nem létező kulcsok esetén. A legtöbbször nem kell ezt a megkülönböztetést megtennie, de vannak függvények, amikor ezt teszi.

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

Van egy ContainsValue() olyan helyzetünk is, amikor a kulcs ismerete vagy a teljes gyűjtemény iterálása nélkül kell tesztelni egy értéket.

Kulcsok eltávolítása és törlése

A függvény segítségével eltávolíthatja a .Remove() kulcsokat.

$person.remove('age')

Ha értékeket $null rendel hozzájuk, csak egy olyan kulccsal rendelkezik, amely rendelkezik $null értékkel.

A kivonattáblák törlésének gyakori módja, ha csak egy üres kivonattáblára inicializálja azt.

$person = @{}

Bár ez működik, próbálja meg inkább használni a függvényt clear() .

$person.clear()

Ez az egyik olyan eset, amikor a függvény használata ön dokumentáló kódot hoz létre, és nagyon tisztavá teszi a kód szándékait.

Az összes szórakoztató dolog

Rendezett kivonattáblák

Alapértelmezés szerint a kivonattáblák nincsenek rendezve (vagy rendezve). A hagyományos környezetben a sorrend nem számít, ha mindig kulcs használatával éri el az értékeket. Előfordulhat, hogy azt szeretné, hogy a tulajdonságok a definiált sorrendben maradjanak. Szerencsére van rá mód a kulcsszóval ordered .

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

A kulcsok és értékek számbavétele után azok ebben a sorrendben maradnak.

Beágyazott kivonattáblák

Ha egy sorban definiál egy kivonattáblát, pontosvesszővel elválaszthatja a kulcs-érték párokat.

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

Ez hasznos lesz, ha a csőben hozza létre őket.

Egyéni kifejezések a gyakori folyamatparancsokban

Van néhány parancsmag, amely támogatja a kivonattáblák használatát egyéni vagy számított tulajdonságok létrehozásához. Ezt általában a következővel Select-Object látja: és Format-Table. A kivonattáblák speciális szintaxisa így néz ki, ha teljes mértékben kibontva van.

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

A name parancsmag ezt az oszlopot címkézné. Ez expression egy szkriptblokk, amely akkor lesz végrehajtva, ha $_ az objektum értéke a csőben van. Ez a szkript működik:

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

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

Ezt elhelyeztem egy változóban, de könnyen definiálható beágyazottan, és rövidíthet namen rá és expressione arra, amíg ott van.

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

Én személy szerint nem tetszik, hogy mennyi ideig teszi a parancsokat, és ez gyakran elősegíti néhány rossz viselkedést, hogy én nem kerül be. Nagyobb valószínűséggel hozok létre egy új kivonattáblát, vagy pscustomobject minden olyan mezőt és tulajdonságot, amelyet szeretnék ahelyett, hogy ezt a módszert használnám a szkriptekben. De van egy csomó kód, ami ezt teszi, ezért azt akartam, hogy tudd. Arról beszélek, hogy később létrehozok egy pscustomobject újat.

Egyéni rendezési kifejezés

A gyűjtemények rendezése egyszerű, ha az objektumok olyan adatokkal rendelkeznek, amelyek alapján rendezni szeretné a gyűjteményt. Rendezés előtt hozzáadhatja az adatokat az objektumhoz, vagy létrehozhat egy egyéni kifejezést az objektumhoz Sort-Object.

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

Ebben a példában a felhasználók listáját készítem, és néhány egyéni parancsmagot használok további információk lekéréséhez csak a rendezéshez.

Kivonattáblák listájának rendezése

Ha rendelkezik a rendezni kívánt kivonattáblák listájával, azt fogja tapasztalni, hogy a Sort-Object kulcsok nem tulajdonságokként vannak kezelve. Ezt egy egyéni rendezési kifejezéssel lehet lekérni.

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

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

Kivonattáblák formázása parancsmagokon

Ez az egyik kedvenc dolog a kivonattáblákkal kapcsolatban, amelyeket sokan nem fedeznek fel korán. Az ötlet az, hogy ahelyett, hogy az összes tulajdonságot egy sorban biztosítanák egy parancsmagnak, először egy kivonattáblába csomagolhatja őket. Ezután speciális módon adhat a kivonatolót a függvénynek. Íme egy példa a DHCP-hatókör normál módon történő létrehozására.

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"

A splatting használata nélkül ezeket a dolgokat egyetlen sorban kell meghatározni. Vagy legörgeti a képernyőt, vagy körbefut, ahol valaha is úgy érzi. Most hasonlítsa össze ezt egy splattingot használó paranccsal.

$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

A splat műveletet az @ előjel használata hívja meg ahelyett $ , hogy az.

Csak szánjon egy kis időt arra, hogy értékelje, milyen könnyen olvasható ez a példa. Pontosan ugyanazt a parancsot adják meg, ugyanazokkal az értékekkel. A másodikat könnyebb megérteni és fenntartani.

Splatting-et használok, amikor a parancs túl sokáig tart. Túl sokáig definiálom, amíg az ablakom jobbra görget. Ha három tulajdonságot találok meg egy függvényhez, akkor valószínűleg újraírom egy szórt kivonattáblával.

Splatting opcionális paraméterekhez

A splatting egyik leggyakoribb módja az, hogy a szkriptem más részeiből származó opcionális paraméterekkel foglalkozom. Tegyük fel, hogy van egy függvényem, amely egy Get-CIMInstance opcionális $Credential argumentumot tartalmazó hívást burkol.

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

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

Get-CIMInstance @CIMParams

Először a gyakori paraméterekkel rendelkező kivonattáblát hozom létre. Aztán hozzáadom, $Credential ha létezik. Mivel itt splattinget használok, csak egyszer kell meghívnom Get-CIMInstance a kódot. Ez a kialakítási minta nagyon tiszta, és számos választható paramétert képes könnyen kezelni.

A helyesség kedvéért megírhatja a parancsokat, hogy engedélyezze $null a paraméterek értékeit. Egyszerűen nem mindig tudja szabályozni a többi hívó parancsot.

Több léc

Ugyanahhoz a parancsmaghoz több kivonattáblát is létrehozhat. Ha újra megvizsgáljuk az eredeti splatting-példát:

$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

Ezt a módszert akkor fogom használni, ha olyan paraméterekkel rendelkezem, amelyeket sok parancsnak adom át.

Splatting tiszta kódhoz

Nincs semmi baj azzal, ha egyetlen paramétert szúr be, ha a kód tisztábbá válik.

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

Végrehajtható fájlok splattingja

A splatting néhány szintaxist /param:value használó végrehajtható fájlon is működik. Robocopy.exepéldául ilyen paraméterekkel rendelkezik.

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

Nem tudom, hogy ez minden olyan hasznos, de érdekesnek találtam.

Kivonattáblák hozzáadása

A kivonattáblák támogatják az összeadás operátort két kivonattábla kombinálásához.

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

Ez csak akkor működik, ha a két kivonattábla nem oszt meg kulcsot.

Beágyazott kivonattáblák

A kivonattáblákat értékként használhatjuk egy kivonattáblán belül.

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

Egy alapszintű kivonattáblával kezdtem, amely két kulcsot tartalmaz. Hozzáadtam egy üres kivonattáblával hívott location kulcsot. Aztán hozzáadtam az utolsó két elemet a location kivonatolóhoz. Ezt is meg tudjuk tenni beágyazottan.

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

Ez ugyanazt a kivonattáblát hozza létre, amelyet fent láttunk, és ugyanúgy érheti el a tulajdonságokat.

$person.location.city
Austin

Az objektumok szerkezetét többféleképpen is megközelítheti. Íme egy második módszer a beágyazott kivonattáblák megtekintésére.

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

Ez ötvözi a kivonattáblák objektumok és tulajdonságok gyűjteményeként való használatának fogalmát. Az értékek továbbra is könnyen elérhetők, még akkor is, ha azokat a kívánt módszerrel ágyazzák be.

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

Általában a pont tulajdonságot használom, amikor tulajdonságként kezelem. Ezek általában olyan dolgok, amelyeket statikusan definiáltam a kódban, és a fejem tetején ismerem őket. Ha végig kell lépnem a listán, vagy programozott módon hozzá kell férnem a kulcsokhoz, a szögletes zárójelekkel meg kell adnom a kulcs nevét.

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

A kivonattáblák beágyazásának lehetősége sok rugalmasságot és lehetőséget kínál.

Beágyazott kivonattáblák

Amint elkezdi beágyazni a kivonattáblákat, szüksége lesz egy egyszerű módszerre, hogy megnézhesse őket a konzolról. Ha az utolsó kivonattáblát választom, egy ilyen kimenetet kapok, és csak olyan mélyre megy:

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

Én megy a parancsot nézi ezeket a dolgokat, ConvertTo-JSON mert nagyon tiszta, és én gyakran használ JSON más dolgokat.

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

Még ha nem is ismeri a JSON-t, látnia kell, amit keres. Van egy Format-Custom parancs az ilyen strukturált adatokhoz, de még mindig jobban szeretem a JSON-nézetet.

Objektumok létrehozása

Néha csak egy objektumra van szükség, és a tulajdonságok tárolására használt kivonattáblával egyszerűen nem lehet elvégezni a feladatot. A kulcsokat leggyakrabban oszlopnevekként szeretné látni. A-ból pscustomobject ilyen egyszerű.

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

$person

name  age
----  ---
Kevin  36

Még ha nem is eredetileg hozza létre pscustomobject , szükség esetén később is leadhatja.

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

[pscustomobject]$person

name  age
----  ---
Kevin  36

Már van részletes írási pscustomobject , hogy el kell menni olvasni ezt követően. Az itt tanultakra épül.

Kivonattáblák olvasása és írása fájlba

Mentés CSV-fájlba

Küzd azzal, hogy kap egy kivonattáblát, hogy mentse a CSV az egyik nehézséget, hogy utaltam fent. Alakítsa át a kivonattáblát csv-fájllá pscustomobject , és az megfelelően menthető CSV-fájllá. Ez segít, ha egy pscustomobject oszlopsorrend megőrzése érdekében kezdi. De szükség esetén át is vetheti egy pscustomobject beágyazottba.

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

Még egyszer, nézd meg a write-up segítségével pscustomobject.

Beágyazott kivonattábla mentése fájlba

Ha egy beágyazott kivonattáblát kell mentenem egy fájlba, majd újra be kell olvasnom, akkor a JSON-parancsmagokkal hajtom végre.

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

Ezzel a módszerrel kapcsolatban két fontos szempont van. Először is, hogy a JSON ki van írva többsoros így kell használni a -Raw lehetőséget, hogy olvassa vissza egy sztring. A második az, hogy az importált objektum már nem egy [hashtable]. Ez most már egy [pscustomobject] , és problémákat okozhat, ha nem számít rá.

Nézze meg a mélyen beágyazott kivonattáblákat. Ha JSON-ra konvertálja, előfordulhat, hogy nem a várt eredményt kapja.

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

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

A Depth paraméter használatával győződjön meg arról, hogy kibontotta az összes beágyazott kivonattáblát.

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

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

Ha importálásra van szüksége[hashtable], akkor az és Import-CliXml a Export-CliXml parancsokat kell használnia.

JSON átalakítása kivonattáblává

Ha konvertálnia kell a JSON-t egy [hashtable], van egy módja, hogy tudom, hogy ezt a JavaScriptSerializer a .NET.

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

A PowerShell 6-os verziótól kezdve a JSON-támogatás a NewtonSoft JSON.NET használja, és kivonattábla-támogatást ad hozzá.

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

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

A PowerShell 6.2 hozzáadta a Depth paramétert a következőhöz ConvertFrom-Json: . Az alapértelmezett mélység 1024.

Olvasás közvetlenül egy fájlból

Ha egy PowerShell-szintaxist használó kivonattáblát tartalmazó fájllal rendelkezik, azt közvetlenül is importálhatja.

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

Importálja a fájl tartalmát egy scriptblock, majd ellenőrzi, hogy nincs-e benne más PowerShell-parancs, mielőtt végrehajtja.

Ezen a megjegyzésen tudta, hogy a moduljegyzék (a psd1 fájl) csak egy kivonattábla?

A kulcsok bármilyen objektum lehetnek

A legtöbb esetben a kulcsok csak sztringek. Így bármit idézhetünk, és kulcssá tehetjük.

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

Lehet csinálni néhány furcsa dolgokat, hogy lehet, hogy nem jött rá, hogy meg tudod csinálni.

$person.'full name'

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

Csak azért, mert tudsz csinálni valamit, még nem jelenti azt, hogy kellene. Ez az utolsó csak úgy néz ki, mint egy hiba, amely arra vár, hogy megtörténjen, és könnyen félreértené bárki, aki elolvassa a kódot.

Technikailag a kulcsnak nem kell sztringnek lennie, de könnyebben átgondolható, ha csak sztringeket használ. Az indexelés azonban nem működik jól az összetett kulcsokkal.

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

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

A kivonattáblában lévő értékek kulcs alapján történő elérése nem mindig működik. Például:

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

Ha a kulcs tömb, a $key változót egy alkifejezésbe kell burkolni, hogy taghozzáférési (.) jelöléssel lehessen használni. Tömbindex ([]) jelölést is használhat.

Automatikus változókban való használat

$PSBoundParameters

$PSBoundParameters egy automatikus változó, amely csak egy függvény környezetében létezik. Tartalmazza az összes paramétert, amellyel a függvényt meghívták. Ez nem pontosan egy kivonattábla, de elég közel ahhoz, hogy úgy kezeld, mint egy.

Ez magában foglalja a kulcsok eltávolítását és más függvényekbe való beszűkítését. Ha úgy találja, hogy proxyfüggvényeket ír, tekintse meg közelebbről ezt.

További részletekért lásd about_Automatic_Variables .

PSBoundParameters gotcha

Fontos megjegyezni, hogy ez csak a paraméterekként átadott értékeket foglalja magában. Ha alapértelmezett értékekkel rendelkező paraméterekkel is rendelkezik, de a hívó nem adja át őket, $PSBoundParameters nem tartalmazza ezeket az értékeket. Ezt általában figyelmen kívül hagyják.

$PSDefaultParameterValues

Ez az automatikus változó lehetővé teszi alapértelmezett értékek hozzárendelését bármely parancsmaghoz a parancsmag módosítása nélkül. Tekintse meg ezt a példát.

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

Ez hozzáad egy bejegyzést a $PSDefaultParameterValues kivonattáblához, amely a paraméter alapértelmezett értékeként Out-File -Encoding van megadvaUTF8. Ez munkamenet-specifikus, ezért helyezze el a $profilesaját fiókjában.

Gyakran használom ezt a gyakran beírt értékek előre kiosztására.

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

Ez helyettesítő karaktereket is elfogad, így tömegesen állíthat be értékeket. Az alábbiakban néhány módszert használhat:

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

Részletesebb leírásért tekintse meg ezt a nagyszerű cikket Az automatikus alapértékekMichael Sorens részéről.

Regex $Matches

Az operátor használatakor egy -match automatikus változó lesz meghívva $matches az egyezés eredményével. Ha a regexben vannak alkifejezések, ezek az alkifejezések is fel vannak sorolva.

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

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

Névvel ellátott egyezések

Ez az egyik kedvenc funkcióm, amelyről a legtöbb ember nem tud. Ha névvel ellátott reguláris egyezést használ, akkor az egyezés név szerint elérhető a találatokon.

$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
}

A fenti példában ez (?<Name>.*) egy elnevezett alkifejezés. Ezt az értéket ezután a tulajdonságba helyezi.$Matches.Name

Group-Object -AsHashtable

Az egyik kevéssé ismert funkció Group-Object az, hogy egyes adathalmazokat kivonattáblává alakíthat.

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

Ez hozzáadja az egyes sorokat egy kivonattáblához, és a megadott tulajdonságot használja kulcsként a hozzáféréshez.

Kivonattáblák másolása

Fontos tudni, hogy a kivonattáblák objektumok. És minden változó csak egy objektumra mutató hivatkozás. Ez azt jelenti, hogy több munka szükséges a kivonattáblák érvényes másolatának létrehozásához.

Referenciatípusok hozzárendelése

Ha egy kivonattáblával rendelkezik, és hozzárendeli egy második változóhoz, mindkét változó ugyanarra a kivonattáblára mutat.

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]

Ez kiemeli, hogy ugyanazok, mert az egyikben lévő értékek módosítása a másikban lévő értékeket is módosítja. Ez akkor is érvényes, ha kivonattáblákat ad át más függvényeknek. Ha ezek a függvények módosítják ezt a kivonattáblát, az eredeti is módosul.

Sekély másolatok, egy szinttel

Ha a fenti példához hasonló egyszerű kivonattáblával rendelkezünk, akkor .Clone() készíthetünk egy sekély másolatot.

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]

Ez lehetővé teszi, hogy néhány alapvető módosítást hajtsunk végre az egyiken, amely nem befolyásolja a másikat.

Sekély példányok, beágyazott

Azért nevezik sekély másolatnak, mert csak az alapszintű tulajdonságokat másolja. Ha az egyik tulajdonság hivatkozási típus (például egy másik kivonattábla), akkor ezek a beágyazott objektumok továbbra is egymásra mutatnak.

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]

Így láthatja, hogy bár klónoztam a kivonattáblát, a hivatkozás person nem volt klónozva. Létre kell hoznunk egy mély másolatot, hogy valóban legyen egy második kivonattáblánk, amely nem kapcsolódik az elsőhöz.

Részletes másolatok

Többféleképpen is készíthet mély másolatot a kivonattábláról (és megtarthatja kivonattábláként). Íme egy függvény, amely a PowerShell használatával hoz létre rekurzív módon egy mély másolatot:

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
        }
    }
}

Más referenciatípusokat és tömböket nem kezel, de jó kiindulási pont.

Egy másik módszer, ha a .Net használatával deszerializálja azt a CliXml használatával, az alábbi függvényhez hasonlóan:

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

Rendkívül nagy kivonattáblák esetén a deszerializáló függvény a felskálázás során gyorsabb. Ennek a módszernek a használatakor azonban figyelembe kell vennie néhány szempontot. Mivel cliXml-t használ, memóriaigényes, és ha hatalmas kivonattáblákat klónoz, ez problémát jelenthet. A CliXml egy másik korlátozása a 48-as mélységi korlátozás. Ez azt jelenti, hogy ha egy 48 rétegnyi beágyazott kivonattáblát tartalmazó kivonattáblával rendelkezik, a klónozás sikertelen lesz, és egyáltalán nem lesz kivonattábla kimenete.

Bármi egyéb?

Gyorsan letakartam egy csomó földet. Remélem, hogy elsétálsz valami újat, vagy jobban megérted, amikor ezt olvasod. Mivel lefedtem ennek a funkciónak a teljes spektrumát, vannak olyan szempontok, amelyek most nem vonatkoznak rád. Ez teljesen rendben van, és elvárható attól függően, hogy mennyit használ a PowerShell-lel.