De tekstuele uitvoer van commando's in de PowerShell-interpreter is slechts een manier om informatie in een menselijk leesbare vorm weer te geven. In werkelijkheid is de omgeving op het werken met objecten: cmdlets en functies ontvangen deze als invoer en , en de in interactieve modus en in scripts beschikbare variabele types zijn gebaseerd op .NET-klassen. In het vierde artikel van de cyclus zullen we dieper ingaan op het werken met objecten.
Inhoudsopgave:
Objecten in PowerShell
Laten we herinneren dat een object een verzameling van gegevensvelden (eigenschappen, gebeurtenissen, enz.) en methoden voor hun verwerking is. De structuur ervan wordt bepaald door het type, dat meestal is gebaseerd op de in de uniforme .NET Core-platform gebruikte klassen. Er is ook de mogelijkheid om met COM-, CIM (WMI)- en ADSI-objecten te werken. Eigenschappen en methoden zijn nodig om verschillende acties op gegevens uit te voeren, bovendien kunnen in PowerShell objecten als argumenten worden doorgegeven aan functies en cmdlets, kunnen hun waarden aan variabelen worden toegewezen, en er is ook een (de pipeline). Elk commando in de pipeline geeft zijn uitvoer achtereenvolgens door aan het volgende ā object voor object. Voor verwerking kunnen gecompileerde cmdlets worden gebruikt of kunnen eigen , om verschillende manipulaties met objecten in de pipeline uit te voeren: filteren, sorteren, groeperen en zelfs hun structuur te wijzigen. Het doorgeven van gegevens op deze manier heeft een aanzienlijk voordeel: het ontvangende commando hoeft zich geen zorgen te maken over de syntactische parsing van de byte-stroom (tekst), alle benodigde informatie kan eenvoudig worden geĆ«xtraheerd door toegang te krijgen tot de bijbehorende eigenschappen en methoden.
Structuur van objecten bekijken
Als voorbeeld zullen we de cmdlet Get-Process uitvoeren, waarmee je informatie over actieve processen in het systeem kunt verkrijgen:

Het zal geformatteerde tekstgegevens op het scherm weergeven die geen inzicht geven in de eigenschappen van de geretourneerde objecten en hun methoden. Voor een grondige analyse van de uitvoer moet je leren de structuur van objecten te onderzoeken, en hiervoor helpt de cmdlet Get-Member ons:
Get-Process | Get-Member 
Hier zien we al het type en de structuur, en met behulp van extra parameters kunnen we bijvoorbeeld alleen de eigenschappen van het object dat binnenkomt weergeven:
Get-Process | Get-Member -MemberType PropertyDeze kennis is nodig voor het oplossen van beheertaken in interactieve modus of voor het schrijven van je eigen scripts: laten we zeggen, om informatie over vastgelopen processen op te halen op basis van de eigenschap Responding.
Objecten filteren
PowerShell staat toe dat objecten die aan bepaalde voorwaarden voldoen door de pijplijn worden doorgestuurd:
Where-Object { scriptblok }Het resultaat van de uitvoering van het scriptblok tussen haakjes moet een logisch waarde zijn. Als deze waar ($true) is, wordt het object dat naar de cmdlet Where-Object komt doorgestuurd in de pijplijn; in het andere geval (waarde $false) wordt het verwijderd. Laten we ter illustratie een lijst met gestopte Windows Server-services weergeven, d.w.z. degenen waarvan de eigenschap Status gelijk is aan "Stopped":
Get-Service | Where-Object {$_.Status -eq "Stopped"} 
Hier zien we opnieuw een tekstuele weergave, maar als we de type en interne werking van de objecten die door de pijplijn gaan willen begrijpen, is dat niet moeilijk:
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member 
Objecten sorteren
Bij het pijplijngerichte verwerken van objecten komt vaak de noodzaak van sorteren op. Bij de cmdlet Sort-Object worden de namen van de eigenschappen (sorteringssleutels) doorgegeven, en deze retourneert de objecten gesorteerd op hun waarden. Het is niet moeilijk om de uitvoer van actieve processen te sorteren op de verbruikte CPU-tijd (eigenschap cpu):
Get-Process | Sort-Object āProperty cpuDe parameter -Property kan bij het aanroepen van de cmdlet Sort-Object weggelaten worden ā deze wordt standaard gebruikt. Voor omgekeerde sortering wordt de parameter -Descending toegepast:
Get-Process | Sort-Object cpu -Descending 
Objecten en hun delen selecteren
De cmdlet Select-Object stelt je in staat om een bepaald aantal objecten aan het begin of het einde van de pijplijn te selecteren met de parameters -First of -Last. Hiermee kun je enkele objecten of specifieke eigenschappen selecteren, evenals nieuwe objecten op basis daarvan maken. Laten we de werking van de cmdlet aan de hand van eenvoudige voorbeelden bekijken.
Met de volgende opdracht kunt u informatie opvragen over de 10 processen die het meeste RAM verbruiken (eigenschap WS):
Get-Process | Sort-Object WS -Descending | Select-Object -First 10 
U kunt alleen bepaalde eigenschappen van de objecten die door de pipeline gaan selecteren en nieuwe objecten op basis daarvan creƫren:
Get-Process | Select-Object ProcessName, Id -First 1Als resultaat van de pipeline krijgen we een nieuw object, waarvan de structuur zal verschillen van de structuur die door de Get-Process cmdlet wordt geretourneerd. Laten we dit verifiƫren met Get-Member:
Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member 
Let op, dat Select-Object een enkel object retourneert (-First 1), dat slechts twee velden bevat die we hebben opgegeven: hun waarden zijn gekopieerd van het eerste object dat door de Get-Process cmdlet naar de pipeline is gestuurd. Het gebruik van Select-Object is een van de manieren om objecten te creƫren in PowerShell-scripts:
$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType() 
Met Select-Object kunt u berekende eigenschappen aan objecten toevoegen, die moeten worden gepresenteerd als . Daarbij komt de waarde van de eerste sleutel overeen met de naam van de eigenschap, en de waarde van de tweede - met de waarde van de eigenschap voor het huidige element in de pipeline:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} 
Laten we kijken naar de structuur van de objecten die door de pipeline gaan:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member 
ForEach-Object, Group-Object en Measure-Object
Er zijn andere cmdlets voor het werken met objecten. Ter illustratie laten we drie van de meest nuttige zien:
ForEach-Object laat u PowerShell-code uitvoeren voor elk object in de pipeline:
ForEach-Object { scriptblok }Group-Object groepeert objecten op basis van de waarde van een eigenschap:
Group-Object PropertyNameAls je deze met de -NoElement parameter uitvoert, kun je het aantal elementen in de groepen ontdekken.
Measure-Object aggregeert verschillende samenvattende parameters op basis van de waarden van de velden in de objecten in de pipeline (berekent de som en vindt ook de minimum-, maximum- of gemiddelde waarde):
Measure-Object -Property PropertyName -Minimum -Maximum -Average -SumDe besproken cmdlets worden meestal in interactief modus gebruikt, terwijl in scripts vaker blokken worden gemaakt met Begin, Process en End. met blokken Begin, Process en End.
Objecten .NET en COM maken (New-Object)
Er zijn veel softwarecomponenten met .NET Core en COM-interfaces die waardevol zijn voor systeembeheerders. Met de klasse System.Diagnostics.EventLog kan je systeemlogboeken beheren direct vanuit Windows PowerShell. Laten we een voorbeeld bekijken van het maken van een instantie van deze klasse met behulp van de cmdlet New-Object met de parameter -TypeName:
New-Object -TypeName System.Diagnostics.EventLog 
Aangezien we geen specifieke gebeurtenislogboek hebben opgegeven, bevat de verkregen instantie van de klasse geen gegevens. Om dit te veranderen, is het nodig om tijdens het creƫren een speciale constructor aan te roepen met de parameter -ArgumentList. Als we toegang willen krijgen tot het toepassingslogboek, moeten we de string "Application" als argument aan de constructor doorgeven:
$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog 
Let op: we hebben de uitvoer van de opdracht opgeslagen in de variabele $AppLog. Hoewel pipelining meestal wordt gebruikt in interactieve modus, vereist het schrijven van scripts vaak dat er een verwijzing naar het object wordt opgeslagen. Bovendien bevinden de basisklassen van .NET Core zich in de namespace System: PowerShell zoekt daar standaard naar de opgegeven typen, dus het is heel correct om Diagnostics.EventLog in plaats van System.Diagnostics.EventLog te schrijven.
Om met het logboek te werken kan je de bijbehorende methoden aanroepen:
$AppLog | Get-Member -MemberType Method 
Laten we zeggen dat het wordt gewist met de methode Clear() als er toegangrechten zijn:
$AppLog.Clear()De cmdlet New-Object wordt ook gebruikt voor het werken met COM-componenten. Er zijn er behoorlijk wat ā van scripts met Windows-serverlibraries tot ActiveX-applicaties, zoals bijvoorbeeld Internet Explorer. Om een COM-object te creĆ«ren, moet de parameter -ComObject met de programmatische identificatie ProgId van de gewenste klasse worden opgegeven:
New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObjectVoor het creƫren van eigen objecten met een willekeurige structuur is het gebruik van New-Object te ouderwets en omslachtig; deze cmdlet wordt gebruikt voor het werken met externe softwarecomponenten ten opzichte van PowerShell. In de volgende artikelen zal dit onderwerp uitgebreider worden besproken. Naast .NET- en COM-objecten zullen we ook CIM (WMI) en ADSI-objecten bestuderen.
Statische methoden aanroepen
Instanties van sommige .NET Core-klassen kunnen niet worden gemaakt: onder deze bevinden zich System.Environment en System.Math. Ze zijn en bevatten alleen statische eigenschappen en methoden. Het zijn in wezen referentiebibliotheken die worden gebruikt zonder objecten te creƫren. Een statische klasse kan worden aangeroepen via een literiaal door de naam van het type tussen vierkante haken te plaatsen. Als we echter de structuur van het object bekijken met Get-Member, zien we het type System.RuntimeType in plaats van System.Environment:
[System.Environment] | Get-Member 
Om alleen de statische elementen te bekijken, moet Get-Member worden aangeroepen met de parameter -Static (let op het type object):
[System.Environment] | Get-Member -Static 
Voor toegang tot statische eigenschappen en methoden worden twee achtereenvolgende dubbele punten gebruikt in plaats van een punt na het literiaal:
[System.Environment]::OSVersionOf
$test=[System.Math]::Sqrt(25)
$test
$test.GetType() 
Type PSCustomObject
Onder de vele beschikbare datatypes in PowerShell verdient PSCustomObject speciale vermelding, bedoeld voor het opslaan van objecten met een willekeurige structuur. Het creƫren van zo'n object met de cmdlet New-Object wordt beschouwd als een klassieke, maar omslachtige en verouderde manier:
$object = New-Object āTypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Moskou';
Country = 'Rusland'}
Laten we kijken naar de structuur van het object:
$object | Get-Member 
Vanaf PowerShell 3.0 is er ook een andere syntaxis beschikbaar:
$object = [PSCustomObject]@{Name = 'Ivan Danko';
City = 'Moskou';
Country = 'Rusland'
}
Toegang tot de gegevens kan op een van de equivalente manieren:
$object.Name
$object.'Name'
$value = 'Name'
$object.$value
Laten we een voorbeeld geven van het omzetten van een bestaande hashtable naar een object:
$hash = @{'Name'='Ivan Danko'; 'City'='Moskou'; 'Country'='Rusland'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()

Een van de nadelen van objecten van dit type is dat de volgorde van hun eigenschappen kan veranderen. Om dit te voorkomen, moet je het attribuut [ordered] gebruiken:
$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko';
City = 'Moskou';
Country = 'Rusland'
}
Er zijn ook andere manieren om een object te creƫren: eerder hebben we het gebruik van de cmdlet . Nu rest ons om het toevoegen en verwijderen van elementen uit te leggen. Dit is vrij eenvoudig te doen voor het object uit het vorige voorbeeld:
$object | Add-Member āMemberType NoteProperty āName Age āValue 33
$object | Get-Member

De cmdlet Add-Member stelt je in staat niet alleen eigenschappen, maar ook methoden toe te voegen aan het eerder gemaakte object $object door gebruik te maken van de constructie "-MemberType ScriptMethod":
$ScriptBlock = {
# code
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member
Houd er rekening mee dat we een variabele $ScriptBlock van het type ScriptBlock hebben gebruikt om de code van de nieuwe methode op te slaan.

Om eigenschappen te verwijderen, wordt de bijbehorende methode gebruikt:
$object.psobject.properties.remove('Name')
Eigen klassen creƫren
Met PowerShell 5.0 werd het mogelijk om te definiƫren met behulp van de voor object-georiƫnteerde programmeertalen kenmerkende syntaxis. Hiervoor is het sleutelwoord Class bedoeld, gevolgd door de naam van de klasse en de beschrijving van de inhoud in accolades:
class MyClass
{
# klasse-inhoud
}
Dit is een echte .NET Core-typenaam, waarbij de eigenschappen, methoden en andere elementen worden beschreven. Laten we een voorbeeld bekijken van het definiƫren van de eenvoudigste klasse:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
}
Voor het maken van een object (een instantie van de klasse) wordt de cmdlet , of het type-lettertype [MyClass] en new (de standaardconstructor):
$object = New-Object -TypeName MyClassof
$object = [MyClass]::new()Laten we de structuur van het object analyseren:
$object | Get-Member 
Vergeet niet het bereik: het is niet toegestaan om naar de typenaam te verwijzen als een string of het type-lettertype buiten het script of de module te gebruiken, waarin de klasse is gedefinieerd. Functies kunnen echter instanties van de klasse (objecten) retourneren die buiten de module of het script toegankelijk zijn.
Na het maken van het object vullen we de eigenschappen in:
$object.Name = 'Ivan Danko'
$object.City = 'Moskou'
$object.Country = 'Rusland'
$object

Merk op dat in de beschrijving van de klasse niet alleen de types van de eigenschappen worden opgegeven, maar ook hun standaardwaarden:
class Example
{
[string]$Name = 'John Doe'
}
De beschrijving van de klasse-methode lijkt op de beschrijving van een functie, maar zonder het gebruik van het sleutelwoord function. Net als bij een functie kunnen parameters indien nodig aan de methoden worden doorgegeven:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
#beschrijving van de methode
Smile([bool]$param1)
{
If($param1) {
Write-Host ':)'
}
}
}
Nu kan een vertegenwoordiger van onze klasse glimlachen:
$object = [MyClass]::new()
$object.Smile($true)
Methoden kunnen worden overbelast, bovendien heeft een klasse , en ook constructors wiens namen overeenkomen met de naam van de klasse zelf. Een klasse die in een PowerShell-script of module is gedefinieerd, kan als basis dienen voor een andere klasse ā dit is hoe overerving wordt gerealiseerd. Bestaande .NET-klassen zijn toegestaan als basisklassen.
class MyClass2 : MyClass
{
# lichaam van de nieuwe klasse, waarvan MyClass de basis is
}
[MyClass2]::new().Smile($true)
Onze beschrijving van het werken met objecten in PowerShell kan moeilijk als volledig worden beschouwd. In volgende publicaties proberen we dit uit te diepen met praktische voorbeelden: het vijfde artikel van de serie zal zich richten op de integratie van PowerShell met externe softwarecomponenten. Vorige delen zijn te vinden via de onderstaande links.
Bron: habr.com
