Windows PowerShellRepensando o pipeline

Don Jones

Muito já se falou sobre o quanto o Windows PowerShell é diferente, novo e interessante, no entanto, ele se baseia em conceitos de interface de linha de comando que existem há décadas, basicamente em sistemas operacionais baseados no UNIX e no Linux. Na verdade, a terminologia comum que compartilha com seus antecedentes pode

esconder a real flexibilidade e exclusividade do Windows PowerShell™ e sua conhecida eficiência em um ambiente Windows®.

Um dos recursos mais discutidos do Windows PowerShell é seu pipeline, mas, infelizmente, ele também é um dos mais incompreendidos. Isso porque depende de uma terminologia definida no início da década de 70, que então representava uma funcionalidade totalmente diferente e menos eficiente.

A origem dos pipes

Um dos primeiros shells do UNIX já criados foi o Thompson, que era muito primitivo e apresentava apenas os elementos mais básicos de linguagem de script sem nenhuma variável. O shell tinha um design deliberadamente modesto, já que seu único propósito era executar programas. Entretanto, ele introduziu um conceito-chave que foi aprimorado em outros shells daquela época: os pipes. Usando os símbolos < e >, o shell podia ser instruído a redirecionar a entrada e a saída para diferentes comandos, e a partir deles. O usuário agora era capaz de, por exemplo, redirecionar a saída do comando para um arquivo.

Essa sintaxe foi posteriormente expandida de forma que a saída de um comando também pudesse ser transportada via pipe para a entrada de outro comando, permitindo que longas seqüências de comandos fossem encadeadas para realizar tarefas mais complicadas. Na versão 4 do shell, o caractere de linha vertical "|" foi adotado em pipes e, assim, tornou-se conhecido como o caractere de pipe. Mesmo as primeiras versões do MS-DOS® implementavam pipes básicos por meio desses caracteres, permitindo ao usuário, por exemplo, transportar via pipe a saída do comando type para a entrada do comando more, criando uma exibição de uma página por vez para arquivos de texto longo.

Embora o shell Thompson fosse considerado totalmente inadequado na época do lançamento da versão 6 do UNIX em 1975, o conceito de pipes foi muito bem assimilado pelos desenvolvedores e usuários de shell e transmitido para diversas tecnologias empregadas atualmente.

Pipes de texto

Uma limitação de quase todos os shells é sua natureza essencialmente baseada em texto. Nos sistemas operacionais baseados em UNIX, isso não representa uma limitação, mas um reflexo do funcionamento do sistema. Quase todos os recursos no UNIX podem ser traduzidos como algum tipo um arquivo e, por isso, a possibilidade de transportar texto via pipe de um comando para outro proporciona uma grande capacidade e flexibilidade.

O texto, porém, é realmente uma limitação quando se trata de informações de gerenciamento. Por exemplo, se eu lhe apresentasse uma lista de serviços executados em um computador Windows, certamente você entenderia. Eu poderia colocar o nome do serviço na primeira coluna e seu modo de inicialização na segunda. Seu poderoso cérebro entenderia ou traduziria, com transparência e rapidez, a exibição do texto como informações importantes com as quais você poderia trabalhar. Entretanto, os computadores não são tão inteligentes assim; para que um computador fizesse algo significativo com essa lista, seria necessário dizer-lhe, talvez, que a primeira coluna consiste nos caracteres de 1 a 20, que os caracteres de 22 a 40 formam a segunda coluna e assim por diante.

Há séculos, esse tipo de análise de arquivo de texto era o único meio que os administradores tinham de encadear vários comandos. Na verdade, linguagens de script como VBScript e Perl são excelentes na manipulação de cadeia de caracteres, basicamente porque precisam aceitar a saída de texto de um programa ou comando e depois analisá-la como algum tipo de dado útil que possa ser usado em uma tarefa subseqüente. Já escrevi trabalhos em VBScript, por exemplo, que aceitavam a saída de texto do comando Dir, analisavam a saída de nomes e datas de arquivo e movia os arquivos antigos, não utilizados, para um local de arquivo morto. A análise de cadeias de caracteres é bastante perigosa, pois quase sempre ocorrem exceções, ou variações nos dados de entrada, que exigem uma correção na lógica para resolver todas as possíveis permutações.

Como forma de automação ou script administrativo em um ambiente Windows, a análise de cadeia de caracteres não é muito útil. Isso porque o Windows em si não armazena muita informação em um formato de texto de fácil acesso. Em vez disso, ele usa armazenamentos datacêntricos, como o Active Directory®, o registro do Windows e o armazenamento de certificados, de forma que os criadores de script tenham de usar primeiro uma ferramenta para gerar algum tipo de saída de texto e, em seguida, um script para analisar o texto e fazer algo com ele.

Os objetos são mais fáceis

Os desenvolvedores de software do Windows sempre facilitaram um pouco as coisas. A princípio, a Microsoft desenvolveu o COM especificamente para representar o complexo funcionamento do Windows de forma mais fácil. Hoje, o Microsoft® .NET Framework realiza a mesma tarefa: ele representa o funcionamento interno do software de maneira padronizada.

Em geral, tanto o COM quanto o .NET expõem os itens como objetos. (Um desenvolvedor de software poderia protestar contra essa simplificação, mas, em nome de nossa discussão, um termo simples é o suficiente.) Todos esses objetos possuem vários tipos de membros. Para o nosso propósito, as propriedades e os métodos dos objetos são o que mais interessa. Basicamente, uma propriedade descreve de alguma forma um objeto, modifica-o ou altera seu comportamento. Por exemplo, um objeto de serviço possui uma propriedade que contém o nome do serviço e outra que contém seu modo de inicialização. Os métodos fazem o objeto realizar uma ação. Um objeto de serviço possui métodos chamados Stop, Start, Pause e Resume, por exemplo, representando as diversas ações que você pode executar em um serviço.

Da perspectiva da programação, ou criação de scripts, os membros de um objeto são referenciados por meio de uma notação pontuada. Os objetos são, em geral, atribuídos a variáveis, que fornecem uma maneira de manipulá-los fisicamente. Por exemplo, se um serviço estiver atribuído à variável $service, poderei interrompê-lo usando a sintaxe $service.Stop. Ou poderei recuperar o nome de exibição do serviço usando $service.Name.

Objetos no pipe

Como o Windows é um sistema operacional amplo e complexo, e como não armazena seus dados de gerenciamento em representações ao estilo de texto, as técnicas de shell mais antigas, infelizmente, não são adequadas. Por exemplo, suponha que eu tenha uma ferramenta de linha de comando chamada SvcList.exe, que produz uma lista formatada de serviços e seus modos de inicialização. No shell de linha de comando do Windows, que seguramente nasceu do antigo shell do MS-DOS, eu poderia executar algo como:

SvcList.exe | MyScript.vbs 

Essa instrução recupera uma lista de serviços e a transporta via pipe para um arquivo VBScript. Eu teria de escrever o arquivo VBScript de forma que analisasse a lista formatada e fizesse o pretendido, por exemplo, definir a saída de qualquer serviço com um modo de inicialização Disabled. Essa tarefa levaria muito tempo. Na verdade, o problema é que SvcList.exe possui uma saída exclusiva; ela não compartilha um formato comum que outros comandos possam consumir facilmente ao usar sua saída.

Os objetos, porém, podem fornecer esse formato comum, e é por isso que o pipeline do Windows PowerShell funciona com objetos inteiros, e não apenas texto. Ao executar um cmdlet como Get-WMIObject, você produz um grupo (ou coleção, na linguagem de programador) de objetos. Cada objeto vem completo com propriedades e métodos que permitem manipulá-lo. Se eu transportar via pipe objetos para o cmdlet Where-Object, poderei filtrá-los de forma que apenas os objetos que eu desejar sejam exibidos. Where-Object não precisa analisar nenhum texto porque não é texto que ele está recebendo, mas objetos. Por exemplo:

Get-WMIObject Win32_Service | Where-Object {$_.StartMode -eq “Disabled” }

Ou, se você preferir encurtar a sintaxe disponível por meio de aliases:

gwmi Win32_Service | where {$_.StartMode -eq “Disabled” }

O interessante é que o Windows PowerShell sempre passa objetos pelo pipeline. Somente no fim do pipeline, quando não restam mais lugares para os quais passar objetos, o shell gera uma representação de texto dos objetos usando regras de formatação internas. Por exemplo, considere o seguinte:

Gwmi Win32_Service | where {$_.StartName –eq “LocalSystem” } | select Name,StartMode

Esse conjunto de três cmdlets recupera todos os serviços do meu computador local, filtra os que não usam a conta LocalSystem para fazer logon e passa o restante para o cmdlet Select-Object, que emite apenas as duas propriedades, Name e StartMode, que eu o instruí a selecionar. O resultado é um relatório simples de serviços que fazem logon como LocalSystem (talvez para fins de auditoria de segurança).

Como possuem o mesmo formato de dados — objetos —, todos os cdmlets podem compartilhar dados entre si sem qualquer análise complicada de cadeia de caracteres. E como o Windows PowerShell possui uma capacidade nativa de criar uma representação de texto de um objeto, o fim desse pipe, certamente, será uma saída de texto legível. A Figura 1 mostra um exemplo da saída gerada.

Figura 1 Saída de texto gerada por uma série de cmdlets em pipe que passam pelos objetos

Figura 1** Saída de texto gerada por uma série de cmdlets em pipe que passam pelos objetos **

O atrativo dos pipes

O que torna os pipes tão incríveis no Windows PowerShell é que tudo no Windows PowerShell é um objeto completo, com propriedades e métodos que podem ser usados. Mesmo um arquivo de texto é, tecnicamente, uma coleção de objetos de cadeia de caracteres, em que cada linha do arquivo funciona como um objeto de cadeia de caracteres exclusivo e independente. Por exemplo, crie um arquivo de texto (usando o Bloco de Notas) chamado C:\Computers.txt. Preencha o arquivo com texto e execute o seguinte no Windows PowerShell:

Get-Content C:\Computers.txt | Select-Object Length | Format-List

Ou, novamente, se preferir menos digitação, use aliases:

gc C:\Computers.txt | select Length | fl

Esse código fornece uma lista que indica o comprimento de cada linha do arquivo de texto, em caracteres. Get-Content recupera os objetos da cadeia de caracteres do arquivo, Select-Object captura a propriedade Length de cada um deles e Format-List cria uma saída de texto boa e legível. Embora talvez não seja muito prática, essa ferramenta administrativa ilustra que mesmo as coisas mais simples, como uma linha de texto, são objetos no Windows PowerShell.

A capacidade de transportar objetos via pipe de um cmdlet para outro, ou para um script, confere à criação todo o poder que uma linha pode ter. São cadeias de caracteres simples de cmdlets anexadas a um longo pipeline, que refina ainda mais um conjunto de objetos para produzir exatamente o que você deseja. Praticamente sem nenhum tipo de script ou programação, os cmdlets do Windows PowerShell, encadeados em um pipeline apropriado, podem obter resultados incríveis.

Oferecendo suporte às gerações futuras

O fato de que os futuros produtos de servidor da Microsoft também estejam sendo criados no Windows PowerShell amplia essa funcionalidade. Ao implementar um novo computador com Exchange Server 2007, por exemplo, você pode usar o Windows PowerShell para recuperar todas as caixas de correio, separar todas as que não forem do escritório em que o novo servidor de email estará localizado e mover as outras para o novo servidor, tudo em uma única linha de texto sem scripts. A equipe do Exchange Server 2007 publicou uma longa lista dessas poderosas linhas. Isso mostra o verdadeiro poder do pipeline e as tarefas administrativas que ele é capaz de realizar.

O truque com o Windows PowerShell é entender que, embora ele se baseie em filosofias e princípios antigos do universo do UNIX, essa nova ferramenta é especialmente adequada para a administração do Windows. Não se deixe enganar pela trivialidade da terminologia achando que o Windows PowerShell é apenas uma cópia do shell do UNIX para o Windows. O Windows PowerShell contém conceitos inteiramente novos que tiram proveito da plataforma Windows e está intimamente ligado ao jeito Windows de fazer as coisas.

Don Jones é MVP do Windows PowerShell e autor de Windows PowerShell 101 (ScriptingTraining.com). Você pode entrar em contato com Don em www.ScriptingAnswers.com.

© 2008 Microsoft Corporation e CMP Media, LLC. Todos os direitos reservados. A reprodução parcial ou completa sem autorização é proibida..