Tekstoutput fra kommandoer i PowerShell's interpretervinduet er blot en måde at vise information på en menneskelig forståelig måde. I virkeligheden er miljøet til at arbejde med objekter: cmdlets og funktioner modtager dem som input og , og de tilgængelige variabeltyper i interaktiv tilstand og i scripts er baseret på .NET-klasser. I denne fjerde artikel i serien vil vi undersøge arbejdet med objekter mere detaljeret.
Indholdsfortegnelse:
Objekter i PowerShell
Husk, at et objekt er en samling af datarammer (egenskaber, hændelser osv.) og metoder til at behandle dem. Dets struktur er bestemmes af typen, som normalt er baseret på klasser fra den standardiserede .NET Core-platform. Der er også mulighed for at arbejde med COM-, CIM (WMI) og ADSI-objekter. Egenskaber og metoder er nødvendige for at udføre forskellige handlinger på data, og i PowerShell kan objekter også videregives som argumenter til funktioner og cmdlets, tildeles værdier til variabler, og der findes også (pipeline). Hver kommando i pipelinen sender sit output videre til den næste sekventielt - objekt for objekt. For behandlingen kan man bruge komprimerede cmdlets eller oprette sine egne , for at udføre forskellige manipulationer med objekter i pipelinen: filtrering, sortering, gruppering og endda ændring af deres struktur. Dataoverførsel i denne form har en betydelig fordel: den modtagende kommando behøver ikke at håndtere syntaktisk analyse af byte-strømmen (tekst), al nødvendig information kan let udtrækkes ved hjælp af henvisning til de relevante egenskaber og metoder.
Visning af objektstrukturer
Som eksempel kører vi cmdlet'en Get-Process, der gør det muligt at få information om de aktive processer i systemet:

Den vil vise nogle formaterede tekstdata, der ikke giver indtryk af egenskaberne ved de returnerede objekter og deres metoder. For at finjustere output er det nødvendigt at lære at undersøge objektets struktur, og her vil cmdleten Get-Member hjælpe os:
Get-Process | Get-Member 
Her ser vi allerede typen og strukturen, og med hjælp fra ekstra parametre kan vi for eksempel kun vise egenskaberne for det indkomne objekt:
Get-Process | Get-Member -MemberType PropertyDenne viden vil være nyttig til at løse administrative opgaver i interaktiv tilstand eller til at skrive egne scripts: for eksempel for at få oplysninger om hængte processer ved hjælp af egenskaben Responding.
Filtrering af objekter
PowerShell giver mulighed for at sende objekter gennem røret, der opfylder et bestemt kriterium:
Where-Object { scriptblok }Resultatet af udførelsen af scriptblokken i parenteserne skal være en boolesk værdi. Hvis den er sand ($true), vil det objekt, der går ind i Where-Object cmdleten, blive sendt videre i røret; ellers (værdi $false) bliver det fjernet. For eksempel kan vi vise listen over stoppede Windows Server-tjenester, det vil sige dem, hvis egenskab Status har værdien "Stopped":
Get-Service | Where-Object {$_.Status -eq "Stopped"} 
Her ser vi igen tekstrepræsentationen, men hvis man ønsker at forstå typen og den interne struktur af de objekter, der passerer gennem røret, er det ikke svært:
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member 
Sortering af objekter
Ved behandlingen af objekter gennem røret opstår der ofte behov for at sortere dem. Cmdleten Sort-Object modtager navne på egenskaber (sorteringsnøgler), og den returnerer objekter sorteret efter deres værdier. Det er ikke svært at sortere output af aktive processer efter den brugte CPU-tid (egenskaben cpu):
Get-Process | Sort-Object –Property cpuParameteren -Property kan udelades ved kald til cmdleten Sort-Object — den anvendes som standard. For omvendt sortering anvendes parameteren -Descending:
Get-Process | Sort-Object cpu -Descending 
Udvælgelse af objekter og deres dele
Cmdleten Select-Object giver mulighed for at vælge et bestemt antal objekter i begyndelsen eller slutningen af røret ved hjælp af parametrene -First eller -Last. Man kan vælge enkeltstående objekter eller bestemte egenskaber, samt oprette nye objekter baseret på dem. Lad os analysere cmdlets funktionalitet i enkle eksempler.
Den følgende kommando viser information om 10 processer, der bruger den maksimale mængde hukommelse (egenskab WS):
Get-Process | Sort-Object WS -Descending | Select-Object -First 10 
Man kan udtrække specifikke egenskaber fra objekterne i røret og oprette nye på baggrund af dem:
Get-Process | Select-Object ProcessName, Id -First 1Som resultat af røret vil vi få et nyt objekt, hvis struktur vil være anderledes end strukturen returneret af Get-Process. Lad os bekræfte dette med Get-Member:
Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member 
Bemærk, at Select-Object returnerer et enkelt objekt (-First 1), som kun har de to felter, vi angav: deres værdier blev kopieret fra det første objekt, der blev sendt til røret af Get-Process cmdlet.
$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType() 
Med Select-Object kan man tilføje beregnede egenskaber til objekter, som skal præsenteres som . Her svarer værdien af den første nøgle til navnet på egenskaben, og værdien af den anden til egenskaben for det aktuelle element i røret:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} 
Lad os se på strukturen af objekterne, der passerer gennem røret:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member 
ForEach-Object, Group-Object og Measure-Object
Der findes også andre cmdlets til at arbejde med objekter. Som eksempel vil vi beskrive tre af de mest nyttige:
ForEach-Object giver mulighed for at udføre PowerShell-kode for hvert objekt i røret:
ForEach-Object { scriptblok }Group-Object grupperer objekter efter værdien af en egenskab:
Group-Object PropertyNameHvis man kører det med parameteren -NoElement, kan man finde ud af antallet af elementer i grupperne.
Measure-Object aggregerer forskellige opsummeringsparametre baseret på værdierne af felterne i objekterne i røret (beregner summen samt finder minimum, maksimum eller gennemsnit):
Measure-Object -Property PropertyName -Minimum -Maximum -Average -SumNormalt bruges de nævnte cmdlets i interaktiv tilstand, mens der oftere oprettes med blokkene Begin, Process og End.
Oprettelse af .NET- og COM-objekter (New-Object)
Der er mange softwarekomponenter med .NET Core- og COM-grænseflader, som kan være nyttige for systemadministratorer. Ved hjælp af klassen System.Diagnostics.EventLog kan du administrere systemlogfiler direkte fra Windows PowerShell. Lad os gennemgå et eksempel på oprettelsen af en instans af denne klasse ved hjælp af cmdlet'en New-Object med parameteren -TypeName:
New-Object -TypeName System.Diagnostics.EventLog 
Da vi ikke har angivet en bestemt hændelseslog, indeholder den oprettede instans af klassen ikke data. For at ændre dette skal vi under oprettelsen anvende en særlig konstruktørmetode ved hjælp af parameteren -ArgumentList. Hvis vi ønsker adgang til applikationsloggen, skal vi angive strengen "Application" som argument til konstruktøren:
$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog 
Bemærk: Udsalgsdataene fra kommandoen er gemt i variablen $AppLog. Selvom der typisk anvendes pipelines i interaktiv tilstand, kræver scripting ofte, at man gemmer en reference til objektet. Desuden findes de grundlæggende .NET Core-klasser i navnerummet System: PowerShell leder som standard efter de angivne typer der, så det er helt korrekt at skrive Diagnostics.EventLog i stedet for System.Diagnostics.EventLog.
For at arbejde med loggen kan du få adgang til de relevante metoder:
$AppLog | Get-Member -MemberType Method 
Lad os sige, at den ryddes med metoden Clear() hvis der er tilstrækkelige rettigheder:
$AppLog.Clear()Cmdlet'en New-Object bruges også til at arbejde med COM-komponenter. Der er ret mange af dem — fra de scripts, der leveres med serveren, til ActiveX-applikationer som for eksempel Internet Explorer. For at oprette en COM-objekt skal du angive parameteren -ComObject med ProgId for den ønskede klasse:
New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObjectFor at oprette brugerdefinerede objekter med en hvilken som helst struktur virker brugen af New-Object alt for forældet og besværlig, denne cmdlet bruges typisk til at arbejde med eksterne programkomponenter i forhold til PowerShell. I de følgende artikler vil dette emne blive undersøgt nærmere. Udover .NET- og COM-objekter vil vi også studere CIM- (WMI) og ADSI-objekter.
Kald af statiske metoder
Det er umuligt at oprette instanser af nogle .NET Core-klasser: blandt dem er System.Environment og System.Math. De er og indeholder kun statiske egenskaber og metoder. I bund og grund er det hjælpebiblioteker, der bruges uden at oprette objekter. Man kan referere til en statisk klasse gennem litteralen ved at sætte typenavnet i firkantede parenteser. Hvis man ser på objektets struktur ved hjælp af Get-Member, vil vi se typen System.RuntimeType i stedet for System.Environment:
[System.Environment] | Get-Member 
For kun at se de statiske elementer skal man kalde Get-Member med parameteren -Static (bemærk objektets type):
[System.Environment] | Get-Member -Static 
For at få adgang til statiske egenskaber og metoder bruges to på hinanden følgende kolon i stedet for punktum efter litteralen:
[System.Environment]::OSVersionEller
$test=[System.Math]::Sqrt(25)
$test
$test.GetType() 
Typen PSCustomObject
Blandt de mange datatyper, der er tilgængelige i PowerShell, skal PSCustomObject nævnes, da den er beregnet til at gemme objekter med vilkårlig struktur. Oprettelse af et sådant objekt ved hjælp af cmdlet'en New-Object betragtes som en klassisk, men tung og forældet metode:
$object = New-Object –TypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'}
Lad os se på objektets struktur:
$object | Get-Member 
Fra PowerShell 3.0 er der også en anden syntaks tilgængelig:
$object = [PSCustomObject]@{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'
}
Adgang til data kan opnås på en af de ækvivalente måder:
$object.Name
$object.'Name'
$value = 'Name'
$object.$value
Lad os give et eksempel på konvertering til et objekt fra en eksisterende hash-tabel:
$hash = @{'Name'='Ivan Danko'; 'City'='Moscow'; 'Country'='Russia'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()

En af ulemperne ved objekter af denne type er, at rækkefølgen af deres egenskaber kan ændre sig. For at undgå dette er det nødvendigt at bruge attributten [ordered]:
$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'
}
Der er også andre muligheder for oprettelse af objektet: ovenfor har vi set brugen af cmdlet'en . Vi skal nu se på tilføjelse og fjernelse af elementer. At gøre dette for objektet fra det tidligere eksempel er ret enkelt:
$object | Add-Member –MemberType NoteProperty –Name Age –Value 33
$object | Get-Member

Cmdlet'en Add-Member tillader ikke kun tilføjelse af egenskaber til det tidligere oprettede objekt $object, men også metoder ved hjælp af konstruktionen "-MemberType ScriptMethod":
$ScriptBlock = {
# kode
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member
Bemærk: Vi brugte variablen $ScriptBlock af typen ScriptBlock til at gemme koden til den nye metode.

For at fjerne egenskaber anvendes den relevante metode:
$object.psobject.properties.remove('Name')
Oprettelse af egne klasser
I PowerShell 5.0 blev det muligt at definere ved hjælp af syntaksen typisk for objektorienterede programmeringssprog. Dette gøres med det reserverede ord Class, efterfulgt af klassens navn og en beskrivelse af dens krop i krøllede parenteser:
class MyClass
{
# klassens krop
}
Dette er en ægte .NET Core type, hvis krop beskriver dens egenskaber, metoder og andre elementer. Lad os se et eksempel på definitionen af en simpel klasse:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
}
For at oprette et objekt (en instans af klassen) bruges cmdlet'en , eller type litteral [MyClass] og new (standardkonstruktøren):
$object = New-Object -TypeName MyClasseller
$object = [MyClass]::new()Lad os analysere objektets struktur:
$object | Get-Member 
Det er vigtigt at huske på synlighedsområdet: man kan ikke referere til typen som en streng eller bruge type litteralen uden for det script eller modul, hvori klassen er defineret. Beholdere (funktioner) kan dog returnere klasseinstanser (objekter), som vil være tilgængelige uden for modulet eller scriptet.
Efter oprettelsen af objektet udfylder vi dets egenskaber:
$object.Name = 'Ivan Danko'
$object.City = 'Moscow'
$object.Country = 'Russia'
$object

Vi bemærker, at der i klassens beskrivelse angives ikke blot egenskabernes typer, men også deres standardværdier:
class Example
{
[string]$Name = 'John Doe'
}
Beskrivelsen af metode i klassen minder om beskrivelsen af en funktion, men uden at bruge det reserverede ord function. Som i en funktion kan der være parametre, der sendes til metoderne:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
#beskrivelse af metoden
Smile([bool]$param1)
{
If($param1) {
Write-Host ':)'
}
}
}
Nu kan vores klasserepræsentant smile:
$object = [MyClass]::new()
$object.Smile($true)
Metoder kan overbelastes, desuden har klassen , og også konstruktører, hvis navne matcher klassens eget navn. En klasse defineret i et PowerShell-skript eller -modul kan fungere som en base for en anden — sådan realiseres arv. Eksisterende .NET-klasser kan bruges som basisklasser:
class MyClass2 : MyClass
{
#kroppen af den nye klasse, der er baseret på MyClass
}
[MyClass2]::new().Smile($true)
Vores beskrivelse af arbejdet med objekter i PowerShell er svær at kalde udtømmende. I de næste publikationer vil vi prøve at uddybe det med praktiske eksempler: den femte artikel i serien vil være dedikeret til spørgsmålet om integration af PowerShell med tredjeparts softwarekomponenter. Tidligere dele kan findes via linkene nedenfor.
Kilde: habr.com
