Partilhar via


Sobre Os Oleodutos

Breve descrição

Combinando comandos em oleodutos no PowerShell

Longa descrição

Um gasoduto é uma série de comandos ligados pelos operadores de | gasodutos (ASCII 124). Cada operador de gasoduto envia os resultados do comando anterior para o comando seguinte.

A saída do primeiro comando pode ser enviada para processamento como entrada para o segundo comando. E essa saída pode ser enviada para outro comando. O resultado é uma complexa cadeia de comandos ou oleoduto que é composta por uma série de comandos simples.

Por exemplo,

Command-1 | Command-2 | Command-3

Neste exemplo, os Command-1 objetos que emitem são enviados para Command-2 . Command-2processa os objetos e envia-os para Command-3 . Command-3processa os objetos e enviá-los para baixo do oleoduto. Como não há mais comandos no oleoduto, os resultados são apresentados na consola.

Num oleoduto, os comandos são processados de forma a partir da esquerda para a direita. O processamento é manuseado como uma única operação e a saída é exibida à medida que é gerada.

Aqui está um exemplo simples. O seguinte comando obtém o processo do Bloco de Notas e, em seguida, pára-o.

Por exemplo,

Get-Process notepad | Stop-Process

O primeiro comando utiliza o Get-Process cmdlet para obter um objeto que represente o processo do Bloco de Notas. Utiliza um operador de gasoduto | para enviar o objeto de processo para o Stop-Process cmdlet, o que impede o processo do Bloco de Notas. Note que o Stop-Process comando não Name tem um nome ou parâmetro de identificação para especificar o processo, porque o processo especificado é submetido através do pipeline.

Este exemplo de pipeline obtém os ficheiros de texto no diretório atual, seleciona apenas os ficheiros com mais de 10.000 bytes de comprimento, classifica-os por comprimento e exibe o nome e o comprimento de cada ficheiro numa tabela.

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

Este gasoduto é composto por quatro comandos na ordem especificada. A seguinte ilustração mostra a saída de cada comando à medida que é passada para o comando seguinte no oleoduto.

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

Utilização de oleodutos

A maioria dos cmdlets PowerShell são projetados para suportar gasodutos. Na maioria dos casos, pode canalizar os resultados de um Get cmdlet para outro cmdlet do mesmo substantivo. Por exemplo, pode canalizar a saída do Get-Service cmdlet para os Start-Service Stop-Service cmdlets ou cmdlets.

Este pipeline exemplo inicia o serviço WMI no computador:

Get-Service wmi | Start-Service

Por outro exemplo, pode canalizar a saída ou dentro do fornecedor de Get-Item Get-ChildItem registo PowerShell para o New-ItemProperty cmdlet. Este exemplo adiciona uma nova entrada de registo, NoOfEmployees, com um valor de 8124, à chave de registo MyCompany.

Get-Item -Path HKLM:\Software\MyCompany |
  New-ItemProperty -Name NoOfEmployees -Value 8124

Muitos dos cmdlets utilitários, Get-Member Where-Object como, Sort-Object por Group-Object exemplo, Measure-Object são usados quase exclusivamente em oleodutos. Pode canalizar qualquer tipo de objeto para estes cmdlets. Este exemplo mostra como classificar todos os processos no computador pelo número de pegas abertas em cada processo.

Get-Process | Sort-Object -Property handles

Pode canalizar objetos para os cmdletes de formatação, exportação e saída, tais Format-List Format-Table como, Export-Clixml , , e Export-CSV Out-File .

Este exemplo mostra como usar o Format-List cmdlet para apresentar uma lista de propriedades para um objeto de processo.

Get-Process winlogon | Format-List -Property *

Com um pouco de prática, você vai descobrir que combinar comandos simples em oleodutos poupa tempo e dactilografia, e torna o seu script mais eficiente.

Como funcionam os oleodutos

Esta secção explica como os objetos de entrada estão ligados aos parâmetros do cmdlet e processados durante a execução do gasoduto.

Aceita entrada de gasoduto

Para suportar a pipelinagem, o cmdlet recetor deve ter um parâmetro que aceite a entrada do gasoduto. Utilize o Get-Help comando com as opções Full ou Parâmetro para determinar quais os parâmetros de um cmdlet que aceitam a entrada do gasoduto.

Por exemplo, para determinar qual dos parâmetros do Start-Service cmdlet aceita a entrada do gasoduto, escreva:

Get-Help Start-Service -Full

ou

Get-Help Start-Service -Parameter *

A ajuda para o Start-Service cmdlet mostra que apenas os parâmetros InputObject e Name aceitam a entrada do gasoduto.

-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 envia objetos através do oleoduto Start-Service para, o PowerShell tenta associar os objetos aos parâmetros InputObject e Name.

Métodos de aceitação da entrada do gasoduto

Os parâmetros cmdlets podem aceitar a entrada do gasoduto de uma de duas maneiras diferentes:

  • ByValue: O parâmetro aceita valores que correspondam ao tipo .NET esperado ou que possam ser convertidos para esse tipo.

    Por exemplo, o parâmetro Nome de aceita entrada de Start-Service gasoduto por valor. Pode aceitar objetos de cordas ou objetos que podem ser convertidos em cordas.

  • ByPropertyName: O parâmetro só aceita a entrada quando o objeto de entrada tem uma propriedade com o mesmo nome que o parâmetro.

    Por exemplo, o parâmetro Nome de Start-Service pode aceitar objetos que tenham uma propriedade Nome. Para listar as propriedades de um objeto, encaneá-lo a Get-Member .

Alguns parâmetros podem aceitar objetos pelo valor ou nome da propriedade, facilitando a entrada do pipeline.

Ligação de parâmetros

Quando canaliza objetos de um comando para outro comando, o PowerShell tenta associar os objetos canalizados a um parâmetro do cmdlet recetor.

O componente de ligação de parâmetros da PowerShell associa os objetos de entrada aos parâmetros cmdlet de acordo com os seguintes critérios:

  • O parâmetro deve aceitar a entrada de um oleoduto.
  • O parâmetro deve aceitar o tipo de objeto que está a ser enviado ou um tipo que pode ser convertido para o tipo esperado.
  • O parâmetro não foi usado no comando.

Por exemplo, o Start-Service cmdlet tem muitos parâmetros, mas apenas dois deles, Nome e InputObject aceitam a entrada do gasoduto. O parâmetro Nome leva cordas e o parâmetro InputObject leva objetos de serviço. Portanto, pode canalizar cordas, objetos de serviço e objetos com propriedades que podem ser convertidos em fios ou objetos de serviço.

O PowerShell gere a ligação dos parâmetros da forma mais eficiente possível. Não se pode sugerir ou forçar o PowerShell a ligar-se a um parâmetro específico. O comando falha se o PowerShell não conseguir ligar os objetos canalizados.

Para obter mais informações sobre erros de vinculação de resolução de problemas, consulte a Investigação de Erros do Pipeline mais tarde neste artigo.

Processamento único de uma vez

Canalizar objetos para um comando é muito parecido com usar um parâmetro do comando para enviar os objetos. Vejamos um exemplo de oleoduto. Neste exemplo, usamos um oleoduto para exibir uma tabela de objetos de serviço.

Get-Service | Format-Table -Property Name, DependentServices

Funcionalmente, isto é como usar o parâmetro InputObject Format-Table para submeter a coleção de objetos.

Por exemplo, podemos guardar a recolha de serviços para uma variável que é passada usando o parâmetro InputObject.

$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices

Ou podemos incorporar o comando no parâmetro InputObject.

Format-Table -InputObject (Get-Service) -Property Name, DependentServices

No entanto, há uma diferença importante. Quando canaliza vários objetos para um comando, o PowerShell envia os objetos ao comando um de cada vez. Quando se utiliza um parâmetro de comando, os objetos são enviados como um único objeto de matriz. Esta pequena diferença tem consequências significativas.

Ao executar um oleoduto, o PowerShell enumera automaticamente qualquer tipo que implemente a IEnumerable interface e envia os membros através do pipeline um de cada vez. A exceção é [hashtable] , que requer uma chamada para o GetEnumerator() método.

Nos exemplos seguintes, uma matriz e um haxixe são canalizados para o Measure-Object cmdlet para contar o número de objetos recebidos da tubagem. A matriz tem vários membros, e o haxixe tem múltiplos pares de valores-chave. Só a matriz é enumerada uma de cada vez.

@(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 :

Da mesma forma, se canalizar vários objetos de processo do Get-Process cmdlet para o Get-Member cmdlet, a PowerShell envia cada objeto de processo, um de cada vez, para Get-Member . Get-Memberexibe a classe .NET (tipo) dos objetos do processo e as suas propriedades e métodos.

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-Memberelimina duplicados, por isso, se os objetos são todos do mesmo tipo, só apresenta um tipo de objeto.

No entanto, se utilizar o parâmetro InputObject de Get-Member , em seguida, Get-Member recebe uma matriz de objetos System.Diagnostics.Process como uma única unidade. Exibe as propriedades de uma variedade de objetos. (Note o símbolo da matriz [] () após o nome do tipo System.Object.)

Por exemplo,

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

Este resultado pode não ser o que pretendia. Mas depois de o entenderes, podes usá-lo. Por exemplo, todos os objetos de matriz têm uma propriedade Count. Pode usá-lo para contar o número de processos em execução no computador.

Por exemplo,

(Get-Process).count

É importante lembrar que os objetos enviados pelo oleoduto são entregues um de cada vez.

Investigar erros de gasoduto

Quando o PowerShell não consegue associar os objetos canalizados a um parâmetro do cmdlet recetor, o comando falha.

No exemplo seguinte, tentamos mover uma entrada de registo de uma chave de registo para outra. O Get-Item cmdlet obtém o caminho de destino, que é então canalizado para o Move-ItemProperty cmdlet. O Move-ItemProperty comando especifica o caminho e o nome atuais da entrada de registo a ser movido.

Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product

O comando falha e o PowerShell apresenta a seguinte mensagem de erro:

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

Para investigar, utilize o Trace-Command cmdlet para rastrear o componente de ligação dos parâmetros do PowerShell. O exemplo a seguir traça a ligação dos parâmetros enquanto o gasoduto está a ser executado. O parâmetro PSHost apresenta os resultados dos vestígios na consola e o parâmetro FilePath envia os resultados do traço para o debug.txt ficheiro para referência posterior.

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
}

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

Finalmente, mostra que a tentativa de ligar o caminho ao parâmetro destino 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
...

Utilize o Get-Help cmdlet para ver os atributos do parâmetro Destino.

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

Os resultados mostram que o Destino leva a entrada do gasoduto apenas "pelo nome da propriedade". Portanto, o objeto canalizado deve ter uma propriedade chamada Destino.

Utilize Get-Member para ver as propriedades do objeto vindo. Get-Item

Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member

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

O parâmetro Path aceita a entrada do gasoduto pelo nome ou pelo valor.

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

Para corrigir o comando, temos de especificar o destino no Move-ItemProperty cmdlet e usar Get-Item para obter o Caminho do item que queremos mover.

Por exemplo,

Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product

Continuação da linha intrínseca

Como já foi discutido, um gasoduto é uma série de comandos ligados por operadores de gasodutos ( | ), normalmente escritos numa única linha. No entanto, para a legibilidade, o PowerShell permite-lhe dividir o gasoduto em várias linhas. Quando um operador de tubos é o último símbolo da linha, o parser PowerShell une a linha seguinte ao comando atual para continuar a construção do gasoduto.

Por exemplo, o seguinte gasoduto de linha única:

Command-1 | Command-2 | Command-3

pode ser escrito como:

Command-1 |
  Command-2 |
    Command-3

Os espaços principais nas linhas subsequentes não são significativos. O entalhe aumenta a legibilidade.

Consulte também

about_PSReadLine

about_Objects

about_Parameters

about_Command_Syntax

about_ForEach