L'output testuale dei comandi nella finestra dell'interprete PowerShell è semplicemente un modo per visualizzare le informazioni in una forma comprensibile per gli esseri umani. In realtà, l'ambiente per lavorare con gli oggetti: i cmdlet e le funzioni ricevono questi oggetti in input e , mentre i tipi di variabili disponibili in modalità interattiva e negli script si basano sulle classi .NET. Nel quarto articolo della serie, approfondiremo il lavoro con gli oggetti in modo più dettagliato.
Contenuto:
Oggetti in PowerShell
Ricordiamo che un oggetto è un insieme di campi dati (proprietà, eventi, ecc.) e metodi per il loro trattamento. La sua struttura è determinata dal tipo, che di solito si basa sulle classi utilizzate nella piattaforma unificata .NET Core. Esiste anche la possibilità di lavorare con oggetti COM, CIM (WMI) e ADSI. Le proprietà e i metodi sono necessari per eseguire varie azioni sui dati, inoltre in PowerShell gli oggetti possono essere passati come argomenti a funzioni e cmdlet, assegnando i loro valori a variabili; esiste anche (pipeline). Ogni comando nella pipeline passa il suo output al successivo, uno dopo l'altro — oggetto dopo oggetto. Per l'elaborazione, si possono utilizzare cmdlet compilati o creare proprie , per eseguire diverse manipolazioni con gli oggetti nella pipeline: filtraggio, ordinamento, raggruppamento e persino modifica della loro struttura. La trasmissione dei dati in questo modo ha un notevole vantaggio: il comando ricevente non deve occuparsi del parsing del flusso di byte (testo), tutte le informazioni necessarie possono essere facilmente estratte accedendo alle relative proprietà e metodi.
Visualizzazione della struttura degli oggetti
Ad esempio, eseguiamo il cmdlet Get-Process, che consente di ottenere informazioni sui processi attivi nel sistema:

Esso visualizzerà a schermo alcuni dati testuali formattati, che non forniscono un'idea delle proprietà degli oggetti restituiti e dei loro metodi. Per analizzare finemente l'output, è necessario imparare a esplorare la struttura degli oggetti e in questo ci aiuterà il cmdlet Get-Member:
Get-Process | Get-Member 
Qui vediamo già il tipo e la struttura, e con l'aiuto di parametri aggiuntivi possiamo, ad esempio, visualizzare solo le proprietà dell'oggetto passato in ingresso:
Get-Process | Get-Member -MemberType PropertyQueste conoscenze saranno utili per risolvere compiti di amministrazione in modalità interattiva o per scrivere i propri script: ad esempio, per ottenere informazioni sui processi bloccati tramite la proprietà Responding.
Filtraggio degli oggetti
PowerShell consente di passare attraverso la pipeline oggetti che soddisfano una certa condizione:
Where-Object { blocco di script }Il risultato dell'esecuzione del blocco di script tra le parentesi graffe deve essere un valore booleano. Se è vero ($true), l'oggetto passato al cmdlet Where-Object verrà passato ulteriormente nella pipeline, altrimenti (valore $false) verrà rimosso. Ad esempio, visualizziamo l'elenco dei servizi di Windows Server arrestati, ovvero quelli il cui stato ha valore «Stopped»:
Get-Service | Where-Object {$_.Status -eq "Stopped"} 
Qui vediamo di nuovo una rappresentazione testuale, ma se si desidera è facile comprendere il tipo e la struttura interna degli oggetti che passano attraverso la pipeline:
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member 
Ordinamento degli oggetti
Durante l'elaborazione degli oggetti nella pipeline sorge spesso la necessità di ordinarli. Al cmdlet Sort-Object vengono passati i nomi delle proprietà (chiavi di ordinamento), e restituirà oggetti ordinati in base ai loro valori. Non è difficile ordinare l'output dei processi in esecuzione in base al tempo di CPU utilizzato (proprietà cpu):
Get-Process | Sort-Object –Property cpuIl parametro -Property nella chiamata al cmdlet Sort-Object può anche non essere specificato: viene utilizzato per impostazione predefinita. Per un 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 della pipeline utilizzando i parametri -First o -Last. Consente di selezionare singoli oggetti o proprietà specifiche, nonché di creare nuovi oggetti basati su di essi. Analizziamo il funzionamento del cmdlet con semplici esempi.
Il comando successivo restituisce informazioni su 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 determinate proprietà degli oggetti che passano attraverso la pipeline e creare nuovi oggetti basati su di esse:
Get-Process | Select-Object ProcessName, Id -First 1Il risultato del lavoro del conveyaore sarà un nuovo oggetto, la cui struttura sarà diversa da quella dell'oggetto restituito dal cmdlet Get-Process. Verifichiamo questo con 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 che abbiamo specificato: i loro valori sono stati copiati dal primo oggetto passato al cmdlet Get-Process. Uno dei modi per creare oggetti negli script PowerShell si basa sull'uso di Select-Object:
$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType() 
Con Select-Object è possibile aggiungere proprietà calcolate agli oggetti, che devono essere presentate sotto forma di . In questo caso, il valore della sua prima chiave corrisponde al nome della proprietà, mentre il valore della seconda è il valore della proprietà per l'elemento corrente del conveyoare:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} 
Vediamo la struttura degli oggetti che passano attraverso il conveyoare:
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. Per esempio, parleremo di tre dei più utili:
ForEach-Object permette di eseguire codice in PowerShell per ogni oggetto nel conveyoare:
ForEach-Object { blocco dello script }Group-Object raggruppa gli oggetti in base al valore della proprietà:
Group-Object PropertyNameSe eseguito con il parametro -NoElement, è possibile conoscere il numero di elementi nei gruppi.
Measure-Object aggregando vari parametri riassuntivi basati sui valori dei campi degli oggetti nel conveyoare (calcola la somma, oltre a trovare 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 tende a creare con i blocchi Begin, Process ed End.
Creazione di oggetti .NET e COM (New-Object)
Ci sono molti componenti software con interfacce .NET Core e COM che possono essere utili agli amministratori di sistema. Con la classe System.Diagnostics.EventLog è possibile gestire i registri di sistema direttamente da Windows PowerShell. Esaminiamo un esempio di creazione di un'istanza di questa classe usando il cmdlet New-Object con il parametro -TypeName:
New-Object -TypeName System.Diagnostics.EventLog 
Poiché non abbiamo specificato un determinato registro eventi, l'istanza della classe ottenuta non contiene dati. Per modificare questo comportamento, è necessario chiamare un metodo costruttore speciale al momento della sua creazione utilizzando 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 
Nota: abbiamo salvato l'output del comando nella variabile $AppLog. Anche se nel modo interattivo si utilizzano solitamente pipeline, nella scrittura di script è spesso necessario mantenere un riferimento all'oggetto. Inoltre, le classi principali di .NET Core si trovano nello spazio dei nomi System: PowerShell cerca per default i tipi specificati al suo interno, quindi è assolutamente 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 viene svuotato tramite il metodo Clear() se si dispone dei diritti necessari:
$AppLog.Clear()Il cmdlet New-Object è utilizzato anche per lavorare con i componenti COM. Ce ne sono molti — dalle librerie di script fornite con il server alle applicazioni ActiveX, come ad esempio Internet Explorer. Per creare un oggetto COM, è necessario specificare il parametro -ComObject con l'identificatore del programma 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 una struttura qualsiasi, l'uso di New-Object appare obsolete e ingombrante; questo cmdlet è utilizzato per lavorare con componenti software esterni rispetto a PowerShell. Negli articoli successivi, questo argomento sarà trattato in modo più dettagliato. Oltre agli oggetti .NET e COM, studieremo anche gli oggetti CIM (WMI) e ADSI.
Chiamata di metodi statici
Non è possibile creare istanze di alcune classi di .NET Core: tra queste ci sono System.Environment e System.Math. Sono e contengono solo proprietà e metodi statici. In sostanza, si tratta di librerie di riferimento, che vengono utilizzate senza la creazione di oggetti. È possibile fare riferimento a una classe statica attraverso un letterale, racchiudendo il nome del tipo tra parentesi quadre. Di conseguenza, se guardiamo alla struttura dell'oggetto utilizzando Get-Member, vedremo il tipo System.RuntimeType invece di System.Environment:
[System.Environment] | Get-Member 
Per visualizzare solo gli elementi statici, è necessario richiamare Get-Member con il parametro -Static (prestare attenzione al tipo di oggetto):
[System.Environment] | Get-Member -Static 
Per accedere a proprietà e metodi statici si utilizzano due punti consecutivi invece del 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, creato per memorizzare oggetti con una struttura arbitraria. Creare un tale oggetto utilizzando il cmdlet New-Object è considerato un metodo classico, ma ingombrante e obsoleto:
$object = New-Object –TypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Mosca';
Country = 'Russia'}
Diamo un'occhiata alla struttura dell'oggetto:
$object | Get-Member 
A partire da PowerShell 3.0 è disponibile anche un'altra sintassi:
$object = [PSCustomObject]@{Name = 'Ivan Danko';
City = 'Mosca';
Country = 'Russia'
}
Si possono 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 di una hash table esistente:
$hash = @{'Name'='Ivan Danko'; 'City'='Mosca'; 'Country'='Russia'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()

Uno dei difetti di questo tipo di oggetti è 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: abbiamo esaminato l'uso del cmdlet . Rimane da capire come aggiungere e rimuovere elementi. Farlo per l'oggetto del precedente esempio è piuttosto semplice:
$object | Add-Member –MemberType NoteProperty –Name Age –Value 33
$object | Get-Member

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

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

Va notato che nella descrizione della classe vengono specificati non solo i tipi di proprietà, ma anche i loro valori predefiniti:
class Example
{
[string]$Name = 'John Doe'
}
La descrizione del metodo di classe ricorda la descrizione di una funzione, ma senza l'uso della parola chiave function. Come per le funzioni, ai metodi possono essere passati parametri se 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 , così come 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 — si realizza così l'ereditarietà. In questo caso, è possibile utilizzare classi esistenti di .NET come classi base:
class MyClass2 : MyClass
{
# corpo della nuova classe che ha MyClass come base
}
[MyClass2]::new().Smile($true)
La nostra descrizione del lavoro con gli oggetti in PowerShell è difficile da definire esaustiva. Nelle pubblicazioni future cercheremo di approfondirla con esempi pratici: il quinto articolo del ciclo sarà dedicato alle questioni di integrazione di PowerShell con componenti software di terze parti. Le parti precedenti possono essere trovate ai link qui sotto.
Fonte: habr.com
