about_Pipelines

Aplica-se a: Windows PowerShell 2.0, Windows PowerShell 3.0, Windows PowerShell 4.0, Windows PowerShell 5.0

TÓPICO

about_pipelines

DESCRIÇÃO BREVE

Combinando comandos em pipelines no Windows PowerShell

DESCRIÇÃO LONGA

Um pipeline é uma série de comandos conectados por operadores de pipeline (|) (ASCII 124). Cada operador de pipeline envia os resultados do comando anterior para o próximo comando.

Você pode usar pipelines para enviar os objetos que são produzidos por um comando que serão usados como entrada para outro comando para processamento. E você pode enviar a saída do comando para outro comando. O resultado é uma cadeia de comando muito poderosa ou "pipeline" que é composto de uma série de comandos simples.

Por exemplo,

Command-1 | Command-2 | Command-3  

Neste exemplo, os objetos que Command-1 emite são enviados ao Command-2. Command-2 processa os objetos e os envia para o Command-3. Command-3 processa os objetos e envia-os pelo pipeline. Como não há mais comandos no pipeline, os resultados são exibidos no console.

Em um pipeline, os comandos são processados da esquerda para a direita na ordem em que aparecem. O processamento é tratado como uma única operação e a saída é exibida como ela será gerada.

Segue um exemplo simples. O comando a seguir obtém o processo do bloco de notas e, depois, interrompe ele.

         get-process notepad | stop-process

O primeiro comando usa o cmdlet Get-Process para obter um objeto que representa o processo do bloco de notas. Ele usa um operador de pipeline (|) para enviar o objeto de processo para o cmdlet Stop-Process, que interrompe o processo do bloco de notas. Observe que o comando Stop-Process não tem um parâmetro Name ou ID para especificar o processo, porque o processo especificado é enviado por meio do pipeline.

Segue um exemplo prático. Esse pipeline de comando obtém os arquivos de texto no diretório atual, seleciona apenas os arquivos que têm mais de 10.000 bytes, classifica-os por comprimento e exibe o nome e o tamanho de cada arquivo em uma tabela.

        Get-ChildItem -path *.txt | Where-Object {$_.length -gt 10000} | 
        Sort-Object -property Length | Format-Table -property name, length

Esse pipeline é composto por quatro comandos na ordem especificada. O comando é escrito horizontalmente, mas mostraremos o processo verticalmente no gráfico a seguir.

       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

USO DE PIPELINES

Os cmdlets do Windows PowerShell foram projetados para serem usados em pipelines. Por exemplo, geralmente é possível canalizar os resultados de um cmdlet Get para um cmdlet de ação (como um cmdlet Set, Start, Stop ou Rename) para o mesmo substantivo.

Por exemplo, é possível canalizar qualquer serviço do cmdlet Get-Service para os cmdlets Start-Service ou Stop-Service (embora os serviços desabilitados não possam ser reiniciados dessa maneira).

Esse pipeline de comando inicia o serviço WMI no computador:

get-service wmi | start-service

Os cmdlets que obtêm e definem objetos dos provedores Windows PowerShell, como os cmdlets Item e ItemProperty, também são projetados para serem usados em pipelines.

Por exemplo, é possível canalizar os resultados do comando Get-Item ou Get-ChildItem no provedor de Registro Windows PowerShell para o cmdlet New-ItemProperty. Este comando adiciona uma nova entrada de Registro, NoOfEmployees, com um valor de 8124, à chave do Registro MyCompany.

       get-item -path HKLM:\Software\MyCompany | new-Itemproperty -name NoOfEmployees -value 8124

Muitos dos cmdlets do utilitário, como Get-Member, Where-Object, Sort-Object, Group-Object e Measure-Object, são usados quase que exclusivamente em pipelines. É possível canalizar todos os objetos a esses cmdlets.

Por exemplo, você pode canalizar todos os processos no computador para o comando Sort-Object e classificá-los pelo número de identificadores no processo.

get-process | sort-object -property handles

Além disso, é possível canalizar todos os objetos nos cmdlets de formatação, como Format-List e Format-Table, os cmdlets Export, como Export-Clixml e Export-CSV, e os cmdlets de saída, como Out-Printer.

Por exemplo, você pode canalizar o processo Winlogon para o cmdlet Format-List para exibir todas as propriedades do processo em uma lista.

get-process winlogon | format-list -property *

Com um pouco de prática, você verá que esses comandos de combinação simples em pipelines economizam tempo e digitação, e tornam seu script mais eficiente.

COMO FUNCIONAM OS PIPELINES

Quando você "canaliza" objetos, que é enviar os objetos na saída de um comando para outro comando, o Windows PowerShell tenta associar os objetos canalizados com um dos parâmetros do cmdlet de recebimento.

Para fazer isso, o componente "associação de parâmetros" do Windows PowerShell, que associa objetos de entrada com parâmetros de cmdlet, tenta encontrar um parâmetro que atende aos seguintes critérios:

-- O parâmetro deve aceitar a entrada de um pipeline (nem todos fazem)

-- O parâmetro deve aceitar o tipo de objeto que está sendo enviado ou um tipo no qual o objeto possa ser convertido.

-- O parâmetro não pode já ter sido usado no comando.

Por exemplo, o cmdlet Start-Service tem vários parâmetros, mas somente dois deles, Name e InputObject aceitam entrada de pipeline. O parâmetro Name usa cadeias de caracteres e o parâmetro InputObject usa objetos de serviço. Portanto, é possível canalizar cadeias de caracteres e objetos de serviço (e objetos com propriedades que podem ser convertidos em objetos de cadeia de caracteres e de serviço) para Start-Service.

Se o componente de associação de parâmetro do Windows PowerShell não puder associar os objetos conectados a um parâmetro do cmdlet de recebimento, o comando falhará e Windows PowerShell solicitará os valores de parâmetro ausentes.

Não é possível forçar o componente de associação de parâmetro a associar os objetos conectados a um determinado parâmetro. Você nem mesmo não pode sugerir um parâmetro. Em vez disso, a lógica do componente gerencia a canalização do modo mais eficiente possível.

PROCESSAMENTO "UM DE CADA VEZ"

Canalizar objetos a um comando é semelhante a usar um parâmetro do comando para enviar os objetos.

Por exemplo, canalizar objetos que representam os serviços no computador para um comando Format-Table, como:

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

é semelhante a salvar os objetos de serviço em uma variável e usar o parâmetro InputObject do Format-Table para enviar o objeto de serviço.

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

ou como inserir o comando no valor do parâmetro

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

No entanto, há uma diferença importante. Quando você canaliza vários objetos em um comando, o Windows PowerShell envia objetos ao comando um por vez. Quando você usa um parâmetro de comando, os objetos são enviados como um objeto de matriz.

Essa diferença aparentemente técnica pode ter consequências interessantes e, às vezes, útil.

Por exemplo, se você canalizar vários objetos de processo do cmdlet Get-Process para o cmdlet Get-Member, o Windows PowerShell envia cada objeto de processo, um de cada vez, para Get-Member. Get-Member exibe a classe do .NET (tipo) de objetos de processo e suas propriedades e métodos. (Get-Member elimina duplicatas, portanto, se os objetos forem todos do mesmo tipo, ele exibe apenas um tipo de objeto.)

Nesse caso, o Get-Member exibe as propriedades e métodos de cada objeto de processo, ou seja, um objeto 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
                 ...

No entanto, se você usar o parâmetro InputObject de Get-Member, então Get-Member recebe uma matriz de objetos System.Diagnostics.Process como uma única unidade e exibe as propriedades de uma matriz de objetos. (Observe o símbolo de matriz ([]) após o nome do 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()

Esse resultado pode não ser o que você pretendia, mas depois de entendê-lo, você pode usá-lo. Por exemplo, uma matriz de objetos de processo tem uma propriedade Count que você pode usar para contar o número de processos no computador.

(get-process).count

Essa distinção pode ser importante, lembre-se que, ao transferir objetos para um cmdlet, eles são entregues um de cada vez.

ACEITA ENTRADA DO PIPELINE

Para receber os objetos em um pipeline, o cmdlet de recebimento deve ter um parâmetro que aceita entrada do pipeline. Você pode usar um comando Get-Help com os parâmetros Full ou Parameter para determinar quais, se houver, dos parâmetros do cmdlet aceitam entrada do pipeline.

Na exibição padrão Get-Help, o item "Aceita entrada do pipeline" aparece em uma tabela de atributos de parâmetro. Essa tabela é exibida somente quando você usa os parâmetros Full ou Parameter do cmdlet Get-Help.

Por exemplo, para determinar quais dos parâmetros do cmdlet Start-Service aceita entrada do pipeline, digite:

        get-help start-service -full

        get-help start-service -parameter *

Por exemplo, a ajuda para o cmdlet Start-Service mostra que os parâmetros Name e InputObject aceitam entrada do pipeline ("true"). Todos os outros parâmetros têm um valor de "false" na linha "Aceitar entrada do 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

Isso significa que você pode enviar objetos (PsObjects) pelo pipeline para o cmdlet Where-Object e Windows PowerShell associará o objeto com o parâmetro InputObject.

MÉTODOS DE ACEITAÇÃO DE ENTRADA DO PIPELINE

Parâmetros de cmdlets podem aceitar entrada de pipeline de uma das duas maneiras diferentes:

-- ByValue: Parâmetros que aceitam a entrada "por valor" podem aceitar objetos canalizados que têm o mesmo tipo .NET como seu valor de parâmetro ou objetos que podem ser convertidos para esse tipo.

Por exemplo, o parâmetro Name de Start-Service aceita entrada do pipeline por valor. Ele pode aceitar objetos de cadeia de caracteres ou objetos que podem ser convertidos em cadeias de caracteres.

-- ByPropertyName: Parâmetros que aceitam a entrada "pelo nome da propriedade" podem aceitar objetos canalizados somente quando uma propriedade do objeto tiver o mesmo nome que o parâmetro.

Por exemplo, o parâmetro Name de Start-Service pode aceitar objetos que têm uma propriedade Name.

(Para listar as propriedades de um objeto, canalize-o para Get-Member.)

Alguns parâmetros podem aceitar objetos por valor ou por nome de propriedade. Esses parâmetros são projetados para obter entradas do pipeline facilmente.

INVESTIGANDO ERROS DE PIPELINE

Se um comando falhar devido a um erro de pipeline, você pode investigar a falha e reescrever o comando.

Por exemplo, o seguinte comando tenta mover uma entrada de Registro de uma chave do Registro para outra usando o cmdlet Get-Item para obter o caminho de destino e, em seguida, canalizar o caminho para o cmdlet Move-ItemProperty.

Especificamente, o comando usa o cmdlet Get-Item para obter o caminho de destino. Ele usa um operador de pipeline para enviar o resultado para o cmdlet Move-ItemProperty. O comando Move-ItemProperty especifica o caminho atual e o nome da entrada do Registro a ser movida.

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

O comando falhará e Windows PowerShell exibirá a seguinte mensagem de erro:

         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

Para investigar, use o cmdlet Trace-Command para rastrear o componente de associação de parâmetros de Windows PowerShell. O seguinte comando rastreia o componente de associação de parâmetros, enquanto o comando está em processamento. Ele usa o parâmetro -pshost para exibir os resultados no console e o comando -filepath para enviá-los para o arquivo debug.txt para referência posterior.

         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

Os resultados do rastreamento são longos, mas eles mostram os valores que estão sendo associados ao cmdlet Get-Item e, em seguida, os valores nomeados que estão sendo associados ao 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]
        ...

Por fim, ele mostra que a tentativa de associar o caminho para o parâmetro Destination de Move-ItemProperty falhou.

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

Para investigar a falha, use o cmdlet Get-Help para exibir os atributos do parâmetro Destination. O comando a seguir obtém informações detalhadas sobre o parâmetro Destination.

get-help move-itemproperty -parameter destination

Os resultados mostram que Destination recebe entrada de pipeline apenas "pelo nome da propriedade". Ou seja, o objeto canalizado deve ter uma propriedade chamada 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    

Para ver as propriedades do objeto que está sendo canalizado para o cmdlet Move-ItemProperty, canalize-o para o cmdlet Get-Member. O seguinte comando canaliza os resultados da primeira parte do comando para o cmdlet Get-Member.

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

A saída mostra que o item é um Microsoft.Win32.RegistryKey que não tem uma propriedade Destination. Isso explica por que o comando falhou.

Para corrigir o comando, devemos especificar o destino no cmdlet Move-ItemProperty. Podemos usar um comando Get-ItemProperty para obter o caminho, mas o nome e o destino devem ser especificados na parte Move-ItemProperty do comando.

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

Para verificar se o comando funcionou, use um comando Get-ItemProperty:

get-itemproperty hklm:\software\mycompany\sales

Os resultados mostram que a entrada de Registro Product foi movida para a chave Sales.

        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

CONSULTE TAMBÉM

about_objects

about_parameters

about_command_syntax

about_foreach