about_Pipelines

Aggiornamento: maggio 2014

Si applica a: Windows PowerShell 2.0, Windows PowerShell 3.0, Windows PowerShell 4.0, Windows PowerShell 5.0

ARGOMENTO

about_pipelines

DESCRIZIONE BREVE

Combinazione di comandi in pipeline in Windows PowerShell

DESCRIZIONE LUNGA

Una pipeline è una serie di comandi uniti da operatori pipeline (|)(ASCII 124). Ogni operatore pipeline invia i risultati del comando precedente al comando successivo.

È possibile usare le pipeline per inviare gli oggetti restituiti da un comando in modo che vengano usati come input per un altro comando per l'elaborazione. È anche possibile inviare l'output del comando a un altro comando ancora. Il risultato è una catena di comandi molto potente, o "pipeline", costituita da una serie di comandi semplici.

Ad esempio:

Command-1 | Command-2 | Command-3  

In questo esempio, gli oggetti che Command-1 genera vengono inviati a Command-2. Command-2 elabora gli oggetti e li invia a Command-3. Command-3 elabora gli oggetti e li invia più avanti nella pipeline. Poiché nella pipeline non sono presenti altri comandi, i risultati vengono visualizzati nella console.

In una pipeline, i comandi vengono elaborati da sinistra verso destra nell'ordine in cui vengono visualizzati. L'elaborazione viene gestita come un'unica operazione e l'output viene visualizzato non appena viene generato.

Ecco un semplice esempio. Il comando seguente avvia il processo del Blocco note, quindi lo interrompe.

         get-process notepad | stop-process

Il primo comando usa il cmdlet Get-Process per ottenere un oggetto che rappresenta il processo del Blocco note e usa un operatore pipeline (|) per inviare l'oggetto processo al cmdlet Stop-Process, che interrompe il processo del Blocco note. Si noti che il comando Stop-Process non dispone di un parametro Name o ID per specificare il processo perché il processo specificato viene inviato attraverso la pipeline.

Ecco un esempio pratico. Questa pipeline di comandi ottiene i file di testo nella directory corrente, seleziona solo i file che superano i 10.000 byte, li ordina in base alla 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. Il comando è scritto in senso orizzontale, ma il processo verrà illustrato verticalmente nella figura seguente.

       Get-ChildItem -path *.txt

                  |
                  |   (FileInfo objects )
                  |   (    .txt         )
                  |
                  V                   

       Where-Object {$_.length -gt 10000}

                  |
                  |   (FileInfo objects )
                  |   (    .txt         )
                  |   ( Length > 10000  )
                  |
                  V

       Sort-Object -property Length

                  |
                  |   (FileInfo objects  )
                  |   (    .txt          )
                  |   ( Length > 10000   )
                  |   ( Sorted by length )
                  |
                  V

       Format-Table -property name, length

                  |   
                  |   (FileInfo objects     )
                  |   (    .txt             )
                  |   ( Length > 10000      )
                  |   ( Sorted by length    )
                  |   (Formatted in a table )
                  |
                  V
        Name                       Length
        ----                       ------
        tmp1.txt                    82920
        tmp2.txt                   114000
        tmp3.txt                   114000

UTILIZZO DI PIPELINE

I cmdlet di Windows PowerShell sono stati progettati per essere usati nelle pipeline. Ad esempio, generalmente è possibile inviare i risultati di un cmdlet Get a un cmdlet di azione (ad esempio, un cmdlet Set, Start, Stop o Rename) per lo stesso sostantivo.

Ad esempio, è possibile inviare qualsiasi servizio dal cmdlet Get-Service ai cmdlet Start-Service o Stop-Service (anche se in questo modo non è possibile riavviare i servizi disattivati).

Questa pipeline di comandi avvia il servizio WMI sul computer:

get-service wmi | start-service

Anche i cmdlet per ottenere e impostare oggetti dei provider di Windows PowerShell, ad esempio i cmdlet Item e ItemProperty, sono progettati per essere usati nelle pipeline.

Ad esempio, è possibile inviare i risultati di un comando Get-Item o Get-ChildItem nel provider del Registro di sistema di Windows PowerShell al cmdlet New-ItemProperty. Questo comando aggiunge una nuova voce del Registro di sistema, NoOfEmployees, con il 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 in pipeline. È possibile inviare tramite pipeline quansiasi oggetto a questi cmdlet.

Ad esempio, è possibile inviare tutti i processi nel computer al comando Sort-Object e ordinarli in base al numero di handle nel processo.

get-process | sort-object -property handles

È anche possibile inviare tutti gli oggetti ai cmdlet di formattazione, quali Format-List e Format-Table, ai cmdlet di esportazione, come Export-Clixml e Export-CSV, e ai cmdlet Out, come Out-Printer.

Ad esempio, è possibile inviare il processo Winlogon al cmdlet Format-List per visualizzare tutte le proprietà del processo in un elenco.

get-process winlogon | format-list -property *

Con un po' di pratica, si capirà che la combinazione di semplici comandi in pipeline consente di risparmiare tempo e rende la creazione di script più efficiente.

FUNZIONAMENTO DELLE PIPELINE

Quando si "inviano" oggetti in una pipeline, vale a dire si inviano gli oggetti dell'output di un comando a un altro comando, Windows PowerShell tenta di associare gli oggetti inviati a uno dei parametri del cmdlet ricevente.

A tale scopo, il componente "associazione di parametro" di Windows PowerShell, che associa gli oggetti di input ai parametri dei cmdlet, prova a trovare un parametro che soddisfa i criteri seguenti:

-- Il parametro deve accettare input da una pipeline (non tutti lo fanno)

-- Il parametro deve accettare il tipo di oggetto inviato o un tipo in cui l'oggetto possa essere convertito.

-- Il parametro non deve essere già usato nel comando.

Ad esempio, il cmdlet Start-Service dispone di molti parametri, ma solo due di essi, Name e InputObject, accettano input della pipeline. Il parametro Name accetta stringhe e il parametro InputObject oggetti servizio. Pertanto, è possibile inviare stringhe e oggetti servizio (e oggetti con proprietà che possono essere convertite in oggetti stringa e servizio) a Start-Service.

Se il componente di associazione di parametro di Windows PowerShell non può associare gli oggetti inviati a un parametro del cmdlet ricevente, il comando non riesce e Windows PowerShell chiede i valori del parametro mancante.

Non è possibile forzare il componente di associazione di parametro ad associare gli oggetti inviati a un determinato parametro e non è neanche possibile suggerire un parametro. Al contrario, la logica del componente gestisce l'invio nel modo più efficiente possibile.

ELABORAZIONE UNO ALLA VOLTA

Inviare oggetti a un comando in una pipeline è un'operazione molto simile all'uso di un parametro del comando per inviare gli oggetti.

Ad esempio, l'invio di oggetti che rappresentano i servizi nel computer a un comando Format-Table, quale:

  get-service | format-table -property name, dependentservices

è molto simile al salvataggio di oggetti servizio in una variabile e all'utilizzo del parametro InputObject di Format-Table per inviare l'oggetto servizio.

  $services = get-service
                  format-table -inputobject $services -property name, dependentservices

o all'incorporamento del comando nel valore del parametro

                  format-table -inputobject (get-service wmi) -property name, dependentservices

Tuttavia, esiste una differenza importante. Quando si usa la pipeline per inviare più oggetti a un comando, Windows PowerShell invia gli oggetti al comando uno alla volta. Quando si usa un parametro di comando, gli oggetti vengono inviati come un singolo oggetto matrice.

Questa differenza apparentemente tecnica può avere conseguenze interessanti e in alcuni casi utili.

Ad esempio, se si inviano più oggetti processo dal cmdlet Get-Process al cmdlet Get-Member, Windows PowerShell invia ogni oggetto processo, uno alla volta, a Get-Member. Get-Member visualizza la classe .NET (tipo) degli oggetti processo e relativi metodi e proprietà (Get-Member elimina i duplicati, pertanto se gli oggetti sono tutti dello stesso tipo, viene visualizzato un solo tipo di oggetto).

In questo caso, Get-Member visualizza le proprietà e i metodi di ogni oggetto processo, ovvero un oggetto System.Diagnostics.Process.

                 get-process | get-member

                    TypeName: System.Diagnostics.Process

                 Name                           MemberType     Definition
                 ----                           ----------     ----------
                 Handles                        AliasProperty  Handles = Handlecount
                 Name                           AliasProperty  Name = ProcessName
                 NPM                            AliasProperty  NPM = NonpagedSystemMemorySize
                 ...

Tuttavia, se si usa il parametro InputObject di Get-Member, Get-Member riceve una matrice di oggetti System.Diagnostics.Process come singola unità e visualizza le proprietà di una matrice di oggetti (si noti il simbolo della matrice ([]) dopo il nome del tipo System.Object).

                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 desiderato, ma dopo averlo compreso è possibile usarlo. Ad esempio, una matrice di oggetti processo ha una proprietà Count che può essere usata per contare il numero di processi nel computer.

(get-process).count

Questa distinzione può essere importante, pertanto tenere presente che quando si inviano oggetti a un cmdlet in una pipeline, questi vengano recapitati uno alla volta.

ACCETTA L'INPUT DELLA PIPELINE

Per ricevere gli oggetti in una pipeline, il cmdlet ricevente deve avere un parametro che accetta l'input della pipeline. È possibile usare un comando Get-Help con i parametri Full o Parameter per determinare quale parametro del cmdlet, se esiste, accetta l'input della pipeline.

Nella visualizzazione predefinita Get-Help, l'elemento "Accetta l'input della pipeline" viene visualizzato in una tabella di attributi dei parametri. Questa tabella viene visualizzata solo quando si usano i parametri Full or Parameter del cmdlet Get-Help.

Ad esempio, per determinare quale parametro del cmdlet Start-Service accetta l'input della pipeline, digitare:

        get-help start-service -full

        get-help start-service -parameter *

Ad esempio, la Guida per il cmdlet Start-Service mostra che i parametri Name e InputObject accettano l'input della pipeline ("true"). Tutti gli altri parametri presentano un valore "false" nella riga "Accetta l'input della pipeline?".

        -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?                    1
           Default value
      -->  Accept pipeline input?       true (ByValue, ByPropertyName)
           Accept wildcard characters?  true

        -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?                    false
           Position?                    named
           Default value
      -->  Accept pipeline input?       true (ByValue)
           Accept wildcard characters?  false

Ciò significa che è possibile inviare oggetti (PsObjects) attraverso la pipeline al cmdlet Where-Object e Windows PowerShell assocerà l'oggetto al parametro InputObject.

METODI DI ACCETTAZIONE DELL'INPUT DELLA PIPELINE

I parametri dei cmdlet possono accettare l'input della pipeline in uno dei due modi diversi:

-- ByValue: i parametri che accettano l'input "in base al valore" possono accettare oggetti inviati che hanno lo stesso tipo .NET del valore di parametro oppure oggetti che possono essere convertiti in quel tipo.

Ad esempio, il parametro Name di Start-Service accetta l'input della pipeline in base al valore. Può accettare oggetti stringa o oggetti che possono essere convertiti in stringhe.

-- ByPropertyName: i parametri che accettano l'input "in base al nome della proprietà" possono accettare oggetti inviati solo quando una proprietà dell'oggetto ha lo stesso nome del parametro.

Ad esempio, il parametro Name di Start-Service può accettare gli oggetti che hanno una proprietà Name

(per elencare le proprietà di un oggetto, inviarlo a Get-Member).

Alcuni parametri possono accettare oggetti in base al valore o al nome di proprietà. Questi parametri sono progettati per acquisire facilmente l'input dalla pipeline.

ANALISI DEGLI ERRORI DELLA PIPELINE

Se un comando ha esito negativo a causa di un errore della pipeline, è possibile analizzare il problema e riscrivere il comando.

Ad esempio, il comando seguente tenta di spostare una voce del Registro di sistema da una chiave del Registro di sistema all'altra usando il cmdlet Get-Item per ottenere il percorso di destinazione e quindi inviando il percorso al cmdlet Move-ItemProperty.

Nello specifico, il comando usa il cmdlet Get-Item per ottenere il percorso di destinazione. Usa un operatore pipeline per inviare il risultato al cmdlet Move-ItemProperty. Il comando Move-ItemProperty 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 Windows PowerShell visualizza il messaggio di errore seguente:

         Move-ItemProperty : The input object cannot be bound to any parameters for the
         command either because the command does not 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 product

Per analizzare il problema, usae il cmdlet Trace-Command per monitorare il componente di associazione di parametro di Windows PowerShell. Il comando seguente analizza il componente di associazione di parametro durante l'elaborazione del comando. Questo componente usa il parametro -pshost per visualizzare i risultati nella console e il comando -filepath per inviarli al file debug.txt per riferimento futuro.

         trace-command -name parameterbinding -expression {get-item -path hklm:\software\mycompany\sales |
             move-itemproperty -path hklm:\software\mycompany\design -name product} -pshost -filepath debug.txt

I risultati della traccia sono piuttosto lunghi, ma mostrano i valori associati al cmdlet Get-Item, quindi i valori denominati associati al cmdlet Move-ItemProperty.

       ... 
        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
        ... 

Per esaminare il problema, utilizzare il cmdlet Get-Help per visualizzare gli attributi del parametro Destination. Il comando seguente ottiene informazioni dettagliate sul parametro Destination.

get-help move-itemproperty -parameter destination

I risultati mostrano che Destination accetta l'input della pipeline solo "per nome proprietà". In altre parole, l'oggetto inviato deve avere una proprietà denominata Destination.

        -destination <string>
            Specifies the path to the destination location.

            Required?                    true
            Position?                    2
            Default value
            Accept pipeline input?       true (ByPropertyName)
            Accept wildcard characters?  true    

Per visualizzare le proprietà dell'oggetto inviato al cmdlet Move-ItemProperty, inviarlo al cmdlet Get-Member. Il comando seguente invia i risultati della prima parte del comando al cmdlet Get-Member.

          get-item -path hklm:\software\mycompany\sales | get-member

L'output mostra che l'elemento è un Microsoft.Win32.RegistryKey che non dispone di una proprietà Destination. Ciò spiega perché il comando ha avuto esito negativo.

Per correggere il comando, è necessario specificare la destinazione nel cmdlet Move-ItemProperty. È possibile usare un comando Get-ItemProperty per ottenere il percorso, ma è necessario specificare il nome e la destinazione nella parte del comando Move-ItemProperty.

         get-item -path hklm:\software\mycompany\design | 
             move-itemproperty -dest hklm:\software\mycompany\design -name product    

Per verificare se il comando ha funzionato, usare un comando Get-ItemProperty:

get-itemproperty hklm:\software\mycompany\sales

I risultati mostrano che la voce del Registro di sistema del prodotto è stata spostata alla chiave Vendite.

        PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\mycompany\sales
        PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\mycompany
        PSChildName  : sales
        PSDrive      : HKLM
        PSProvider   : Microsoft.PowerShell.Core\Registry
        Product      : 18

VEDERE ANCHE

about_objects

about_parameters

about_command_syntax

about_foreach