Windows PowerShellConstruções do Windows PowerShell

Don Jones

No mês passado, mostrei algumas maneiras pelas quais o Windows PowerShell poderia ser usado imediatamente para solucionar tarefas administrativas – sem precisar escrever nenhum script. Entretanto, embora o Windows PowerShell seja um excelente shell interativo, você realmente pode aproveitar seus recursos e automatizar tarefas mais complexas quando começar a utilizar linguagem de script ao mesmo tempo simples e poderosa.

Em primeiro lugar, você pode estar se perguntando: a Microsoft precisa mesmo de outra linguagem de script? Afinal de contas, a Microsoft criou o KiXtart, um processador de script de logon, assim como o Visual Basic® Scripting Edition (VBScript). A resposta, no entanto, é sim. A Microsoft realmente precisava de outra linguagem de script. Explicarei o porquê.

A linguagem do Windows PowerShell™ precisava ser simples e intuitiva, de modo que os administradores pudessem aprendê-la sem muito treinamento. Também precisava ser bastante flexível, para poder acomodar todas as funcionalidades poderosas que o próprio Windows PowerShell oferece aos usuários.

Como o Windows PowerShell é baseado no Microsoft® .NET Framework, sua sintaxe de script precisava ser compatível com .NET. Ao montar uma nova linguagem de script para o Windows PowerShell, os desenvolvedores selecionaram uma sintaxe C# essencialmente muito simples (pronuncia-se C-Sharp, umas das linguagens fornecida no .NET Framework). Por que não continuar usando uma sintaxe similar ao VBScript? Na verdade, a linguagem de script do Windows PowerShell não é tão diferente do VBScript, mas aproximando-se mais da sintaxe C#, o PowerShell fornece uma espécie de primeiro degrau para o aprendizado da programação em .NET Framework. Se, algum dia, você decidir migrar para o Visual Studio® e começar a escrever aplicativos em C#, grande parte de sua sintaxe de script do Windows PowerShell poderá migrar com você.

Uma das coisas mais importantes na linguagem de script do Windows PowerShell – ou em qualquer linguagem de script, na verdade – é sua construção. São elementos de linguagem especiais que permitem que o Windows PowerShell execute comparações lógicas e efetue ações diferentes com base nos resultados das comparações ou que o permitem repetir uma ou mais instruções diversas vezes.

Pensando logicamente

As comparações lógicas representam o âmago de muitas construções de linguagem de script, e o Windows PowerShell não é uma exceção. Essencialmente, uma comparação examina dois valores ou objetos e avalia se a comparação é True ou False. Por exemplo, você pode se perguntar, "A data de vencimento da senha deste usuário é a mesma de hoje?" O resultado será True se as datas forem as mesmas e False se forem diferentes. Observe que estou usando maiúsculas para True e False, porque são termos com um significado especial no Windows PowerShell.

Aqui há um exemplo de uma comparação lógica real que você poderia executar no Windows PowerShell:

PS C:\> $a = 1
PS C:\> $b = 2
PS C:\> $a -eq $b
False

Criei uma variável de nome $a e a configurei para que contivesse o valor 1. No Windows PowerShell, os nomes de variáveis sempre começam com um cifrão, então é fácil encontrá-las. O sinal de = é tecnicamente chamado de operador de atribuição, porque é usado para atribuir um valor. Em seguida, crio uma segunda variável, $b, e lhe atribuo o valor 2. Agora, temos a comparação lógica real – eu peço para o Windows PowerShell comparar o conteúdo de $a e $b com o operador -eq (igualdade). O PowerShell executa a comparação, determina que os dois valores não são iguais e exibe o resultado: False.

Os operadores do Windows PowerShell são um pouco diferentes de outras linguagens de script que talvez você já tenha visto, e também se diferenciam de C#. A maioria das linguagens usam o operador = para executar verificações de igualdade e também para atribuição de valor; o Windows PowerShell evita a confusão com um operador dedicado para cada função. A Figura 1 mostra os operadores de comparação do Windows PowerShell, juntamente com operadores equivalentes em outras linguagens (como VBScript) que talvez você já conheça.

Figure 1 Operadores de comparação do PowerShell

Operador Nome Descrição
-eq Igualdade Testa se valores são iguais. Outras linguagens podem usar = ou == para testar igualdade.
-ne Diferente de Testa desigualdade. Outras linguagens podem usar <> ou != para testar desigualdade.
-gt Maior que Testa se um valor é maior do que o outro. Outras linguagens podem usar o caractere >.
-lt Menor que Testa se um valor é menor do que o outro. Outras linguagens podem usar o caractere <.
-ge Maior ou igual a Testa se um valor é maior ou igual a outro valor. Similar a >= em VBScript e outras linguagens.
-le Menor ou igual a Testa se um valor é menor ou igual a outro valor. Similar a <= em VBScript e outras linguagens.

Esses operadores de comparação têm outros recursos interessantes. Veja esta comparação:

PS C:\> $a = "TechNet"
PS C:\> $b = "technet"
PS C:\> $a -eq $b
True

Por padrão, os operadores de comparação não diferenciam maiúsculas de minúsculas, o que significa que a versão com maiúsculas de TechNet é considerada como equivalente a "technet". Isso é conveniente, porque na maior parte das tarefas administrativas, você não precisa se preocupar se as letras são maiúsculas ou minúsculas. Entretanto, nos casos em que precisar dessa diferenciação, você pode pedir ao Windows PowerShell que execute uma comparação diferenciando maiúsculas de minúsculas, adicionando a letra c ao início do operador de comparação:

PS C:\> $a -ceq $b
False

Da mesma forma, se você se estiver preocupado ou confuso com a possibilidade do Windows PowerShell executar uma comparação diferenciando maiúsculas de minúsculas, você poderá forçá-lo a fazer isso, acrescentando a letra i no início do operador:

PS C:\> $a -ieq $b
True

Lembre-se de que comparações lógicas sempre resultam em um dos dois valores: True ou False.

Tomando decisões

Agora que você sabe como criar comparações lógicas, pode começar a usá-las em construções. A primeira construção que vou mostrar permite que o Windows PowerShell tome decisões com base em uma comparação. Ela é chamada de construção If, e há algumas variações dela. Esta é a mais simples:

PS C:\> if ($a -eq $b) {
>> Write-Host "They are equal"
>> }
>>
They are equal

Há alguns itens interessantes a serem observados aqui. Primeiro, as variáveis $a e $b ainda contêm os valores "TechNet" e "technet", respectivamente. Comecei a construção usando a palavra-chave If. Em seguida, entre parênteses, digitei a comparação lógica que desejava executar. Depois disso vem uma chave, que sinaliza o início do que eu vou chamar de código condicional – o código que o Windows PowerShell executará se a comparação retornar um resultado True. Você já sabe, pelo exemplo anterior, que essa comparação retorna o resultado True, então esperamos que o código condicional seja executado. Digito o código condicional, Write-Host "They are equal" e pressiono Enter. Finalmente, termino a seção do código condicional digitando uma chave de fechamento e pressionando Enter duas vezes. (O segundo Enter em uma linha em branco avisa o analisador que eu terminei de escrever e que o código pode ser executado.)

Observe que essa construção não está sendo executada a partir de um arquivo de script. Eu simplesmente digitei a construção na linha de comando do Windows PowerShell. Isso é o que torna o Windows PowerShell exclusivo no mundo do script do Windows: os scripts podem ser criados interativamente e colocados em um arquivo para armazenamento permanente.

Assim que eu digitei a primeira chave e pressionei Enter, o Windows PowerShell exibiu um prompt >>. Esse é o modo dele dizer "Reconheço que você está em uma construção, e estou pronto para receber o que será inserido na construção". Depois de digitar a chave de fechamento e pressionar Enter duas vezes, o Windows PowerShell imediatamente executou a construção, determinou que sua comparação lógica era True e executou o código condicional. Você pode perceber isso porque "They are equal" (Eles são iguais) foi exibido antes que o PowerShell voltasse ao seu prompt normal. Usar o Windows PowerShell para fazer scripts interativamente permite que você teste rapidamente partes do código antes de montá-los em um script mais permanente, o que facilita o aprendizado e a depuração.

Devo salientar que o Windows PowerShell não é muito exigente em relação a tarefas como pressionar Enter. Por exemplo, isto é funcionalmente igual ao exemplo anterior:

PS C:\> if ($a -eq $b) { Write-Host "They are equal" }
They are equal

Como digitei tudo em uma linha, o Windows PowerShell não precisou exibir o >>prompt especial; ele simplesmente executou a construção quando pressionei Enter no final da linha. Como o Windows PowerShell sabia que podia executar a construção? Porque ela estava completa neste ponto – a chave de fechamento tinha sido digitada.

Comentei que havia outras variações da construção If. Aqui há um exemplo completo, apresentado como poderia aparecer em um arquivo de script PS1, e não no shell:

if ($a -eq $b) {
  Write-Host "They are equal"
} elseif ($a -lt $b) {
  Write Host "One is less than the other"
} else {
  Write Host "One is greater than the other"
}

A construção começa da mesma maneira, usando a palavra-chave If. No entanto, para o caso de a comparação ser False, forneci outra comparação usando a palavra-chave Elseif. Se essa segunda comparação também for False, então minha última palavra-chave, Else, fornecerá um código final, que será executado.

Repetindo suas instruções

O Windows PowerShell contém algumas construções para executar códigos várias vezes, até que alguma comparação seja True ou False. Elas são chamadas de construções em loop pelos programadores. O melhor é que uma das construções em loop mais úteis consegue enumerar os objetos em uma coleção e executar uma ou mais linhas de código para cada objeto. Essa construção é adequadamente chamada de construção foreach, e ela se assemelha a isto:

PS C:\> $names = get-content "c:\computers.txt"
PS C:\> foreach ($name in $names) {
>> Write-Host $name
>> }
>>
don-pc
testbed

Comecei pedindo que o cmdlet Get-Content do Windows PowerShell recuperasse o conteúdo do arquivo c:\computers.txt file, um arquivo que eu mesmo criei e que contém um nome de computador por linha. O Windows PowerShell trata cada linha como um objeto, de modo que o arquivo é essencialmente uma coleção que contém tais objetos. A coleção termina com a variável $names. Usando a palavra-chave Foreach, peço para que o Windows PowerShell enumere a coleção $names usando a variável $name para representar o objeto atual sempre que o loop é executado. O código do loop é colocado entre chaves. Dessa forma, para cada nome do arquivo, eu coloco o nome na linha de comando. E, como você pode perceber na saída após a construção, isso é exatamente o que o Windows PowerShell faz. É possível perceber como isso proporcionaria um benefício óbvio para o trabalho administrativo com script: você poderia construir facilmente uma lista de nomes de servidores, por exemplo, e fazer com que o Windows PowerShell recuperasse informações de cada um deles, um por vez.

Construções reais

Então, vamos pegar comparações lógicas, as construções If e foreach, e fazer algo útil. Quero verificar rapidamente o status do serviço do Messenger em um conjunto de servidores. Espero que o serviço esteja parado na maior parte dos servidores, então não quero que o Windows PowerShell relacione todos os servidores nos quais o serviço esteja no estado esperado; desejo que ele liste apenas os servidores nos quais o serviço do Messenger tenha sido iniciado, porque preciso executar algo nesses servidores.

Sei que o cmdlet Get-Service do Windows PowerShell pode me ajudar a recuperar as informações de que preciso no computador local. Entretanto, infelizmente, ele não consegue acessar um computador remoto, que é a minha intenção. Por sorte, também consigo acessar as mesmas informações por intermédio do WMI (Windows Management Instrumentation), usando o cmdlet Get-WMIObject, que me permite trabalhar com um computador remoto. Então, eis aqui o script:

$names = get-content c:\computers.txt
foreach ($name in $names) {
  $svc = get-wmiobject win32_service '
   -computer $name -filter "name='messenger'"
  if ($svc.started -eq $True ) {
    write-host "$name has Messenger running"
  }
}

Você reparou no caractere ' na terceira linha? Ele informa ao Windows PowerShell que a próxima linha é uma continuação. Isso é útil em casos como esse, em que toda a linha não caberia na revista sem quebrá-la. Repare também que minha construção If compara $svc.started com $True. A variável $True é uma variável especial no Windows PowerShell, que representa o valor True booleano. (Uma variável relacionada, $False, representa o False booleano.) Na verdade, eu poderia ter usado um atalho aqui:

$names = get-content c:\computers.txt
foreach ($name in $names) {
  $svc = get-wmiobject win32_service '
   -computer $name -filter "name='messenger'"
  if ($svc.started) {
    write-host "$name has Messenger running"
  }
}

Lembre-se de que a condição da construção If precisa simplesmente ser True ou False. Normalmente, você obtém True ou False comparando dois valores, como fiz com a primeira versão deste script. Entretanto, como a propriedade Started é True ou False, não é necessário compará-la com True ou False.

Uma ferramenta útil

Então, aqui está – uma ferramenta administrativa simples e útil que utiliza construções para executar o trabalho. Quer você a digite no Windows PowerShell interativamente ou salve-a em um arquivo PS1 para poder reutilizá-la com facilidade, ela é uma ferramenta útil para verificar o status de um serviço em vários computadores, e uma ótima demonstração de como as construções podem ajudar a automatizar tarefas administrativas.

Don Jones é o diretor de projetos e serviços da SAPIEN Technologies e co-autor do Windows PowerShell: TFM (SAPIEN Press, 2006). Entre em contato com Don em seu site em ScriptingAnswers.com.

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