about_Pipelines
Descrizione breve
Combinazione di comandi in pipeline in PowerShell
Descrizione lunga
Una pipeline è una serie di comandi connessi dagli operatori pipeline () (|
ASCII 124). Ogni operatore della pipeline invia i risultati del comando precedente al comando successivo.
L'output del primo comando può essere inviato per l'elaborazione come input al secondo comando. E l'output può essere inviato a un altro comando. Il risultato è una catena di comandi o una pipeline complessa costituita da una serie di semplici comandi.
ad esempio:
Command-1 | Command-2 | Command-3
In questo esempio gli oggetti che Command-1
emettono vengono inviati a Command-2
.
Command-2
elabora gli oggetti e li invia a Command-3
. Command-3
elabora gli oggetti e li invia verso il basso nella pipeline. Poiché nella pipeline non sono presenti altri comandi, i risultati vengono visualizzati nella console.
In una pipeline i comandi vengono elaborati in ordine da sinistra a destra. L'elaborazione viene gestita come singola operazione e l'output viene visualizzato come generato.
Ecco un semplice esempio. Il comando seguente ottiene il processo blocco note e quindi lo arresta.
ad esempio:
Get-Process notepad | Stop-Process
Il primo comando usa il Get-Process
cmdlet per ottenere un oggetto che rappresenta il processo del Blocco note. Usa un operatore pipeline (|
) per inviare l'oggetto processo al Stop-Process
cmdlet , che arresta il processo del Blocco note. Si noti che il Stop-Process
comando non dispone di un parametro Name o ID per specificare il processo, perché il processo specificato viene inviato tramite la pipeline.
Questo esempio di pipeline ottiene i file di testo nella directory corrente, seleziona solo i file di lunghezza superiore a 10.000 byte, li ordina per lunghezza e visualizza il nome e la lunghezza di ogni file in una tabella.
Get-ChildItem -Path *.txt |
Where-Object {$_.length -gt 10000} |
Sort-Object -Property length |
Format-Table -Property name, length
Questa pipeline è costituita da quattro comandi nell'ordine specificato. La figura seguente mostra l'output di ogni comando quando viene passato al comando successivo nella pipeline.
Get-ChildItem -Path *.txt
| (FileInfo objects for *.txt)
V
Where-Object {$_.length -gt 10000}
| (FileInfo objects for *.txt)
| ( Length > 10000 )
V
Sort-Object -Property Length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
V
Format-Table -Property name, length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
| ( Formatted in a table )
V
Name Length
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
Uso delle pipeline
La maggior parte dei cmdlet di PowerShell è progettata per supportare le pipeline. Nella maggior parte dei casi, è possibile inviare tramite pipe i risultati di un cmdlet Get a un altro cmdlet dello stesso sostantivo.
Ad esempio, è possibile inviare tramite pipe l'output del Get-Service
cmdlet ai Start-Service
cmdlet o Stop-Service
.
Questa pipeline di esempio avvia il servizio WMI nel computer:
Get-Service wmi | Start-Service
Per un altro esempio, è possibile inviare tramite pipe l'output di Get-Item
o Get-ChildItem
all'interno del provider del Registro di sistema di PowerShell al New-ItemProperty
cmdlet . In questo esempio viene aggiunta una nuova voce del Registro di sistema, NoOfEmployees, con valore 8124, alla chiave del Registro di sistema MyCompany .
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
Molti dei cmdlet di utilità, ad esempio Get-Member
, Where-Object
, Sort-Object
Group-Object
, e Measure-Object
vengono usati quasi esclusivamente nelle pipeline. È possibile inviare tramite pipe qualsiasi tipo di oggetto a questi cmdlet. In questo esempio viene illustrato come ordinare tutti i processi nel computer in base al numero di handle aperti in ogni processo.
Get-Process | Sort-Object -Property handles
È possibile inviare tramite pipe gli oggetti ai cmdlet di formattazione, esportazione e output, ad esempio Format-List
, Format-Table
Export-Clixml
, Export-CSV
, e Out-File
.
In questo esempio viene illustrato come utilizzare il Format-List
cmdlet per visualizzare un elenco di proprietà per un oggetto processo.
Get-Process winlogon | Format-List -Property *
È anche possibile inviare tramite pipe l'output dei comandi nativi ai cmdlet di PowerShell. Ad esempio:
PS> ipconfig.exe | Select-String -Pattern 'IPv4'
IPv4 Address. . . . . . . . . . . : 172.24.80.1
IPv4 Address. . . . . . . . . . . : 192.168.1.45
IPv4 Address. . . . . . . . . . . : 100.64.108.37
Importante
I flussi success e Error sono simili ai flussi stdin e stderr di altre shell. Tuttavia, stdin non è connesso alla pipeline di PowerShell per l'input. Per altre informazioni, vedere about_Redirection.
Con un po' di pratica, si noterà che la combinazione di semplici comandi nelle pipeline consente di risparmiare tempo e digitazione e rende più efficiente lo scripting.
Funzionamento delle pipeline
Questa sezione illustra come gli oggetti di input vengono associati ai parametri del cmdlet ed elaborati durante l'esecuzione della pipeline.
Accetta l'input della pipeline
Per supportare la pipelining, il cmdlet ricevente deve avere un parametro che accetta l'input della pipeline. Usare il Get-Help
comando con le opzioni Full o Parameter per determinare quali parametri di un cmdlet accettano l'input della pipeline.
Ad esempio, per determinare quale dei parametri del cmdlet accetta l'input della Start-Service
pipeline, digitare:
Get-Help Start-Service -Full
or
Get-Help Start-Service -Parameter *
La Guida per il Start-Service
cmdlet mostra che solo i parametri InputObject e Name accettano l'input della pipeline.
-InputObject <ServiceController[]>
Specifies ServiceController objects representing the services to be started.
Enter a variable that contains the objects, or type a command or expression
that gets the objects.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByValue)
Accept wildcard characters? false
-Name <String[]>
Specifies the service names for the service to be started.
The parameter name is optional. You can use Name or its alias, ServiceName,
or you can omit the parameter name.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
Quando si inviano oggetti tramite la pipeline a Start-Service
, PowerShell tenta di associare gli oggetti ai parametri InputObject e Name .
Metodi di accettazione dell'input della pipeline
I parametri dei cmdlet possono accettare l'input della pipeline in uno dei due modi diversi:
ByValue: il parametro accetta valori che corrispondono al tipo .NET previsto o che possono essere convertiti in tale tipo.
Ad esempio, il parametro Name di accetta l'input della
Start-Service
pipeline per valore. Può accettare oggetti stringa o oggetti che possono essere convertiti in stringhe.ByPropertyName: il parametro accetta input solo quando l'oggetto di input ha una proprietà con lo stesso nome del parametro.
Ad esempio, il parametro Name di
Start-Service
può accettare oggetti con una proprietà Name . Per elencare le proprietà di un oggetto, inviarle tramite pipe aGet-Member
.
Alcuni parametri possono accettare oggetti in base al valore o al nome della proprietà, semplificando l'input dalla pipeline.
Binding di parametri
Quando si invia tramite pipe oggetti da un comando a un altro comando, PowerShell tenta di associare gli oggetti inviati tramite pipe a un parametro del cmdlet ricevente.
Il componente di associazione dei parametri di PowerShell associa gli oggetti di input ai parametri del cmdlet in base ai criteri seguenti:
- Il parametro deve accettare l'input da una pipeline.
- Il parametro deve accettare il tipo di oggetto inviato o un tipo che può essere convertito nel tipo previsto.
- Il parametro non è stato usato nel comando .
Ad esempio, il Start-Service
cmdlet ha molti parametri, ma solo due di essi, Name e InputObject accettano l'input della pipeline. Il parametro Name accetta stringhe e il parametro InputObject accetta oggetti servizio. È pertanto possibile inviare tramite pipe stringhe, oggetti servizio e oggetti con proprietà che possono essere convertite in oggetti stringa o servizio.
PowerShell gestisce l'associazione di parametri nel modo più efficiente possibile. Non è possibile suggerire o forzare l'associazione di PowerShell a un parametro specifico. Il comando ha esito negativo se PowerShell non è in grado di associare gli oggetti inviati tramite pipe.
Per altre informazioni sulla risoluzione degli errori di associazione, vedere Analisi degli errori della pipeline più avanti in questo articolo.
Elaborazione una alla volta
Il piping di oggetti a un comando è molto simile all'uso di un parametro del comando per inviare gli oggetti. Di seguito viene illustrato un esempio di pipeline. In questo esempio viene usata una pipeline per visualizzare una tabella di oggetti servizio.
Get-Service | Format-Table -Property Name, DependentServices
A livello funzionale, è simile all'uso del parametro InputObject di Format-Table
per inviare la raccolta di oggetti.
Ad esempio, è possibile salvare la raccolta di servizi in una variabile passata usando il parametro InputObject .
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
In alternativa, è possibile incorporare il comando nel parametro InputObject .
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
Tuttavia, c'è una differenza importante. Quando si inviano tramite pipe più oggetti a un comando, PowerShell invia gli oggetti al comando uno alla volta. Quando si usa un parametro di comando, gli oggetti vengono inviati come singolo oggetto matrice. Questa differenza secondaria ha conseguenze significative.
Quando si esegue una pipeline, PowerShell enumera automaticamente qualsiasi tipo che implementa l'interfaccia o la IEnumerable
controparte generica. Gli elementi enumerati vengono inviati tramite la pipeline uno alla volta. PowerShell enumera anche i tipi System.Data.DataTable tramite la Rows
proprietà .
Esistono alcune eccezioni all'enumerazione automatica.
- È necessario chiamare il
GetEnumerator()
metodo per tabelle hash, tipi che implementano l'interfaccia o laIDictionary
controparte generica e i tipi System.Xml.XmlNode . - La classe System.String implementa
IEnumerable
, tuttavia PowerShell non enumera gli oggetti stringa.
Negli esempi seguenti, una matrice e una tabella hash vengono inoltrate tramite pipe al Measure-Object
cmdlet per contare il numero di oggetti ricevuti dalla pipeline. La matrice ha più membri e la tabella hash ha più coppie chiave-valore. Solo la matrice viene enumerata una alla volta.
@(1,2,3) | Measure-Object
Count : 3
Average :
Sum :
Maximum :
Minimum :
Property :
@{"One"=1;"Two"=2} | Measure-Object
Count : 1
Average :
Sum :
Maximum :
Minimum :
Property :
Analogamente, se si inviano tramite pipe più oggetti di processo dal Get-Process
cmdlet al Get-Member
cmdlet, PowerShell invia a ogni oggetto processo, uno alla volta, a Get-Member
. Get-Member
visualizza la classe .NET (tipo) degli oggetti processo e le relative proprietà e metodi.
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
Nota
Get-Member
elimina i duplicati, quindi se gli oggetti sono tutti dello stesso tipo, visualizza solo un tipo di oggetto.
Tuttavia, se si usa il parametro InputObject di Get-Member
, Get-Member
riceve una matrice di oggetti System.Diagnostics.Process come singola unità. Visualizza le proprietà di una matrice di oggetti. Si noti il simbolo della matrice ([]
) dopo il nome del tipo System.Object .
ad esempio:
Get-Member -InputObject (Get-Process)
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object& Address(Int32 )
Clone Method System.Object Clone()
...
Questo risultato potrebbe non essere quello previsto. Ma dopo averlo compreso, è possibile usarlo. Ad esempio, tutti gli oggetti matrice hanno una proprietà Count . È possibile usarlo per contare il numero di processi in esecuzione nel computer.
ad esempio:
(Get-Process).count
È importante ricordare che gli oggetti inviati alla pipeline vengono recapitati uno alla volta.
Uso di comandi nativi nella pipeline
PowerShell consente di includere comandi esterni nativi nella pipeline. Tuttavia, è importante notare che la pipeline di PowerShell è orientata agli oggetti e non supporta i dati di byte non elaborati.
Il piping o il reindirizzamento dell'output da un programma nativo che restituisce dati di byte non elaborati converte l'output in stringhe .NET. Questa conversione può causare il danneggiamento dell'output dei dati non elaborati.
Tuttavia, PowerShell 7.4 ha aggiunto la PSNativeCommandPreserveBytePipe
funzionalità sperimentale che mantiene i dati del flusso di byte quando si reindirizza il flusso stdout di un comando nativo a un file o quando si esegue il piping dei dati del flusso di byte al flusso stdin di un comando nativo.
Ad esempio, usando il comando curl
nativo è possibile scaricare un file binario e salvarlo su disco usando il reindirizzamento.
$uri = 'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-7.3.4-linux-arm64.tar.gz'
# native command redirected to a file
curl -s -L $uri > powershell.tar.gz
È anche possibile inviare tramite pipe i dati del flusso di byte al flusso stdin di un altro comando nativo. Nell'esempio seguente viene scaricato un file TAR compresso usando curl
. I dati dei file scaricati vengono trasmessi al tar
comando per estrarre il contenuto dell'archivio.
# native command output piped to a native command
curl -s -L $uri | tar -xzvf - -C .
È anche possibile inviare tramite pipe l'output del flusso di byte di un comando di PowerShell all'input del comando nativo. Gli esempi seguenti usano Invoke-WebRequest
per scaricare lo stesso file TAR dell'esempio precedente.
# byte stream piped to a native command
(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
# bytes piped to a native command (all at once as byte[])
,(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
Questa funzionalità non supporta i dati del flusso di byte durante il reindirizzamento dell'output stderr a stdout. Quando si combinano i flussi stderr e stdout , i flussi combinati vengono considerati come dati stringa.
Analisi degli errori della pipeline
Quando PowerShell non è in grado di associare gli oggetti inviati tramite pipe a un parametro del cmdlet ricevente, il comando ha esito negativo.
Nell'esempio seguente si tenta di spostare una voce del Registro di sistema da una chiave del Registro di sistema a un'altra. Il Get-Item
cmdlet ottiene il percorso di destinazione, che viene quindi inviato tramite pipe al Move-ItemProperty
cmdlet . Il Move-ItemProperty
comando specifica il percorso corrente e il nome della voce del Registro di sistema da spostare.
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
Il comando ha esito negativo e PowerShell visualizza il messaggio di errore seguente:
Move-ItemProperty : The input object can't be bound to any parameters for
the command either because the command doesn't take pipeline input or the
input and its properties do not match any of the parameters that take
pipeline input.
At line:1 char:23
+ $a | Move-ItemProperty <<<< -Path HKLM:\Software\MyCompany\design -Name p
Per analizzare, usare il Trace-Command
cmdlet per tracciare il componente di associazione dei parametri di PowerShell. Nell'esempio seguente viene tracciata l'associazione di parametri durante l'esecuzione della pipeline. Il parametro PSHost visualizza i risultati della traccia nella console e il parametro FilePath invia i risultati della traccia al debug.txt
file per riferimento successivo.
Trace-Command -Name ParameterBinding -PSHost -FilePath debug.txt -Expression {
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
}
I risultati della traccia sono lunghi, ma mostrano i valori associati al Get-Item
cmdlet e quindi i valori denominati associati al Move-ItemProperty
cmdlet.
...
BIND NAMED cmd line args [`Move-ItemProperty`]
BIND arg [HKLM:\Software\MyCompany\design] to parameter [Path]
...
BIND arg [product] to parameter [Name]
...
BIND POSITIONAL cmd line args [`Move-ItemProperty`]
...
Infine, mostra che il tentativo di associare il percorso al parametro Destination di Move-ItemProperty
non è riuscito.
...
BIND PIPELINE object to parameters: [`Move-ItemProperty`]
PIPELINE object TYPE = [Microsoft.Win32.RegistryKey]
RESTORING pipeline parameter's original values
Parameter [Destination] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO
COERCION
...
Usare il Get-Help
cmdlet per visualizzare gli attributi del parametro Destination .
Get-Help Move-ItemProperty -Parameter Destination
-Destination <String>
Specifies the path to the destination location.
Required? true
Position? 1
Default value None
Accept pipeline input? True (ByPropertyName)
Accept wildcard characters? false
I risultati mostrano che Destination accetta l'input della pipeline solo "in base al nome della proprietà". Pertanto, l'oggetto inviato tramite pipe deve avere una proprietà denominata Destination.
Usare Get-Member
per visualizzare le proprietà dell'oggetto proveniente da Get-Item
.
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
L'output mostra che l'elemento è un oggetto Microsoft.Win32.RegistryKey che non ha una proprietà Destination . Questo spiega perché il comando non è riuscito.
Il parametro Path accetta l'input della pipeline in base al nome o al valore.
Get-Help Move-ItemProperty -Parameter Path
-Path <String[]>
Specifies the path to the current location of the property. Wildcard
characters are permitted.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? true
Per correggere il comando, è necessario specificare la destinazione nel Move-ItemProperty
cmdlet e usare Get-Item
per ottenere il percorso dell'elemento da spostare.
ad esempio:
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
Continuazione linea intrinseca
Come già illustrato, una pipeline è una serie di comandi connessi dagli operatori della pipeline (|
), in genere scritti su una singola riga. Tuttavia, per la leggibilità, PowerShell consente di suddividere la pipeline tra più righe. Quando un operatore pipe è l'ultimo token nella riga, il parser di PowerShell unisce la riga successiva al comando corrente per continuare la costruzione della pipeline.
Ad esempio, la pipeline a riga singola seguente:
Command-1 | Command-2 | Command-3
può essere scritto come:
Command-1 |
Command-2 |
Command-3
Gli spazi iniziali sulle righe successive non sono significativi. Il rientro migliora la leggibilità.
PowerShell 7 aggiunge il supporto per la continuazione delle pipeline con il carattere della pipeline all'inizio di una riga. Negli esempi seguenti viene illustrato come usare questa nuova funzionalità.
# Wrapping with a pipe at the beginning of a line (no backtick required)
Get-Process | Where-Object CPU | Where-Object Path
| Get-Item | Where-Object FullName -match "AppData"
| Sort-Object FullName -Unique
# Wrapping with a pipe on a line by itself
Get-Process | Where-Object CPU | Where-Object Path
|
Get-Item | Where-Object FullName -match "AppData"
|
Sort-Object FullName -Unique
Importante
Quando si lavora in modo interattivo nella shell, incollando il codice con le pipeline all'inizio di una riga solo quando si usa CTRL+V per incollare. Fare clic con il pulsante destro del mouse sulle operazioni incolla per inserire le righe una alla volta. Poiché la riga non termina con un carattere di pipeline, PowerShell considera l'input completo ed esegue tale riga come immesso.