PowerShell para Sysadmins

imagemOlá, Habitantes! PowerShell é uma linguagem de script e um shell de comando que permite gerenciar e automatizar quase qualquer tarefa. No PowerShell para Sysadmins, o proprietário do Microsoft MVP Adam Bertram, também conhecido como “o Automator”, mostra como usar o PowerShell para que o leitor finalmente tenha tempo para brinquedos, ioga e gatos. Você aprenderá a: -Combinar comandos, controlar o fluxo de execução, lidar com erros, escrever scripts, executá-los remotamente e testá-los usando a estrutura de teste Pester. -Analisar dados estruturados como XML e JSON, trabalhar com serviços populares (como Active Directory, Azure e Amazon Web Services), criar sistemas de monitoramento de servidor. -Criar e projetar módulos PowerShell. - Use o PowerShell para conveniência,instalação totalmente automatizada do Windows. -Crie uma floresta do Active Directory com apenas um host Hyper-V e alguns arquivos ISO. -Crie inúmeros servidores web e SQL com apenas algumas linhas de código! Exemplos da vida real ajudam a preencher a lacuna entre a teoria e o trabalho em um sistema real, e o humor leve do autor torna a leitura mais fácil. Pare de confiar em softwares caros e em conselhos vagos da web!



Para quem é este livro
- , . DevOps, , / (CI/CD).



, PowerShell . PowerShell « Windows» — Microsoft, PowerShell . , , .



Controle de fluxo



Vamos repetir um pouco. No Capítulo 3, aprendemos como combinar comandos usando um pipeline e scripts externos. O Capítulo 2 abordou variáveis ​​e como usá-las para armazenar valores. Uma das principais vantagens de trabalhar com variáveis ​​é a capacidade de usá-las para escrever código que não funcione com valor, mas com "significado". Em vez de trabalhar com o número 3, por exemplo, você trabalhará com o conceito geral de $ serverCount. Isso permite que você escreva um código que funcione da mesma forma, quer você tenha um, dois ou mil servidores. Combine essa capacidade com a capacidade de salvar seu código em scripts que podem ser executados em diferentes computadores, e você pode começar a resolver problemas em uma escala muito maior.



No entanto, na vida, às vezes importa se você trabalha com um servidor, com dois ou com mil. Até agora, você não tem uma maneira adequada de explicar isso, e seus scripts simplesmente são executados de cima para baixo, incapazes de se adaptar com base em determinados valores. Neste capítulo, usaremos o fluxo de controle e a lógica condicional para escrever scripts que executarão comandos diferentes dependendo dos valores sobre os quais operam. No final do capítulo, você aprenderá como usar as instruções if / then e switch, bem como vários loops, para dar ao seu código a flexibilidade necessária.



Um pouco sobre o fluxo de controle



Vamos escrever um script que lê o conteúdo de um arquivo armazenado em vários computadores remotos. Para continuar, baixe um arquivo chamado App_configuration.txt dos materiais do livro em github.com/adbertram/PowerShellForSysadmins/ e coloque-o na raiz da unidade C: \ em vários computadores remotos. Se você não tem computadores remotos, continue lendo por enquanto. Para este exemplo, usarei os servidores chamados SRV1, SRV2, SRV3, SRV4 e SRV5.



Para acessar o conteúdo do arquivo, use o comando Get-Content e especifique o caminho para o arquivo no valor do argumento do parâmetro Path, conforme mostrado abaixo:



Get-Content -Path "\\ servername \ c $ \ App_configuration.txt "



Primeiro, vamos salvar todos os nomes de nossos servidores em um array e executar este comando para cada servidor. Abra um novo arquivo .ps1 e insira o código da Listagem 4.1 nele.



Listagem 4.1. Extração de conteúdo de arquivo de vários servidores



$servers = @('SRV1','SRV2','SRV3','SRV4','SRV5')
Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[1])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[2])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[3])\c$\App_configuration.txt"
Get-Content -Path "\\$($servers[4])\c$\App_configuration.txt"
      
      





Em teoria, esse código deve funcionar sem problemas. Mas este exemplo pressupõe que algo está errado para você. E se o servidor SRV2 estiver inativo? E se alguém esquecer de colocar App_configuration.txt no SRV4? Ou talvez alguém mudou o caminho do arquivo? Você pode escrever um script separado para cada servidor, mas esta solução não será escalonada, especialmente quando você começar a adicionar mais e mais servidores. Você precisa de um código que funcione dependendo da situação.



A ideia por trás do fluxo de controle é que ele permite que você execute diferentes conjuntos de instruções com base em uma lógica predefinida. Imagine que seus scripts sejam executados em um caminho específico. Até agora, seu caminho é simples - da primeira linha de código à última. No entanto, você pode adicionar garfos ao longo do caminho, retornar aos lugares que já visitou ou pular por cima deles. Ao bifurcar os caminhos de execução do seu script, você dá a ele mais flexibilidade, permitindo lidar com muitas situações com um único script.



Começaremos examinando o tipo mais simples de fluxo de controle, a instrução condicional.



Usando declarações condicionais



No Capítulo 2, aprendemos que existem valores lógicos: verdadeiro e falso. Os booleanos permitem que você crie instruções condicionais que instruem o PowerShell a executar um bloco de código específico dependendo se uma expressão (chamada de condição) for avaliada como True ou False. Uma condição é uma pergunta sim / não. Você tem mais de cinco servidores? O servidor 3 está funcionando? O caminho do arquivo existe? Para começar a usar instruções condicionais, vamos ver como converter essas perguntas em expressões.



Construindo Expressões com Operadores Você



pode escrever expressões lógicas usando operadores de comparação que comparam valores. Para usar um operador de comparação, você precisa colocá-lo entre dois valores, por exemplo:



PS> 1 –eq 1
True
      
      





Nesse caso, o operador –eq permite determinar a equivalência de dois valores.

Abaixo está uma lista dos operadores de comparação mais comuns que usaremos:



-eq compara dois valores e retorna True se eles forem iguais.



-ne compara dois valores e retorna True se eles não forem iguais.



-gt compara dois valores e retorna True se o primeiro for maior que o segundo.



-ge compara dois valores e retorna True se o primeiro for maior ou igual ao segundo.



-lt compara dois valores e retorna True se o primeiro for menor que o segundo.



-le compara dois valores e retorna True se o primeiro for menor ou igual ao segundo.



-contains retorna True se o segundo valor fizer parte do primeiro. Por exemplo, este operador permite determinar se um valor está dentro de uma matriz.



O PowerShell também possui operadores de comparação mais avançados. Não vamos nos alongar sobre eles aqui, mas recomendo que você leia sobre eles na documentação da Microsoft em docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators ou na seção de Ajuda do PowerShell (veja o capítulo 1).



Você pode usar os operadores acima para comparar variáveis ​​e valores. Mas a expressão não precisa ser uma comparação. Às vezes, os comandos do PowerShell podem ser usados ​​como condições. No exemplo anterior, queríamos saber a disponibilidade do servidor. Você pode usar o cmdlet Test-Connection para testar a conexão com o servidor. Normalmente, a saída do cmdlet Test-Connection contém muitas informações diferentes, mas com o parâmetro Quiet você pode forçar o comando a retornar True ou False, e o parâmetro Count pode limitar o teste a uma tentativa.



PS> Test-Connection -ComputerName offlineserver -Quiet -Count 1
False
      
      





PS> Test-Connection -ComputerName onlineserver -Quiet -Count 1
True
      
      





Para descobrir se o servidor está inativo, você pode usar o operador –not para inverter a expressão:



PS> -not (Test-Connection -ComputerName offlineserver -Quiet -Count 1)
True
      
      





Agora que você está familiarizado com as expressões básicas, vamos examinar o operador condicional mais simples.



A instrução if A instrução



if funciona simplesmente: se X for verdadeiro, faça Y. É isso!



Para usar uma declaração em uma expressão, escreva a palavra-chave if seguida por parênteses contendo a condição. A expressão é seguida por um bloco de código entre chaves. O PowerShell só executará este bloco de código se a expressão for avaliada como True. Se a expressão if for avaliada como False ou não retornar nada, o bloco de código não será executado. A sintaxe para a instrução if / then é mostrada na Listagem 4.2.



Listagem 4.2. Sintaxe da instrução If



if () {
   #  ,   
}
      
      





Este exemplo tem um pouco de nova sintaxe: o caractere hash (#) denota um comentário - este é o texto que o PowerShell ignora. Você pode usar os comentários para deixar notas e descrições úteis para você ou para outra pessoa que lerá seu código posteriormente.



Agora, vamos dar uma outra olhada no código mostrado na Listagem 4.1. Vou mostrar como usar uma instrução if para evitar a tentativa de alcançar um servidor inativo. Já vimos na seção anterior que o comando Test-Connection pode ser usado como uma expressão que retorna True ou False, então, por enquanto, vamos envolver Test-Connection em uma instrução if e, em seguida, usar o comando Get-Content para evitar tentar acessar um servidor morto. ... Por enquanto, mudaremos apenas o código do primeiro servidor, conforme mostrado na Listagem 4.3.



Listagem 4.3. Usando uma instrução if para acessar seletivamente



$servers = @('SRV1','SRV2','SRV3','SRV4','SRV5')
if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {
   Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"
}
Get-Content -Path "\\$($servers[1])\c$\App_configuration.txt"
----
      
      





Já que você tem Get-Content em sua instrução if, você não encontrará nenhum erro se tentar acessar um servidor quebrado; se o teste falhar, seu script sabe que não deve tentar ler o arquivo. O código tentará acessar o servidor apenas se já souber que está habilitado. Mas observe que este código só dispara se a condição for verdadeira. Freqüentemente, você precisará especificar um comportamento de script para uma condição verdadeira e outro para uma condição falsa. Na próxima seção, você verá como definir o comportamento de uma condição falsa usando a instrução else.



Outra declaração



Para fornecer uma alternativa à sua instrução if, você pode usar a palavra-chave else após o fechamento dos parênteses do bloco if, seguida por outro par de chaves contendo o bloco de código. Conforme mostrado na Listagem 4.4, usaremos uma instrução else para retornar um erro ao console se o primeiro servidor não responder.



Listagem 4.4. Usando a cláusula else para executar o código se a condição

não for verdadeira



if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {
   Get-Content -Path "\\$($servers[0])\c$\App_configuration.txt"
} else {
   Write-Error -Message "The server $($servers[0]) is not responding!"
}
      
      





A instrução if / else funciona muito bem quando você tem duas situações mutuamente exclusivas. Nesse caso, o servidor está conectado ou não, ou seja, precisamos apenas de duas ramificações do código. Vamos ver como lidar com situações mais complexas.



Declaração Elseif



A instrução else cobre a situação oposta: se se não funcionar, faça-o mesmo assim. Essa abordagem funciona para condições binárias, ou seja, quando o servidor está em execução ou não. Mas às vezes você tem que lidar com um grande número de opções. Por exemplo, suponha que você tenha um servidor que não possui o arquivo desejado e tenha armazenado o nome desse servidor na variável $ problemServer (adicione esta linha de código ao seu script!). Isso significa que você precisa de uma verificação adicional para ver se o servidor que você está pesquisando é o servidor com problema. Isso pode ser feito com instruções aninhadas if, conforme mostrado no código a seguir:



if (Test-Connection -ComputerName $servers[0] -Quiet -Count 1) {
   if ($servers[0] –eq $problemServer) {
      Write-Error -Message "The server $servers[0] does not have the right
         file!"
   } else {
      Get-Content -Path "\\$servers[0]\c$\App_configuration.txt"
   }
} else {
   Write-Error -Message "The server $servers[0] is not responding!"
}
----
      
      





Mas existe uma maneira mais simples de implementar a mesma lógica, com uma instrução elseif, que permite verificar uma condição adicional antes de retornar ao bloco else. A sintaxe do bloco elseif é idêntica à sintaxe do bloco if. Portanto, para testar o servidor com problema com a instrução elseif, execute o código da Listagem 4.5.



Listagem 4.5. Usando o bloco elseif



if (-not (Test-Connection -ComputerName $servers[0] -Quiet -Count 1)) { 
   Write-Error -Message "The server $servers[0] is not responding!"
} elseif ($servers[0] –eq $problemServer) 
   Write-Error -Message "The server $servers[0] does not have the right file!"
} else {
   Get-Content -Path "\\$servers[0]\c$\App_configuration.txt"
}
----
      
      





Observe que não adicionamos apenas uma instrução elseif, mas, ao mesmo tempo, alteramos a lógica do código. Agora podemos verificar se o servidor está offline usando o operador –not. Então, depois de determinar o status da rede do servidor, verificamos se ele é problemático. Caso contrário, usamos a instrução else para acionar o comportamento de checkout de arquivo padrão. Como você pode ver, existem várias maneiras de estruturar seu código dessa maneira. O importante é que o código funcione e seja legível para uma pessoa de fora, seja seu colega vendo pela primeira vez, ou você mesmo algum tempo depois de escrevê-lo.



Você pode encadear quantas instruções elseif desejar para acomodar uma ampla variedade de circunstâncias. No entanto, as instruções elseif são mutuamente exclusivas: quando um dos elseifs é avaliado como True, o PowerShell apenas executa seu código e não verifica outros casos. Na Listagem 4.5, isso não causou nenhum problema, já que você só precisava testar o servidor para "problemas" depois de verificar o funcionamento, mas no futuro eu o aconselho a manter esse recurso em mente.



As instruções if, else e elseif são ótimas para implementar respostas de código a perguntas simples de sim / não. Na próxima seção, você aprenderá como trabalhar com lógicas mais complexas.



Declaração de mudança



Vamos ajustar nosso exemplo um pouco. Digamos que temos cinco servidores e, em cada servidor, o caminho para o arquivo necessário é diferente. Com base no que você sabe agora, será necessário criar uma instrução elseif separada para cada servidor. Isso funcionará, mas existe um método mais conveniente.



Observe que agora trabalharemos com um tipo diferente de condição. Se antes precisávamos de respostas a perguntas como "sim / não", agora queremos obter o significado específico de uma coisa. É um servidor SRV1? SRV2? Etc. Se você estivesse trabalhando apenas com um ou dois valores específicos, uma instrução if funcionaria, mas, neste caso, uma instrução switch funciona muito melhor.



A instrução switch permite que você execute diferentes partes do código, dependendo de algum valor. Consiste na palavra-chave switch seguida por uma expressão entre parênteses. Dentro do bloco switch está uma série de instruções, estruturadas assim: primeiro você especifica o valor, seguido por um conjunto de chaves contendo o bloco de código e, finalmente, o bloco padrão, conforme mostrado na Listagem 4.6.



Listagem 4.6. Modelo de declaração de mudança



switch () {
    {
      # 
   }
    {
   }
   default {
     # ,     
   }
}
      
      





Uma instrução switch pode conter um número quase ilimitado de valores. Se a expressão for avaliada como um valor, o código correspondente dentro do bloco será executado. O importante é que, ao contrário de elseif, depois de executar um bloco de código, o PowerShell continuará a verificar o restante das condições, a menos que indicado de outra forma. Se nenhum dos valores corresponder, o PowerShell executará o código no bloco padrão. Para interromper a iteração sobre as condições em uma instrução switch, use a palavra-chave break no final do bloco de código, conforme mostrado na Listagem 4.7.



Listagem 4.7. Usando a palavra-chave break em uma instrução switch



switch () {
    {
      # 
      break
   }
----
      
      





A palavra-chave break permite que você crie condições em uma instrução switch mutuamente exclusivas. Vamos voltar ao nosso exemplo com cinco servidores e o mesmo arquivo com caminhos diferentes. Você sabe que o servidor com o qual está trabalhando só pode ter um valor (ou seja, não pode ser nomeado SRV1 e SRV2 ao mesmo tempo), portanto, é necessário usar instruções break. Seu script deve ser semelhante ao mostrado na Listagem 4.8.



Listagem 4.8. Verificando vários servidores com uma instrução switch



$currentServer = $servers[0]
switch ($currentServer) {
   $servers[0] {
      # Check if server is online and get content at SRV1 path.
      break
   }
   $servers[1] {
      ## Check if server is online and get content at SRV2 path.
      break
   }
   $servers[2] {
      ## Check if server is online and get content at SRV3 path.
      break
   }
----
      
      





Você pode reescrever este código usando apenas as instruções if e elseif (e eu realmente recomendo que você tente isso!). Em qualquer caso, qualquer que seja o método escolhido, você precisa da mesma estrutura para todos os servidores da lista, o que significa que seu cenário será bem longo - imagine testar quinhentos servidores em vez de cinco. Na próxima seção, você aprenderá como se livrar desse problema usando uma das estruturas de fluxo de controle mais fundamentais - um loop.



Usando loops



Há uma boa regra prática para o trabalho com o computador: não se repita (DRY). Se você estiver fazendo o mesmo trabalho, é provável que haja uma maneira de automatizá-lo. O mesmo ocorre com a codificação: se você usar as mesmas linhas continuamente, provavelmente haverá uma solução melhor.



Uma maneira de evitar repetições é usar loops. Um loop permite que você execute código repetidamente até que alguma condição especificada mude. A condição de parada pode iniciar o loop um número especificado de vezes, até que algum valor booleano mude, ou definir que o loop seja executado indefinidamente. Chamaremos cada passagem do loop de iteração.



O PowerShell oferece cinco tipos de loops: foreach, for, do / while, do / until e while. Nesta seção, discutiremos cada tipo de loop, destacaremos seus recursos exclusivos e destacaremos as melhores situações para usá-los.



Sobre o autor



Adam Bertram é um experiente especialista em TI e negócios na Internet com 20 anos de experiência. Empreendedor, Influenciador de TI, MVP da Microsoft, Blogger, Gerente de Treinamento e Autor de Marketing de Conteúdo, trabalhando com várias empresas de TI. Adam também fundou a popular plataforma TechSnips para desenvolver as habilidades dos profissionais de TI (techsnips.io).



Mais detalhes sobre o livro podem ser encontrados no site da editora

» Índice

» Trecho



Para Habitors, desconto de 25% no cupom - PowerShell



Mediante o pagamento da versão em papel do livro, um e-book é enviado para o e-mail.



All Articles