Il pipeline di PowerShell è una delle caratteristiche più importanti (e utili) della shell e del linguaggio di scripting di PowerShell. Una volta comprese le basi di come funziona e di cosa è capace, puoi sfruttarne la potenza nelle tue funzioni personali. In questo tutorial, è esattamente ciò che farai!
Il pipeline di PowerShell ti consente di concatenare comandi per creare un singolo ‘pipeline’ che semplifica il codice, consente l’elaborazione parallela e altro ancora. Se sei pronto a imparare sul pipeline e a creare le tue funzioni per sfruttarlo, cominciamo!
Prerequisiti
Questo post sarà un tutorial con tutte dimostrazioni pratiche. Se vuoi seguirmi, avrai bisogno di PowerShell v3+. Questo tutorial utilizzerà Windows PowerShell v5.1.
Comprensione del PowerShell Pipeline
La maggior parte dei comandi di PowerShell riceve un input tramite un parametro. Il comando riceve un oggetto in input e fa qualcosa con esso al suo interno. Opzionalmente restituisce qualche oggetto tramite l’output.
I comandi in un pipeline agiscono come i corridori umani in una staffetta. Ogni corridore nella staffetta, tranne il primo e l’ultimo, accetta il testimone (oggetti) dal suo predecessore e lo passa al successivo.
Per esempio, il cmdlet Stop-Service
ha un parametro chiamato InputObject
. Questo parametro ti permette di passare un tipo specifico di oggetto a Stop-Service
che rappresenta il servizio di Windows che desideri interrompere.
Per utilizzare il parametro InputObject
, potresti recuperare l’oggetto servizio tramite Get-Service
e poi passare l’oggetto al parametro InputObject
come mostrato di seguito. Questo metodo di fornire input al cmdlet Stop-Service
tramite il parametro InputObject
funziona molto bene e svolge il compito.
Questo metodo di passaggio dell’input al comando Stop-Service
richiede due passaggi distinti. PowerShell deve eseguire prima Get-Service
, salvare l’output in una variabile e poi passare quel valore a Stop-Service
tramite il parametro InputObject
.
Ora, confronta il frammento di codice sopra con il frammento di codice sotto, che fa la stessa cosa. È molto più semplice perché non devi creare una variabile $services
o utilizzare il parametro InputObject
affatto. Invece, PowerShell “sa” che intendi utilizzare il parametro InputObject
. Fa questo tramite un concetto chiamato associazione dei parametri.
Ora hai “concatenato” i comandi insieme con l’operatore |
. Hai creato un pipeline.
Ma, non devi utilizzare solo due comandi per creare una pipeline; puoi concatenarne quanti vuoi (se i parametri del comando lo supportano). Per esempio, il frammento di codice sotto:
- Passa tutti gli oggetti restituiti dal cmdlet
Get-Service
al cmdletWhere-Object
. - Il cmdlet
Where-Object
verifica quindi la proprietàStatus
di ciascun oggetto e restituisce solo quelli con un valore diRunning
. - Successivamente, ogni oggetto viene inviato a
Select-Object
, che restituisce solo le proprietàName
eDisplayName
degli oggetti. - Dato che nessun altro cmdlet accetta gli oggetti restituiti da
Select-Object
, il comando li restituisce direttamente alla console.
I cmdlet
Where-Object
eSelect-Object
comprendono come elaborare l’input della pipeline attraverso un concetto chiamato parameter binding, discusso nella sezione successiva.
Per ulteriori informazioni sulle pipeline, esegui il comando
Get-Help about_pipelines
.
Binding dei parametri della pipeline
A prima vista, la pipeline può sembrare banale. In fondo, sta solo passando oggetti da un comando a un altro. Ma in realtà, la pipeline è molto più complicata. I comandi accettano input solo tramite parametri. La pipeline deve in qualche modo capire quale parametro utilizzare anche quando non lo definisci esplicitamente.
Il compito di stabilire quale parametro utilizzare quando un comando riceve input tramite il pipeline è noto come associazione dei parametri. Per associare con successo un oggetto in arrivo dalla pipeline a un parametro, il/i parametro/i del comando in arrivo deve supportarlo. I parametri del comando supportano l’associazione dei parametri della pipeline in uno dei due modi; ByValue
e/o ByPropertyName
.
ByValue
Il parametro del comando accetta l’intero oggetto in arrivo come valore del parametro. Un parametro ByValue
cerca un oggetto di un tipo specifico negli oggetti in arrivo. Se quel tipo di oggetto è una corrispondenza, PowerShell assume che l’oggetto debba essere associato a quel parametro e lo accetta.
Il cmdlet
Get-ChildItem
ha un parametro chiamatoPath
che accetta un tipo di oggetto stringa e input tramite pipeline tramiteByValue
. Per questo motivo, eseguire qualcosa come'C:\Windows' | Get-ChildItem
restituisce tutti i file nella directory C:\Windows perchéC:\Windows
è una stringa.
ByPropertyName
Il parametro del comando non accetta un intero oggetto ma una singola proprietà di quell’oggetto. Lo fa non guardando il tipo di oggetto ma il nome della proprietà.
Il cmdlet
Get-Process
ha un parametroName
configurato per accettare l’input della pipelineByPropertyName
. Quando si passa un oggetto con una proprietàName
al cmdletGet-Process
come[pscustomobject]@{Name='firefox'} | Get-Process
, PowerShell associa la proprietàName
dell’oggetto in arrivo al parametroName
e utilizza quel valore.
Scoprire i Parametri del Comando che Supportano la Pipeline
Come accennato in precedenza, non tutti i comandi supportano l’input della pipeline. L’autore del comando deve creare tale funzionalità nello sviluppo. Il comando deve avere almeno un parametro che supporta la pipeline, specificare ByValue
o ByPropertyName
.
Come si sa quali comandi e relativi parametri supportano l’input della pipeline? Si potrebbe semplicemente provare con tentativi ed errori, ma c’è un modo migliore con il sistema di aiuto di PowerShell utilizzando il comando Get-Help
.
Ad esempio, dai un’occhiata al parametro Path
del cmdlet Get-ChildItem
qui sotto. Puoi vedere che supporta entrambi i tipi di input della pipeline.

Una volta che sai quali parametri di comando supportano l’input di pipeline, puoi sfruttare quella funzionalità, come mostrato di seguito.
Ma, d’altra parte, il parametro DisplayName
su Get-Service
non supporta l’input di pipeline.

Costruzione della tua funzione di pipeline
Anche se i cmdlet standard di PowerShell supportano l’input di pipeline, non significa che non puoi sfruttare quella funzionalità. Per fortuna, puoi creare anche funzioni che accettano l’input di pipeline.
Per dimostrare, cominciamo con una funzione esistente chiamata Get-ConnectionStatus
.
- Questa funzione ha un singolo parametro (che non accetta input di pipeline) chiamato
ComputerName
, che ti consente di passare uno o più stringhe ad esso. Puoi capire che il parametroComputerName
non accetta input di pipeline perché non è definito come attributo del parametro ([Parameter()]
). - La funzione quindi legge ciascuna di quelle stringhe ed esegue il cmdlet
Test-Connection
contro ognuna di esse. - Per ogni stringa di nome computer passata, restituisce un oggetto con una proprietà
ComputerName
eStatus
.
Successivamente si invoca il comando Get-ConnectionStatus
passando il parametro ComputerName
uno o più nomi host o indirizzi IP come mostrato di seguito.
Passo 1: Consentire l’Input tramite Pipeline
Per consentire a questa funzione di accettare input tramite pipeline, è necessario prima definire l’attributo parametro appropriato. Questo attributo può essere sia ValueFromPipeline
per accettare input di pipeline ByValue o ValueFromPipelineByPropertyName
per accettare input di pipeline ByPropertyName.
Per questo esempio, aggiungere l’attributo parametro ValueFromPipeline
tra le parentesi quadre della definizione [Parameter()]
come mostrato di seguito.
A questo punto, questo è tecnicamente tutto ciò che devi fare. La funzione Get-ConnectionStatus
ora assocerà qualsiasi oggetto stringa passato ad essa al parametro ComputerName
. Ma, anche se si sta verificando l’associazione dei parametri, non significa che la funzione farà qualcosa di significativo con esso.
Passo 2: Aggiungere un Blocco di Processo
Quando si vuole che PowerShell elabori tutti gli oggetti provenienti dalla pipeline, è necessario aggiungere un blocco Process
. Questo blocco indica a PowerShell di elaborare ogni oggetto proveniente dalla pipeline.
Senza un blocco
Process
, PowerShell elaborerà solo il primo oggetto proveniente dalla pipeline. Il bloccoProcess
indica a PowerShell di continuare a elaborare gli oggetti.
italian
Aggiungi un blocco Process
come mostrato di seguito, racchiudendo l’intera funzionalità della funzione.
Invia sempre l’output da all’interno del blocco
Process
. L’invio dell’output da all’interno del bloccoProcess
“streama” gli oggetti nel pipeline, consentendo ad altri comandi di accettare tali oggetti dalla pipeline.
Passaggio di oggetti alla pipeline di PowerShell
Dopo aver definito un blocco Process
nella funzione sopra, puoi chiamare la funzione passando i valori al parametro ComputerName
tramite la pipeline, come mostrato di seguito.
A questo punto, puoi sfruttare la vera potenza della pipeline e iniziare a incorporare più comandi nel mix. Ad esempio, forse hai un file di testo, C:\Test\computers.txt, con una riga di indirizzi IP separati da una nuova riga come segue.
Potresti quindi utilizzare il cmdlet Get-Content
per leggere ciascuno di quegli indirizzi IP nel file di testo e passarli direttamente alla funzione Get-ConnectionStatus
.
Portando questa configurazione un passo oltre, potresti instradare direttamente gli oggetti restituiti da Get-ConnectionStatus
al cmdlet ForEach-Object
.
- Legge tutti i nomi dei computer nel file di testo e li passa alla funzione
Get-ConnectionStatus
. Get-ConnectionStatus
elabora ciascun nome del computer e restituisce un oggetto con le proprietàComputerName
eStatus
.Get-ConnectionStatus
passa quindi ciascun oggetto al cmdletForEach-Object
, che restituisce una singola stringa colorata di ciano con uno stato leggibile dall’utente.
Se l’input tramite pipeline non fosse abilitato per il parametro
ComputerName
o seGet-ConnectionStatus
non restituisse un oggetto all’interno del bloccoProcess
, PowerShell non restituirebbe alcuno stato alla console fino a quando tutti gli oggetti (indirizzi IP) non sono elaborati.
Associazione tramite pipeline per nome della proprietà
Fino a ora, il cmdlet Get-ConnectionStatus
è configurato per accettare l’input tramite pipeline ByValue (ValueFromPipeline
) accettando un array di stringhe come '127.0.0.1', '192.168.1.100'
. Questa funzione funzionerebbe anche correttamente se l’input provenisse da un file CSV invece di un file di testo di indirizzi IP?
Forse hai un file CSV che assomiglia a quanto segue in C:\Test\pc-list.csv.
Nota che il campo
ComputerName
nel file CSV ha lo stesso nome del parametroComputerName
diGet-ConnnectionStatus
.
Se tentassi di importare il CSV e passarlo attraverso la pipeline a Get-ConnectionStatus
, la funzione restituirebbe un risultato inaspettato nella colonna ComputerName
.
Riesci a indovinare cosa è andato storto? Dopotutto, il nome del parametro corrisponde, quindi perché il pipeline di PowerShell non ha vincolato l’output restituito da Import-CSV
al parametro ComputerName
su Get-ConnectionStatus
? Perché è necessario l’attributo del parametro ValueFromPipelineByPropertyName
.
Finora, il parametro ComputerName
della funzione ha una definizione del parametro che assomiglia a [Parameter(ValueFromPipeline)]
. Pertanto, devi aggiungere ValueFromPipelineByPropertyName
per impostare il parametro ComputerName
per supportare l’input ByPropertyName, come mostrato di seguito.
Una volta che hai il supporto del pipeline ByPropertyName, dici a PowerShell di iniziare a guardare i nomi delle proprietà dell’oggetto e il tipo di oggetto. Una volta apportata questa modifica, dovresti quindi vedere l’output previsto.
Riepilogo
In questo tutorial hai imparato come funziona il pipeline di PowerShell, come vincola i parametri e persino come creare la tua funzione che supporta il pipeline di PowerShell.
Anche se le funzioni funzioneranno senza il pipeline, non “streameranno” gli oggetti da un comando all’altro e semplificheranno il codice.
Riesci a pensare a una funzione che hai scritto, o forse stai per scriverne una, che può beneficiare dall’essere pronta per il pipeline?