TÓPICO
about_pipelines
DESCRIÇÃO RESUMIDA
Combinação de comandos em pipelines no Windows PowerShell
DESCRIÇÃO LONGA
Um pipeline é uma série de comandos conectada por operadores de
pipeline (|) (ASCII 124). Cada operador de pipeline envia os
resultados do comando anterior ao próximo comando.
Você pode usar pipelines para enviar os objetos que são
produzidos por um comando para serem usados como entrada para
outro comando para processar. E ainda você pode enviar a saída
daquele comando para outro comando. O resultado é uma cadeia de
comando muito avançada ou "pipeline" que é composto por uma série
de comandos simples.
Por exemplo,
Command-1 | Command-2 | Command-3
Nesse exemplo, os objetos que Command-1 emite são enviados para
Command-2. Command-2 processa os objetos e os envia para
Command-3. Command-3 processa os objetos e os envia para o
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 que eles aparecem. O processamento é tratado
como uma única operação e a saída é exibida da forma que é gerada.
Aqui está um exemplo simples. O comando a seguir obtém o processo
do Bloco de Notas e, em seguida, para-o.
get-process notepad | stop-process
O primeiro comando usa o cmdlet Get-Process para obter a 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 para o processo do Bloco de Notas. Note
que o comando Stop-Process não tem um parâmetro Name ou ID para
especificar o processo, porque o processo especificado é enviado
pelo pipeline.
Aqui está 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 que 10.000 bytes, os classifica por
comprimento e exibe o nome e comprimento 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
USANDO PIPELINES
Os cmdlets do Windows PowerShell foram criados para serem usados
em pipelines. Por exemplo, você pode enviar normalmente os
resultados de um cmdlet Get a um cmdlet de ação (como um cmdlet
Set, Start, Stop ou Rename) para o mesmo substantivo.
Por exemplo, você pode enviar qualquer serviço do cmdlet
Get-Service para o cmdlet Start-Service ou Stop-Service (embora
serviços desabilitados não possam ser reiniciados desse modo).
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 do Windows
PowerShell, como os cmdlets Item e ItemProperty, também são
criados para serem usados em pipelines.
Por exemplo, você pode enviar os resultados de um comando
Get-Item ou Get-ChildItem no provedor de Registro do Windows
PowerShell para o cmdlet New-ItemProperty. Este comando adiciona
uma nova entrada do Registro, NoOfEmployees, com o valor de 8124,
à chave de Registro MyCompany.
get-item -path HKLM:\Software\MyCompany | new-Itemproperty
-name NoOfEmployees -value 8124
Muitos dos cmdlets de utilitário, como Get-Member, Where-Object,
Sort-Object, Group-Object e Measure-Object são usados quase
exclusivamente em pipelines. Você pode enviar qualquer objeto a
esses cmdlets.
Por exemplo, você pode enviar todos os processos no computador
para o comando Sort-Object e tê-los classificado pelo número de
manipulações no processo.
get-process | sort-object -property handles
Além disso, você pode enviar qualquer objeto para os cmdlets de
formatação, como Format-List e Format-Table, os cmdlets de
exportação, como Export-Clixml e Export-CSV e os cmdlets de
saída, como Out-Printer.
Por exemplo, você pode enviar o processo Winlogon ao 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 a combinação de comandos
simples em pipelines economiza tempo e digitação e torna seu
script mais eficiente.
COMO OS PIPELINES FUNCIONAM
Quando você "envia" objetos aos objetos na saída de um comando
para outro comando, o Windows PowerShell tenta associar os
objetos enviados a um dos parâmetros do cmdlet de recebimento.
Para fazer isso, o componente "vinculação de parâmetro" do
Windows PowerShell, que associa objetos de entrada a parâmetros
de cmdlet, tenta localizar um parâmetro que atenda aos seguintes
critérios:
-- O parâmetro deve aceitar entrada de um pipeline (não todos
aceitam)
-- O parâmetro deve aceitar o tipo de objeto que é enviado ou um
tipo para o qual o objeto pode ser convertido.
-- O parâmetro ainda não deve ser usado no comando.
Por exemplo, o cmdlet Start-Service tem muitos parâmetros, mas
apenas dois deles, Name e InputObject, aceitam entrada do
pipeline. O parâmetro Name obtém cadeias de caracteres e o
parâmetro InputObject obtém objetos de serviço. Portanto, você
pode enviar cadeias de caracteres e objetos de serviço (e
objetos com propriedades que podem ser convertidas para cadeias
de caracteres e objetos de serviço) para Start-Service.
Se o componente de vinculação de parâmetro do Windows PowerShell
não puder associar os objetos enviados a um parâmetro do cmdlet
de recebimento, o comando falhará e o Windows PowerShell
solicitará a você os valores de parâmetros não presentes.
Você não pode forçar o componente de vinculação de parâmetro
para associar os objetos enviados com um parâmetro específico --
você não pode nem mesmo sugerir um parâmetro. Em vez disso, a
lógica do componente gerencia o envio do modo mais eficiente
possível.
PROCESSAMENTO UM DE CADA VEZ
O envio de objetos a um comando é como o uso de um parâmetro do
comando para enviar os objetos.
Por exemplo, o envio de objetos que representam os serviços no
computador para um comando Format-Table, como:
get-service | format-table -property name,
dependentservices
É como salvar os objetos de serviço em uma variável e usar o
parâmetro InputObject de Format-Table para enviar o objeto de
serviço.
$services = get-service
format-table -inputobject $services -property name,
dependentservices
ou fixar o comando no valor de parâmetro
format-table -inputobject (get-service wmi)
-property name, dependentservices
Contudo, há uma diferença importante. Quando você envia vários
objetos para um comando, o Windows PowerShell envia os objetos
ao comando um de cada vez. Quando você usa um parâmetro de
comando, os objetos são enviados como um único objeto de matriz.
Essa diferença aparentemente técnica pode ter consequências
interessante e, às vezes, úteis.
Por exemplo, se você enviar 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, ao Get-Member.
Get-Member exibe a classe .NET (tipo) dos objetos de processo e
suas propriedades e métodos.
(Get-Member elimina duplicatas; assim, se os objetos forem todos
do mesmo tipo, exibirá apenas um tipo de objeto.)
Nesse caso, Get-Member exibe as propriedades e métodos de cada
objeto de processo, isto é, 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
...
Contudo, se você usar o parâmetro InputObject de Get-Member,
Get-Member receberá uma matriz do objeto System.Diagnostics.Proc
ess como uma única unidade e exibe as propriedades de uma
matriz de objetos. (Observe o símbolo de matriz ([]) depois que
o System.Object digitem nome.)
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, 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 diferença pode ser importante, portanto, lembre-se de que,
quando você envia objetos a um cmdlet, eles são entregues um de
cada vez.
ACEITA ENTRADA DO PIPELINE
Para receber objetos em um pipeline, o cmdlet de recebimento deve
ter um parâmetro que aceite entrada do pipeline. Você pode usar
um comando Get-Help com os parâmetros Full ou Parameter para
determinar qual dos parâmetros de um cmdlet, se houver, aceita
entrada do pipeline.
Na exibição padrão de Get-Help, o item "Aceita entrada do
pipeline" é exibido em uma tabela de atributos do parâmetro. Essa
tabela é exibida somente quando você usa os parâmetros Full ou
Parameter do cmdlet Get-Help.
Por exemplo, para determinar qual 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[]>
Especifica os nomes para o serviço a ser iniciado.
O nome do parâmetro é opcional. Você pode usar "-Name" ou
seu alias, "-ServiceName", ou omitir o nome do parâmetro.
Necessário? true
Posição? 1
Valor padrão
--> Aceitar entrada do pipeline? true (ByValue,
ByPropertyName)
Aceitar caracteres curinga? true
-inputObject <ServiceController[]>
Especifica os objetos ServiceController que representam os
serviços que devem ser iniciados. Digite uma variável que
contenha os objetos ou digite um comando ou expressão que
obtenha os objetos.
Necessário? false
Posição? named
Valor padrão
--> Aceitar entrada do pipeline? true (ByValue)
Aceitar caracteres curinga? false
Isso significa que você pode enviar objetos (PsObjects) pelo
pipeline para o cmdlet Where-Object e o Windows PowerShell
associará o objeto ao parâmetro InputObject.
MÉTODOS DE ACEITAÇÃO DE ENTRADA DO PIPELINE
Os parâmetros de cmdlets podem aceitar entrada do pipeline de um
destes dois modos:
-- ByValue: os parâmetros que aceitam entrada "por valor" pode
aceitar objetos enviados que têm o mesmo tipo .NET como seu
valor de parâmetro ou objetos que podem ser convertidos
naquele 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: os parâmetros que aceitam entrada "por nome
de propriedade" podem aceitar objetos enviados 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, envie-o para
Get-Member.)
Alguns parâmetros podem aceitar objetos por valor ou por nome de
propriedade. Esses parâmetros são criados para obter a entrada
do pipeline facilmente.
INVESTIGANDO ERROS DE PIPELINE
Se um comando falhar por causa de um erro de pipeline, você
poderá investigar a falha e reescrever o comando.
Por exemplo, o comando a seguir tenta mover uma entrada do
Registro de uma chave do Registro para outra usando o cmdlet
Get-Item para obter o caminho de destino e, em seguida, enviando
o caminho para o cmdlet Move-ItemProperty.
De modo específico, 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 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 falha e o Windows PowerShell exibe a seguinte mensagem
de erro:
Move-ItemProperty: o objeto de entrada não pode ser
associado a nenhum parâmetro para o comando porque o comando
não obtém a entrada do pipeline ou a entrada e suas
propriedades não correspondem a nenhum dos parâmetros que
obtêm entrada do pipeline.
At line:1 char:23
+ $a | move-itemproperty <<<< -path
hklm:\software\mycompany\design -name product
Para analisar, use o cmdlet Trace-Command para rastrear o
componente de vinculação de parâmetro do Windows PowerShell. O
comando a seguir rastreia o componente de vinculação de parâmetro
enquanto o comando está sendo processado. Ele usa o parâmetro
-pshost para exibir os resultados no console, e o comando
-filepath para enviá-los ao arquivo debug.txt para referência futura.
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 prolongados, mas eles mostram
os valores sendo vinculados ao cmdlet Get-Item e, em seguida, os
valores nomeados sendo vinculados 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]
...
Finalmente, ele mostra que a tentativa de vincular o caminho ao
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 analisar 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 obtém a entrada do
pipeline somente "por nome de propriedade".
Isto é, o objeto enviado deve ter uma propriedade nomeada
Destination.
-destination <string>
Especifica o caminho até o local de destino.
Necessário? true
Posição? 2
Valor padrão
Aceitar entrada do pipeline? true (ByPropertyName)
Aceitar caracteres curinga? true
Para ver as propriedades do objeto sendo enviado ao cmdlet
Move-ItemProperty, envie-o para o cmdlet Get-Member. O comando a
seguir envia 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 do Registro de Produto foi
movida a chave de Vendas.
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