L'output testuale dei comandi nella finestra dell'interprete PowerShell è semplicemente un modo per visualizzare le informazioni in un formato comprensibile per gli esseri umani. In realtà, l'ambiente è progettato per lavorare con gli oggetti: i cmdlet e le funzioni ricevono gli oggetti in input e , e i tipi di variabili disponibili in modalità interattiva e negli script sono basati sulle classi .NET. Nel quarto articolo della serie, esamineremo più dettagliatamente il lavoro con gli oggetti.
Indice:
Oggetti in PowerShell
Ricordiamo che un oggetto è un insieme di campi dati (proprietà, eventi, ecc.) e metodi per la loro elaborazione. La sua struttura è definita dal tipo, che solitamente si basa sulle classi utilizzate nella piattaforma unificata .NET Core. Inoltre, è possibile lavorare con oggetti COM, CIM (WMI) e ADSI. Le proprietà e i metodi servono a compiere varie azioni sui dati; inoltre, in PowerShell, gli oggetti possono essere passati come argomenti a funzioni e cmdlet, assegnarne i valori a variabili, e esiste (pipeline). Ogni comando nella pipeline passa il proprio output al successivo in sequenza, oggetto per oggetto. Per l'elaborazione, si possono utilizzare cmdlet compilati o creare proprie , per effettuare varie operazioni sugli oggetti nel conveyor: filtraggio, ordinamento, raggruppamento e persino modifica della loro struttura. La trasmissione dei dati in questo modo presenta un notevole vantaggio: il team ricevente non deve preoccuparsi di analizzare sintatticamente il flusso di byte (testo), tutte le informazioni necessarie possono essere facilmente estratte accedendo alle relative proprietà e metodi.
Visualizzazione della struttura degli oggetti
Per fare un esempio, eseguiamo il cmdlet Get-Process, che consente di ottenere informazioni sui processi attivi nel sistema:

Visualizzerà dati testuali formattati, che non forniscono informazioni sulle proprietà degli oggetti restituiti e sui loro metodi. Per analizzare in dettaglio l'output, dobbiamo imparare a esplorare la struttura degli oggetti, e qui ci aiuterà il cmdlet Get-Member:
Get-Process | Get-Member 
Qui possiamo già vedere il tipo e la struttura, e con parametri aggiuntivi possiamo, ad esempio, visualizzare solo le proprietà dell'oggetto passato in input:
Get-Process | Get-Member -MemberType PropertyQueste conoscenze saranno utili per risolvere compiti di amministrazione in tempo reale o per scrivere i propri script: ad esempio, per ottenere informazioni sui processi bloccati in base alla proprietà Rispondente.
Filtraggio degli oggetti
PowerShell consente di passarli attraverso la pipeline solo gli oggetti che soddisfano una certa condizione:
Where-Object { blocco dello script }Il risultato dell'esecuzione del blocco dello script tra parentesi deve essere un valore booleano. Se è vero ($true), l'oggetto in ingresso al cmdlet Where-Object verrà passato ulteriormente nella pipeline; in caso contrario (valore $false), verrà rimosso. Ad esempio, visualizziamo l'elenco dei servizi di Windows Server interrotti, cioè quelli per cui la proprietà Stato ha valore "Interrotto":
Get-Service | Where-Object {$_.Status -eq "Stopped"} 
Qui vediamo nuovamente una rappresentazione testuale, ma se desideriamo comprendere il tipo e la struttura interna degli oggetti che passano attraverso la pipeline, non è difficile:
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member 
Ordinamento degli oggetti
Quando si elaborano oggetti in un convezione, si presenta spesso la necessità di ordinarli. Al cmdlet Sort-Object vengono passati i nomi delle proprietà (chiavi di ordinamento), e restituisce oggetti ordinati in base ai loro valori. L'output dei processi in esecuzione può essere facilmente ordinato in base al tempo di CPU utilizzato (proprietà cpu):
Get-Process | Sort-Object –Property cpuIl parametro -Property nella chiamata al cmdlet Sort-Object può non essere specificato — è usato per impostazione predefinita. Per l'ordinamento inverso si utilizza il parametro -Descending:
Get-Process | Sort-Object cpu -Descending 
Selezione di oggetti e delle loro parti
Il cmdlet Select-Object consente di estrarre un numero specifico di oggetti all'inizio o alla fine del convezione utilizzando i parametri -First o -Last. Con questo è possibile selezionare singoli oggetti o determinate proprietà, e creare nuovi oggetti basati su di essi. Analizziamo il funzionamento del cmdlet con semplici esempi.
Il comando seguente restituisce informazioni sui 10 processi che consumano la massima quantità di memoria RAM (proprietà WS):
Get-Process | Sort-Object WS -Descending | Select-Object -First 10 
È possibile estrarre solo specifiche proprietà degli oggetti che transitano attraverso il convezione e creare nuovi oggetti basati su di esse:
Get-Process | Select-Object ProcessName, Id -First 1Il risultato dell'esecuzione della pipeline sarà un nuovo oggetto, la cui struttura sarà diversa rispetto a quella restituita dal cmdlet Get-Process. Verifichiamolo usando Get-Member:
Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member 
Si noti che Select-Object restituisce un singolo oggetto (-First 1), che ha solo due campi specificati da noi: i valori sono stati copiati dal primo oggetto passato nella pipeline dal cmdlet Get-Process. L'uso di Select-Object è alla base di uno dei modi per creare oggetti negli script PowerShell:
$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType() 
Con Select-Object è possibile aggiungere proprietà calcolate agli oggetti da presentare sotto forma di . In questo caso, il valore della sua prima chiave corrisponde al nome della proprietà, mentre il valore della seconda chiave è il valore della proprietà per l'elemento corrente della pipeline:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} 
Esaminiamo la struttura degli oggetti che passano attraverso la pipeline:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member 
ForEach-Object, Group-Object e Measure-Object
Esistono anche altri cmdlet per lavorare con gli oggetti. Ad esempio, parleremo di tre dei più utili:
ForEach-Object consente di eseguire codice in PowerShell per ogni oggetto nel pipeline:
ForEach-Object { blocco dello script }Group-Object raggruppa oggetti in base al valore di una proprietà:
Group-Object PropertyNameSe eseguito con il parametro -NoElement, è possibile conoscere il numero di elementi nei gruppi.
Measure-Object aggregando diversi parametri di sintesi in base ai valori dei campi degli oggetti nel pipeline (calcola la somma e trova il valore minimo, massimo o medio):
Measure-Object -Property PropertyName -Minimum -Maximum -Average -SumDi solito, i cmdlet esaminati vengono utilizzati in modalità interattiva, mentre negli script si creano più spesso con i blocchi Begin, Process e End.
Creazione di oggetti .NET e COM (New-Object)
Esistono numerosi componenti software con interfacce .NET Core e COM, utili per gli amministratori di sistema. Utilizzando la classe System.Diagnostics.EventLog, è possibile gestire i registri di sistema direttamente da Windows PowerShell. Analizziamo un esempio di creazione di un'istanza di questa classe utilizzando il cmdlet New-Object con il parametro -TypeName:
New-Object -TypeName System.Diagnostics.EventLog 
Poiché non abbiamo specificato un registro eventi particolare, l'istanza della classe ottenuta non contiene dati. Per modificare ciò, durante la sua creazione è necessario chiamare un metodo costruttore speciale tramite il parametro -ArgumentList. Se vogliamo accedere al registro delle applicazioni, dobbiamo passare la stringa "Application" come argomento al costruttore:
$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog 
Si noti che l'output del comando è stato salvato nella variabile $AppLog. Sebbene nel modo interattivo si usino solitamente le pipeline, la scrittura degli script richiede spesso di mantenere un riferimento all'oggetto. Inoltre, le classi principali di .NET Core si trovano nello spazio dei nomi System: PowerShell cerca automaticamente i tipi specificati al suo interno, quindi è del tutto corretto scrivere Diagnostics.EventLog invece di System.Diagnostics.EventLog.
Per lavorare con il registro, è possibile accedere ai metodi corrispondenti:
$AppLog | Get-Member -MemberType Method 
Diciamo che può essere svuotato con il metodo Clear() se si hanno i diritti di accesso:
$AppLog.Clear()Il cmdlet New-Object è utilizzato anche per lavorare con componenti COM. Ce ne sono molti, dalle librerie di script Windows fornite con il server ad applicazioni ActiveX, come ad esempio Internet Explorer. Per creare un oggetto COM, è necessario specificare il parametro -ComObject con l'identificatore ProgId della classe desiderata:
New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObjectPer creare oggetti personalizzati con strutture arbitrarie, l'uso di New-Object appare troppo arcaico e ingombrante. Questo cmdlet viene utilizzato per lavorare con componenti software esterni rispetto a PowerShell. Nelle prossime articoli esamineremo questo argomento in modo più dettagliato. Oltre agli oggetti .NET e COM, esploreremo anche gli oggetti CIM (WMI) e ADSI.
Chiamata di metodi statici
Non è possibile creare istanze di alcune classi .NET Core: tra queste ci sono System.Environment e System.Math. Sono e contengono solo proprietà e metodi statici. In effetti, sono librerie di riferimento che vengono utilizzate senza creare oggetti. È possibile riferirsi a una classe statica tramite il letterale, racchiudendo il nome del tipo tra parentesi quadre. Se si guarda la struttura dell'oggetto con Get-Member, vedremo il tipo System.RuntimeType anziché System.Environment:
[System.Environment] | Get-Member 
Per visualizzare solo gli elementi statici, è necessario chiamare Get-Member con il parametro -Static (nota il tipo dell'oggetto):
[System.Environment] | Get-Member -Static 
Per accedere alle proprietà e ai metodi statici, si usano due due punti consecutivi invece di un punto dopo il letterale:
[System.Environment]::OSVersionOppure
$test=[System.Math]::Sqrt(25)
$test
$test.GetType() 
Tipo PSCustomObject
Tra i numerosi tipi di dati disponibili in PowerShell, merita una menzione speciale il PSCustomObject, progettato per memorizzare oggetti con una struttura arbitraria. Creare tale oggetto con il cmdlet New-Object è considerato un metodo classico, ma ingombrante e obsoleto:
$object = New-Object –TypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Moscow';
Country = 'Russia'}
Diamo un'occhiata alla struttura dell'oggetto:
$object | Get-Member 
A partire da PowerShell 3.0 è disponibile anche un altro tipo di sintassi:
$object = [PSCustomObject]@{Name = 'Ivan Danko';
City = 'Mosca';
Country = 'Russia'
}
È possibile accedere ai dati in uno dei seguenti modi equivalenti:
$object.Name
$object.'Name'
$value = 'Name'
$object.$value
Facciamo un esempio di conversione in un oggetto da una hash table esistente:
$hash = @{'Name'='Ivan Danko'; 'City'='Mosca'; 'Country'='Russia'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()

Uno degli svantaggi di oggetti di questo tipo è che l'ordine delle loro proprietà può cambiare. Per evitarlo, è necessario utilizzare l'attributo [ordered]:
$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko';
City = 'Mosca';
Country = 'Russia'
}
Ci sono anche altre opzioni per creare un oggetto: sopra abbiamo visto l'uso del cmdlet . Resta da capire come aggiungere e rimuovere elementi. È piuttosto semplice farlo per l'oggetto dell'esempio precedente:
$object | Add-Member –MemberType NoteProperty –Name Age –Value 33
$object | Get-Member

Il cmdlet Add-Member consente di aggiungere all'oggetto $object creato in precedenza non solo proprietà, ma anche metodi utilizzando la struttura "-MemberType ScriptMethod":
$ScriptBlock = {
# codice
}
$oggetto | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$oggetto | Get-Member
Nota: abbiamo utilizzato la variabile $ScriptBlock di tipo ScriptBlock per memorizzare il codice del nuovo metodo.

Per rimuovere le proprietà si utilizza il metodo corrispondente:
$oggetto.psobject.properties.remove('Name')
Creazione di classi personalizzate
A partire da PowerShell 5.0 è possibile definire utilizzando una sintassi tipica dei linguaggi di programmazione orientati agli oggetti. A tale scopo è riservata la parola chiave Class, seguita dal nome della classe e dalla descrizione del corpo tra parentesi graffe:
class MyClass
{
# corpo della classe
}
Questo è un vero tipo .NET Core, nel cui corpo vengono definiti le sue proprietà, i metodi e altri elementi. Consideriamo un esempio di definizione di una classe semplice:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
}
Per creare un oggetto (istanza della classe) si utilizza il cmdlet , oppure il letterale di tipo [MyClass] e new (costruttore di default):
$oggetto = New-Object -TypeName MyClasso
$oggetto = [MyClass]::new()Analizziamo la struttura dell'oggetto:
$object | Get-Member 
Non dimentichiamo la visibilità: non è possibile fare riferimento al nome del tipo come una stringa o utilizzare un literal tipo al di fuori dello script o del modulo in cui è definita la classe. Tuttavia, le funzioni possono restituire istanze della classe (oggetti) che saranno accessibili al di fuori del modulo o dello script.
Dopo aver creato un oggetto, riempiamo le sue proprietà:
$object.Name = 'Ivan Danko'
$object.City = 'Mosca'
$object.Country = 'Russia'
$object

Va notato che nella descrizione della classe si specificano non solo i tipi delle proprietà, ma anche i loro valori predefiniti:
class Example
{
[string]$Name = 'John Doe'
}
La descrizione di un metodo di classe assomiglia alla descrizione di una funzione, ma senza l'uso della parola chiave function. Come per le funzioni, ai metodi possono essere passati parametri quando necessario:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
#descrizione del metodo
Smile([bool]$param1)
{
If($param1) {
Write-Host ':)'
}
}
}
Ora il rappresentante della nostra classe sa sorridere:
$object = [MyClass]::new()
$object.Smile($true)
I metodi possono essere sovraccaricati, inoltre una classe può avere , e anche i costruttori i cui nomi corrispondono al nome della classe stessa. Una classe definita in uno script o modulo PowerShell può fungere da base per un'altra — questo è il modo in cui viene realizzata l'ereditarietà. È possibile utilizzare classi esistenti di .NET come classi di base:
class MyClass2 : MyClass
{
#corpo della nuova classe basata su MyClass
}
[MyClass2]::new().Smile($true)
La nostra descrizione del lavoro con gli oggetti in PowerShell è difficile da definire completa. Nei prossimi articoli cercheremo di approfondirla con esempi pratici: il quinto articolo della serie sarà dedicato alle questioni di integrazione di PowerShell con componenti software di terze parti. Le parti precedenti possono essere trovate ai link sottostanti.
Fonte: habr.com
