Megosztás a következőn keresztül:


Minden, amit tudni akart a kivonatolókról

Szeretnék visszalépni, és beszélni a kivonatolókról. Folyamatosan használom őket. A tegnap esti felhasználói csoporttalálkozónk után tanítottam róluk valakit, és rájöttem, hogy ugyanolyan zavarban voltam velük, mint ő. A kivonatolók nagyon fontosak a PowerShellben, ezért jó, ha alapos ismereteket szerzünk róluk.

Feljegyzé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ézze meg a blogját a PowerShellExplained.com.

Kivonatoló a dolgok gyűjteményeként

Azt akarom, hogy először egy hashtable gyűjteményként jelenjen meg a kivonatoló 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 zavart okoz.

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élja, hogy a tömb értékek vagy objektumok listája vagy gyűjteménye legyen.

$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 az indexek használatával is ugyanúgy frissítheti.

$array[2] = 13

Most karcoltam meg 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 kivonatoló?

A kivonatolók általános értelemben vett alapszintű technikai leírásával kezdem, mielőtt a PowerShell más felhasználási módjaira váltanék.

A kivonatoló egy tömbhöz hasonló adatstruktúra, kivéve, ha az egyes értékeket (objektumokat) kulcs használatával tárolja. Ez egy alapkulcs-/értéktároló. Először létrehozunk egy üres kivonatolót.

$ageList = @{}

Figyelje meg, hogy zárójelek helyett zárójelek használatával határozhatók meg a kivonatoló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, és az életkora az az érték, amelyet menteni szeretnék.

A zárójelek használata a hozzáféréshez

Miután hozzáadta az értékeket a kivonatolóhoz, ugyanezzel a kulccsal húzhatja vissza őket (a tömbhöz hasonló numerikus index helyett).

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

Ha kevin korát akarom, az ő nevével férek hozzá. Ezzel a módszerrel értékeket adhat hozzá vagy frissíthet a kivonatolóban is. Ez ugyanúgy működik, mint a add() fenti függvény.

$ageList = @{}

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

$ageList['Alex'] = 9

Van egy másik szintaxis, amellyel elérheti és frissítheti azokat az értékeket, 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 miként használhatta korábban a kivonatolókat.

Kivonatolók létrehozása értékekkel

Eddig egy üres kivonatolót hoztam létre ezekhez a példákhoz. A kulcsokat és értékeket a létrehozásukkor előre feltöltheti.

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

Keresési táblaként

Az ilyen típusú kivonatolók valódi értéke, 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 a megfelelő kiszolgálót választja ki. Használhat egy switch($env){...} ilyen kijelölést, de a kivonatoló egy szép lehetőség.

Ez még jobb lesz, ha dinamikusan hozza létre a keresési táblát, hogy később használhassa. Ezért gondolja át ezt a megközelítést, amikor 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, ahol a teljesítmény számít, ezt a megközelítést figyelembe kell venni.

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

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

Általában kulcs/érték párként tekint egy kivonatolóra, ahol egy kulcsot ad meg, és egy értéket kap. A PowerShell lehetővé teszi a kulcsok tömbjének megadását több érték lekéréséhez.

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

Ebben a példában ugyanazt a keresési kivonatolót használom fentről, és három különböző tömbstílust biztosítok az egyezések lekéréséhez. Ez egy rejtett gyöngyszem a PowerShellben, amelyről a legtöbb ember nem tud.

Kivonatolók iterálása

Mivel a kivonatoló kulcs-érték párok gyűjteménye, a tömbhöz vagy az elemek normál listájához képest másként kell iterálnia.

Az első dolog, amit észre kell venni, hogy ha a cső a kivonatoló, a cső kezeli, mint egy objektum.

PS> $ageList | Measure-Object
count : 1

Annak ellenére, hogy a .count tulajdonság azt jelzi, 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

Ugyanez a példa egy hurokkal foreach(){...} .

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

A kivonatolóban minden kulcsot sétáltatunk, majd azt használjuk az érték eléréséhez. Ez egy gyakori minta a kivonatolók gyűjteményként való használatakor.

GetEnumerator()

Ez elvezet minket a GetEnumerator() kivonatolón keresztüli 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ékpá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 nem lehet módosítani a kivonatolót. 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 az 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'
}

Kivonatoló tulajdonságok gyűjteményeként

Eddig a hashtable-ban elhelyezett objektumok típusa azonos típusú objektum volt. Az összes példában korokat használtam, és a kulcs a személy neve volt. Ez egy nagyszerű módja annak, hogy megtekintsük, ha az objektumgyűjteménynek van egy neve. A Kivonatolók PowerShellben való használatának egy másik gyakori módja, ha egy tulajdonsággyűjteményt tárol, ahol a kulcs a tulajdonság neve. Ebben 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 kivonatolók dinamikáját, és azt, hogy hogyan használhatja őket a PowerShellben. Íme a fenti 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 kivonatolóban. Attól függően, hogy hogyan definiálta a kulcsokat és az értékeket, ez vagy egy kicsit furcsa, vagy tökéletes. A korlista példája eddig remekül működött. Ehhez egy új példára van szükségünk, hogy jól érezzük magunkat a továbbhaladáshoz.

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

Az ilyen attribútumokhoz $person pedig hozzáadhatunk és hozzáférhetünk.

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

Hirtelen ez a kivonatoló kezd é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 más szemszögbő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óval:

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

Egyszerű, de sok hiba forrása volt számomra, mert figyelmen kívül hagytam a logikám egyik fontos részletét. Elkezdtem használni, hogy tesztelje, van-e kulcs. Ha az érték nulla volt $false , az utasítás váratlanul vissza fog térni $false .

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

Ez a probléma nulla érték esetén működik, de nem $null és nem létező kulcsok esetében. Legtöbbször nem kell ezt a megkülönböztetést elvégeznie, de vannak függvények, amikor ezt teszi.

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

Van egy ContainsValue() olyan helyzet is, amikor egy érték tesztelésére van szükség a kulcs ismerete vagy az egész gyűjtemény iterálása nélkül.

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 kivonatolók törlésének gyakori módja, ha csak inicializálja azt egy üres kivonatolóba.

$person = @{}

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

$person.clear()

Ez egyike azoknak a példányoknak, ahol a függvény használata ön dokumentáló kódot hoz létre, és nagyon tisztavá teszi a kód szándékait.

Minden szórakoztató dolog

Rendezett kivonatolók

Alapértelmezés szerint a kivonatolók nincsenek rendezve (vagy rendezve). A hagyományos környezetben a sorrend nem számít, ha mindig egy kulcsot használ az értékek eléréséhez. Előfordulhat, hogy azt szeretné, hogy a tulajdonságok a megadott sorrendben maradjanak. Szerencsére van mód erre a ordered kulcsszóval.

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

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

Beágyazott kivonatolók

Ha egy sor kivonatolóját definiálja, 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 kivonatolók használatát egyéni vagy számított tulajdonságok létrehozásához. Ezt gyakran látja a következővel Select-Object : és Format-Table. A kivonatolók egy speciális szintaxissal rendelkeznek, amely így néz ki teljes kibontáskor.

$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. A szkript működés közben a következő:

$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 meghatározható beágyazottan, és rövidíthet name n rá és expression arra e is, amíg ön ott van.

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

Én személy szerint nem tetszik, hogy mennyi ideig teszi parancsokat, és ez gyakran előléptet néhány rossz viselkedést, hogy én nem jutok be. Nagyobb valószínűséggel hozok létre egy új kivonatolót, vagy pscustomobject az összes olyan mezőt és tulajdonságot, amelyet szeretnék ahelyett, hogy ezt a módszert használnám szkriptekben. De van egy csomó kód, ami ezt teszi, ezért azt akartam, hogy tudd. Egy későbbi létrehozásról pscustomobject beszélek.

Egyéni rendezési kifejezés

A gyűjtemények könnyen rendezhetők, ha az objektumok rendelkeznek a rendezni kívánt adatokkal. Rendezés előtt hozzáadhatja az adatokat az objektumhoz, vagy létrehozhat egy egyéni kifejezést.Sort-Object

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

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

Kivonatolók listájának rendezése

Ha rendelkezik a rendezni kívánt kivonatoló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}}

Splatting hashtables at parancsmagok

Ez az egyik kedvenc dolog a kivonatolókkal kapcsolatban, amelyeket sokan nem fedeznek fel korán. Az ötlet az, hogy ahelyett, hogy minden tulajdonságot megadnál egy parancsmagnak egy sorban, ehelyett egy kivonatolóba csomagolhatja őket először. 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 definiálni. Vagy legörget a képernyőről, vagy ott burkol, ahol valaha is érzi magát. 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

Az splat műveletet a @ jel helyett a jel $ használata hívja meg.

Csak szánjon egy kis időt, hogy értékelje, milyen könnyen olvasható ez a példa. Pontosan ugyanaz a parancs, ugyanazokkal az értékekkel. A második könnyebb megérteni és fenntartani a továbblépés.

Splattingot használok, amikor a parancs túl hosszú lesz. Túl sokáig definiálom, amíg az ablakom jobbra görget. Ha három tulajdonságot érek el egy függvénynél, akkor az esélyek az, hogy átírom egy szórt kivonatolóval.

Splatting opcionális paraméterekhez

A splatting egyik leggyakoribb módja az opcionális paraméterek kezelése, amelyek más helyről származnak a szkriptemben. Tegyük fel, hogy van egy függvényem, amely egy opcionális $Credential argumentumot tartalmazó hívást burkolGet-CIMInstance.

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

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

Get-CIMInstance @CIMParams

Először létrehozom a kivonatolót a gyakori paraméterekkel. Aztán hozzáadom a $Credential ha létezik. Mivel itt splattingot használok, csak egyszer kell meghívnom Get-CIMInstance a kódot. Ez a tervezési minta nagyon tiszta, és sok opcionális paramétert könnyen kezelhet.

A korrektség kedvéért megírhatja a parancsokat a paraméterek értékeinek engedélyezéséhez $null . Csak nem mindig tudja szabályozni a többi parancsot, amit hív.

Több léc

Több kivonatolót is létrehozhat ugyanahhoz a parancsmaghoz. 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 adok át.

Splatting a tiszta kódhoz

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

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

Végrehajtható elemek splattingja

A splatting néhány szintaxist /param:value használó végrehajtható eszközön 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.

Kivonatolók hozzáadása

A kivonatolók támogatják az összeadás operátort két kivonatoló kombinálásához.

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

Ez csak akkor működik, ha a két kivonatoló nem osztozik kulcson.

Beágyazott kivonatolók

A kivonatolókat értékként használhatjuk egy kivonatolóban.

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

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

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

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

$person.location.city
Austin

Számos módon közelítheti meg az objektumok szerkezetét. Íme egy második módszer a beágyazott kivonatoló megtekintésére.

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

Ez ötvözi a kivonatolók objektumgyűjteményként és tulajdonsággyűjteményként való használatának fogalmát. Az értékek továbbra is könnyen elérhetők, még akkor is, ha azokat tetszőleges megközelítéssel á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 úgy kezelem, mint egy tulajdonságot. Ezek általában olyan dolgok, amelyeket statikusan definiáltam a kódban, és ismerem őket a fejem tetejéről. Ha végig kell lépnem a listán, vagy programozott módon hozzáférek a kulcsokhoz, a zárójelek segítségével 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 kivonatolók beágyazásának képessége sok rugalmasságot és lehetőséget biztosít.

Beágyazott kivonatolók keresése

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

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

A parancsom ConvertTo-JSON azért van, mert nagyon tiszta, és gyakran használok JSON-t más dolgokra.

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 tetszik a JSON nézet.

Objektumok létrehozása

Néha csak egy objektumra van szüksége, és a tulajdonságok tárolására használt kivonatoló egyszerűen nem végzi el a feladatot. A kulcsokat leggyakrabban oszlopnevekként szeretné látni. A pscustomobject megkönnyíti a dolgunkat.

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

$person

name  age
----  ---
Kevin  36

Még akkor is, ha eredetileg nem hozza létre pscustomobject , igény szerint később is leadhatja.

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

[pscustomobject]$person

name  age
----  ---
Kevin  36

Már van részletes írás a pscustomobject , hogy el kell menni olvasni után ez. Sok mindenre épül, amit itt tanultak.

Kivonatolók olvasása és írása fájlba

Mentés CSV-be

Küzd azzal, hogy kap egy kivonatolót, hogy mentse a CSV az egyik nehézség, hogy utaltam a fenti. Konvertálja a kivonatolót csV-vé pscustomobject , és a rendszer helyesen menti azt CSV-vé. Segít, ha egy pscustomobject oszlopsorrend megőrzésével kezdi. De szükség esetén átadhatja egy pscustomobject beágyazott fájlba.

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

Ismét, nézd meg az én írási segítségével pscustomobject.

Beágyazott kivonatoló mentése fájlba

Ha egy beágyazott kivonatolót kell mentenem egy fájlba, majd újra beolvasni, akkor a JSON-parancsmagok használatával csinálom.

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

A módszernek két fontos pontja van. Először is, hogy a JSON van kií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 ez problémákat okozhat, ha nem számít rá.

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

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

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

A Mélység paraméter használatával győződjön meg arról, hogy kibontotta az összes beágyazott kivonatolót.

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

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

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

JSON átalakítása kivonatolóvá

Ha JSON-t kell átalakítania egy [hashtable], van egy módja, hogy tudom, hogy ezt a JavaScriptSerializer a .NET- ben.

[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 kivonatoló támogatást ad hozzá.

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

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

A PowerShell 6.2 hozzáadta a Mélység 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ó kivonatolót tartalmazó fájllal rendelkezik, akkor 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 scriptblockfájlba, 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 kivonatoló?

A kulcsok bármilyen objektum lehetnek

A kulcsok legtöbbször 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 tehetsz 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.

A kulcsnak gyakorlatilag nem kell sztringnek lennie, de könnyebben átgondolhatók, 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 kivonatolóban lévő értékek elérése a kulcsával nem mindig működik. Példa:

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

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

Automatikus változók használata

$PSBoundParameters

$PSBoundParameters egy automatikus változó, amely csak egy függvény környezetében létezik. Az összes paramétert tartalmazza, amellyel a függvényt meghívták. Ez nem pontosan egy kivonatoló, 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ó platformálását. Ha úgy találja, hogy proxyfüggvényeket ír, tekintse meg közelebbről ezt.

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

PSBoundParameters gotcha

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

$PSDefaultParameterValues

Ez az automatikus változó lehetővé teszi az 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 kivonatolóhoz, amely a paraméter alapértelmezett értékeként Out-File -Encoding van beadvaUTF8. Ez munkamenet-specifikus, ezért a $profile.

Ezt gyakran használom olyan értékek előzetes hozzárendeléséhez, amelyeket elég gyakran írok be.

$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 michael sorens automatikus alapértelmezett beállításokról szóló nagyszerű cikkét.

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, amiről a legtöbb ember nem tud. Ha névvel ellátott regex egyezést használ, akkor a találatokon név szerint érheti el az egyezést.

$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. Ez az érték ezután a $Matches.Name tulajdonságba kerül.

Group-Object -AsHashtable

Ennek egyik kevéssé ismert funkciója Group-Object , hogy egyes adathalmazokat kivonatolóvá alakíthat.

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

Ez hozzáadja az egyes sorokat egy kivonatoló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 kivonatolók objektumok. És minden változó csak egy objektumra mutató hivatkozás. Ez azt jelenti, hogy több munka szükséges a kivonatoló érvényes másolatának létrehozásához.

Referenciatípusok hozzárendelése

Ha egy kivonatolóval rendelkezik, és egy második változóhoz rendeli hozzá, mindkét változó ugyanarra a kivonatoló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 kivonatolókat ad át más függvényeknek. Ha ezek a függvények módosítják a kivonatolót, az eredeti is módosul.

Sekély másolatok, egyszintű

Ha van egy egyszerű kivonatolónk, mint a fenti példánk, akkor készíthetünk .Clone() 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 másolatok, beágyazott

Azért nevezik sekély másolatnak, mert csak az alapszintű tulajdonságokat másolja. Ha az egyik tulajdonság referenciatípus (például egy másik kivonatoló), 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]

Láthatja, hogy bár klónoztam a kivonatolót, a hivatkozás person nem klónozott. Egy mély másolatot kell készítenünk, hogy valóban legyen egy második kivonatoló, amely nem kapcsolódik az elsőhöz.

Mély másolatok

Többféleképpen is készíthet mély másolatot a kivonatolóról (és megtarthatja kivonatoló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ópont.

Egy másik módszer, ha a .Net használatával deszerializálja azt a CliXml használatával, mint ebben a függvényben:

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

A rendkívül nagy kivonatolók esetében a deszerializáló függvény gyorsabb, ahogy kiskálázódik. Ennek a módszernek a használatakor azonban figyelembe kell venni néhány dolgot. Mivel CliXml-et használ, memóriaigényes, és ha hatalmas kivonatolókat klónoz, ez problémát jelenthet. A CliXml másik korlátozása a 48-as mélységi korlátozás. Ez azt jelenti, hogy ha 48 réteg beágyazott kivonatolóval rendelkező kivonatolóval rendelkezik, a klónozás sikertelen lesz, és a kivonatoló egyáltalán nem lesz kimenet.

Bármi egyéb?

Gyorsan lefedtem a földet. Remélem, hogy elsétálsz, ha valami újat hajolsz, vagy jobban megérted minden alkalommal, amikor ezt olvasod. Mivel lefedtem ennek a funkciónak a teljes spektrumát, vannak olyan szempontok, amelyek most nem feltétlenül vonatkoznak Önre. Ez tökéletesen rendben van, és elvárható attól függően, hogy mennyit dolgozik a PowerShell-lel.