Automatizar Tarefas com PowerShell PSake: Um Passo a Passo

Então você aprendeu como automatizar tarefas com um script PowerShell.
Isso é ótimo! Mas agora você tem uma bagunça desorganizada de scripts e módulos com uma mistura de execuções manuais de script, tarefas agendadas e muito mais. É hora de trazer alguma ordem para o caos e implementar a engine de orquestração de automação conhecida como PowerShell PSake.

O PSake é uma engine de orquestração escrita como um módulo PowerShell que adiciona ordem aos seus scripts e oferece controle total sobre o que é executado quando e em quais condições. Embora o PSake seja uma ferramenta de automação de compilação e seu caso de uso principal seja em scripts de compilação (geralmente executados por um servidor de compilação em cenários de automação de lançamento), ele é geralmente ignorado em cenários de scripting diários. Vamos mudar isso.

Neste tutorial, você aprenderá como o PSake funciona, juntamente com ótimos exemplos para você colocar em prática hoje mesmo!

Pré-requisitos

Este artigo será um tutorial que espera que você acompanhe. Se você deseja seguir exatamente como abordado, certifique-se de ter:

  • Windows PowerShell 3+. O tutorial usa o Windows PowerShell v5.1
  • O arquivo zip do PSake do Github. Este tutorial usa a versão 4.9.0.

Configurando o Módulo PSake

Supondo que você tenha o projeto PSake do GitHub em sua máquina local, você primeiro precisará passar por algumas etapas para configurá-lo.

  1. Extraia o arquivo zip do PSake baixado do GitHub.
  2. Mova a pasta src para dentro do conteúdo extraído do arquivo ZIP para um caminho abaixo de $env:PSModulePath para garantir que o PowerShell saiba do novo módulo.
  3. Renomeie a pasta src para PSake.
  4. Agora execute Get-Module PSake -ListAvailable para confirmar se ele aparece. Se você não receber um erro, está pronto para prosseguir.

Relacionado: Compreensão e Construção de Módulos PowerShell

Criando um Script Básico de PSake do PowerShell

Para entender o PSake, você precisa construir algo. Vamos criar um script PSake simples para ver o que ele pode fazer.

  1. Crie um script chamado psakefile.ps1 com uma única tarefa. No mínimo, uma tarefa deve ter um nome e um bloco de ação. O nome psakefile.ps1 não é obrigatório, mas é o nome padrão esperado pelo mecanismo.

A PSake task in its basic form is very similar to a PowerShell function:
a container for one or more commands that, when performed together, achieve a certain goal. These commands go into a script block that is passed to the Action parameter. A task has many advantages over a function. You will learn about these advantages as you read along.

Abaixo está um exemplo de um psakefile.ps1 com uma tarefa um tanto simples:

task HelloWorld -Action {
    Write-Host '*** Hello World ***' -ForegroundColor Yellow
}

2. Agora que você construiu o arquivo PSake, pode chamá-lo de um console do PowerShell com o comando Invoke-PSake e passar o nome da tarefa como um valor para o parâmetro TaskList .

Invoke-PSake é o mecanismo de execução para o PSake. Este comando aciona tarefas definidas no psakefile.ps1. Você passa um nome de tarefa ou uma lista de tarefas separadas por vírgulas para o parâmetro TaskList. Se estiver executando várias tarefas, cada tarefa será executada na ordem em que você as passou para TaskList, independentemente de sua localização no psakefile.ps1.

Abaixo está como você pode acionar a tarefa HelloWorld:

Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList 'HelloWorld'

Desde que você mantenha o nome psakefile.ps1 e, dado que você defina o console para a pasta onde ele está localizado, você pode omitir o parâmetro BuildFile e seu valor.

  1. Executar Invoke-PSake irá mostrar a saída do PSake no console. Quando você executa as tarefas em psakefile.ps1, você verá uma saída semelhante ao que você vê abaixo.
Psake script output

A saída consiste nestes componentes:

  1. Os detalhes sobre a versão do PSake.
  2. O nome de cada tarefa de construção logo antes de ser executada (o PSake considera cada tarefa como uma tarefa de construção). No exemplo: Executando HelloWorld em ciano.
  3. Qualquer saída que a tarefa tenha produzido. No exemplo: Hello World em amarelo.
  4. Mensagem de sucesso/falha. No exemplo: psake teve êxito… em verde.
  5. Resumo do tempo (nomeado Relatório de Tempo de Construção) com a duração de cada tarefa, além da duração total do script inteiro.

Instalando SQL com o PSake

Na seção anterior, você não fez muito além de invocar um script fictício do PSake. Agora, construa sobre esse conhecimento e crie um script do PSake que instala o SQL!

Neste exemplo, você vai criar um script PSake que:

  1. Valida o espaço livre em disco em uma máquina.
  2. Faz o download de um arquivo ZIP do SQL de um repositório local.
  3. Extrai o arquivo ZIP.
  4. Executa a instalação no disco C ou D (o que estiver disponível).

Vamos ver a seguir como podemos usar o PSake para essa tarefa.

Projetando os Blocos de Construção

O PSake trata-se de orquestrar tarefas. Cada tarefa deve ter um nome único e idealmente deve executar uma única operação atômica, como uma função do PowerShell. Usando esse conceito, você pode descrever as etapas abaixo para construir uma tarefa para cada uma.

  1. ValidateDiskSpace
  2. DownloadSql
  3. ExtractSql
  4. InstallSqlDriveC
  5. InstallSqlDriveD

Neste estágio, você não está realmente construindo o código para fazer nada; você está apenas estruturando as tarefas e criando o arquivo PSake. Você vai notar as referências Write-Host nas tarefas abaixo; você vai adicionar mais coisas às tarefas depois.

Você sempre deve usar o parâmetro Description para cada tarefa. O parâmetro Description fornece mais informações sobre cada tarefa tanto ao executar as tarefas quanto ao revisar o código.

task ValidateDiskSpace -Description 'Validate Disk Free Space' -Action {
	
	Write-Host "`n   *** Checking disk free space ***`n" -ForegroundColor Yellow
	
}

task DownloadSql -Description 'Download SQL Setup' -Action {
	
	Write-Host "`n   *** Downloading SQL Setup from LAN ***`n" -ForegroundColor Yellow
	
}

task ExtractSql -Description 'Extract SQL Setup' -Action {
	
	Write-Host "`n   *** Extracting SQL Setup files ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveC -Description 'Install SQL on C:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow

}

task InstallSqlDriveD -Description 'Install SQL on D:' -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

Definindo a Ordem de Execução das Tarefas

Agora você tem um arquivo PSake que contém um conjunto de tarefas. Neste ponto, você pode executar todas as tarefas de uma vez ou optar por executar apenas algumas delas com o comando Invoke-PSake.

Você pode chamar algumas (ou todas as tarefas) usando `Invoke-PSake` e o parâmetro `TaskList` como fez anteriormente no exemplo simples. Se você tiver mais de uma tarefa para invocar, crie um array e defina o nome de cada tarefa como um item, conforme mostrado abaixo.

Invoke-PSake executará cada tarefa na ordem definida no array.

$taskList = @()

$taskList += 'ValidateDiskSpace'
$taskList += 'DownloadSql'
$taskList += 'ExtractSql'
$taskList += 'InstallSqlDriveC'
$taskList += 'InstallSqlDriveD'

Invoke-PSake -TaskList $taskList

Ao executar o código acima, você deve obter um resultado como o seguinte:

PSake script output

Adicionando uma Pré-condição

Talvez você precise executar alguma ação apenas se uma determinada condição for atendida. No exemplo do script de instalação do SQL deste tutorial, por exemplo, talvez você precise testar se o volume onde você armazena o instalador está disponível antes de executar a tarefa para invocar o referido instalador.

Você pode usar o parâmetro `PreCondition` para executar um trecho de código que retorne um valor booleano True ou False que dita se essa tarefa é executada ou não.

Observe no exemplo abaixo as variáveis $installSqlOn_C_Drive e $installSqlOn_D_Drive. Quando o `Invoke-PSake` invoca este script, essas variáveis conterão um valor True ou False dependendo se um volume C ou D existe.

Em cada linha de `task`, você pode então ver que cada tarefa tem um parâmetro scriptblock `PreCondition` que contém o valor dessas variáveis. No momento da execução, ou a tarefa `InstallSqlDriveC` ou a tarefa `InstallSqlDriveD` será executada, dependendo dessas variáveis.

$installSqlOn_C_Drive = (Test-Path -Path 'C:') -and (-not (Test-Path -Path 'D:'))
$installSqlOn_D_Drive = (-not (Test-Path -Path 'C:')) -and (Test-Path -Path 'D:')

task InstallSqlDriveC -Description 'Install SQL on C:' -PreCondition { $installSqlOn_C_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on C drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

Parâmetros da Tarefa

Além do Ação e Descrição uma tarefa também suporta estes parâmetros:

  • PreCondicao – Bloco de script que retorna um valor booleano. Se Falso, a tarefa específica é ignorada. (Um exemplo de uso é mostrado acima).
  • PosCondicao Etapa de validação. Um bloco de script que retorna um valor booleano. Falso significa que a validação falhou, fazendo com que todo o script pare.
  • PreAcao – Um bloco de script para executar antes da tarefa.
  • PosAcao Um bloco de script para executar logo após a tarefa ter sido concluída com sucesso.
  • ContinuarEmErro Parâmetro de troca. Se usado, quaisquer erros que possam ocorrer durante a execução da tarefa não farão com que todo o script quebre.
  • Depende O nome de uma tarefa (ou uma lista de nomes de tarefas) que deve ser executada antes da tarefa atual ser executada. O PSake usará essa informação para executar as dependências das tarefas na ordem correta. Por exemplo, se a tarefa A depende da tarefa B, então o motor do PSake executará B antes de A.

À primeira vista, o mecanismo de dependência parece uma boa ideia. Ajuda a definir tarefas em uma ordem lógica. No entanto, usar o parâmetro Depende une diferentes tarefas, tornando difícil testá-las independentemente mais tarde. Mas, uma vez que o usuário pode definir explicitamente a ordem de execução das tarefas e passar essa ordem ao chamar o arquivo PSake → o uso do parâmetro Depende pode ser evitado completamente.

Vamos ver a seguir um exemplo de uso para alguns desses parâmetros da tarefa:

Adicionando PreAction e PostCondition

Usando a tarefa InstallSqlDriveD do exemplo acima como ponto de partida, talvez você tenha uma solicitação adicional para a instalação.

Talvez você precise registrar os horários em que a instalação começa e termina. Você precisa registrar esses horários em duas variáveis de ambiente chamadas SqlSetupStartDate e SqlSetupEndDate. Em segundo lugar, após a conclusão da instalação, você precisa verificar se a pasta D:\TempSqlFiles não existe.

Felizmente, os parâmetros de tarefa PSake PreAction, PostAction e PostCondition (respectivamente) atendem exatamente a esses novos requisitos. Abaixo está um exemplo de como pode ser feito:

task InstallSqlDriveD -Description 'Install SQL on D:' -PreAction {

     Write-Host '*** Writing SQL install start time to env. var. SqlSetupStartDate ***' -ForegroundColor Yellow
     $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupStartDate',$date,'Machine')

 } -PreCondition { 

     $installSqlOn_D_Drive

 } -Action {  
  
     Write-Host '*** Installing SQL Server on D drive... please wait... ***' -ForegroundColor Yellow 

} -PostAction {     

    Write-Host '*** Writing SQL install end time to env. var. SqlSetupEndDate ***' -ForegroundColor Yellow     
    $date = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
[Environment]::SetEnvironmentVariable('SqlSetupEndDate',$date,'Machine') 

} -PostCondition { 
    
Write-Host '*** Verifying temp files deleted ***' -ForegroundColor Yellow
     # caso a pasta exista, isso retornará Falso, fazendo com que todo o script pare
     (-not (Test-Path -Path 'D:\TempSqlFiles'))

 }

Executando Scripts PSake em Testes Pester

Onde você pode invocar um script do PowerShell, você pode invocar um arquivo PSake. Se você estiver criando testes de infraestrutura com Pester, pode invocar o PSake dentro dos testes.

Relacionado: Escrevendo Testes Pester para PowerShell

Por exemplo, talvez você tenha um teste do Pester para confirmar se o arquivo ZIP de configuração do SQL existe em uma pasta depois de executar a tarefa DownloadSql. Nesse caso, você constrói um teste simples do Pester e invoca a tarefa DownloadSql dentro do teste e verifica se o arquivo ZIP está lá logo após sua execução.

Describe 'SQL install with PSake' {

    It 'Downloads Sql files' {

        $setup = 'C:\Downloads\SqlSetup.zip'

        if(Test-Path -Path $setup)
        {
            Remove-Item -Path $setup
        }

        # a única tarefa em teste aqui é DownloadSql
        Invoke-PSake -BuildFile C:\Work\psakefile.ps1 -TaskList DownloadSql
        
        $setup | Should -Exist
    }
}

Passando Parâmetros para Tarefas

Ao começar a usar o PSake, você pode querer parametrizar algumas das tarefas. Tipicamente, com funções e scripts do PowerShell, você passará vários parâmetros nomeados para a função/script; o PSake é diferente.

Para passar parâmetros para arquivos do PSake, você pode usar um bloco Properties que define pares de chave/valor, os quais o PSake então disponibiliza dentro de cada tarefa no arquivo.

Certifique-se de definir o bloco Properties no topo do arquivo PSake. Todas as operações do PSake são lidas de cima para baixo.

Por exemplo, para passar as variáveis dinâmicas SqlYear e SqlVersion para cada tarefa no arquivo PSake, você pode defini-las como mostrado abaixo.

Properties {
    $SqlYear = '2017'
    $SqlVersion = '14.0'
}

task -Name DownloadSql -Action {
    
    Write-Host "SQL version to install: SQL $SqlYear (version $SqlVersion)"

}

Quando você então invoca o arquivo PSake com Invoke-PSake, você veria a seguinte saída. Observe que as variáveis $SqlYear e $SqlVersion foram expandidas com os valores definidos no bloco Properties.

psake version 4.9.1
Copyright (c) 2010-2018 James Kovacs & Contributors

Executing DownloadSql
SQL version to install: SQL 2017 (version 14.0)

psake succeeded executing C:\Work\PSakefile.ps1

--------------------------------------------------
Build Time Report
--------------------------------------------------

Name        Duration
----        --------
DownloadSql 00:00:00
------      --------
Total:      00:00:00

Usando o Parâmetro Properties

Se você preferir passar parâmetros para uma tarefa via um parâmetro tradicional, o PSake pode ajudar. Ainda é necessário manter o bloco Properties no topo do psakefile.ps1 como no exemplo acima, mas o PSake permite que você substitua os valores.

Para fazer isso, defina uma hashtable com cada par de chave/valor que você deseja substituir. Em seguida, passe a hashtable para o parâmetro Properties. O motor PSake utilizará os valores na hashtable fornecida em vez daqueles especificados no bloco Properties dentro do script psakefile.ps1.

Observe as diferenças na sintaxe entre o bloco Properties e o parâmetro Properties. No bloco Properties, cada linha é uma variável e, portanto, é prefixada com um cifrão, enquanto o parâmetro Properties é uma hashtable, então cada item é uma chave e escrito sem um cifrão inicial. Outra diferença é que a hashtable é precedida pelo caractere @.

Abaixo, você pode ver um exemplo de uso do parâmetro Properties.

$myNewProperties = @{
    SqlYear = '2019'
    SqlVersion = '15.0'
}

Invoke-PSake -TaskList DownloadSql -Properties $myNewProperties

Modularização de Tarefas PSake: Tarefas como Arquivos

Em algum momento, seu arquivo PSake provavelmente crescerá exponencialmente, especialmente se você precisar orquestrar tarefas de automação grandes. Para garantir que você possa gerenciar todas essas tarefas, você deve focar na modularização ou dividir as tarefas para facilitar o gerenciamento.

Relacionado: Como Sobreviver ao Refatorar um Script PowerShell Infernal

No exemplo deste tutorial, você estava trabalhando com cinco tarefas:

  • ValidateDiskSpace
  • DownloadSql
  • ExtractSql
  • InstallSqlDriveC
  • InstallSqlDriveD

Cada uma dessas tarefas é definida dentro de um único script pssakefile.ps1. Se você antecipar a adição de muitas tarefas ao longo do tempo, você deve dividir essas tarefas em arquivos separados, com cada tarefa dentro, por exemplo, de ValidateDiskSpace.ps1, DownloadSql.ps1, InstallSqlDriveD.ps1, InstallSqlDriveD.ps1, etc.

Por exemplo, InstallSqlDriveD.ps1 conterá apenas este código:

task InstallSqlDriveD -Description 'Install SQL on D:' -PreCondition { $installSqlOn_D_Drive } -Action {
	
	Write-Host "`n   *** Installing SQL Server on D drive ... please wait... ***`n" -ForegroundColor Yellow
	
}

Uma vez que as tarefas são movidas para fora, importe os arquivos para pssakefile.ps1 usando a função Include. Feito isso, o conteúdo de pssakefile.ps1 é reduzido para este código:

$installSqlOn_C_Drive = $true
$installSqlOn_D_Drive = $false

Include "$PSScriptRoot\ValidateDiskSpace.ps1"
Include "$PSScriptRoot\DownloadSql.ps1"
Include "$PSScriptRoot\ExtractSql.ps1"
Include "$PSScriptRoot\InstallSqlOnC.ps1"
Include "$PSScriptRoot\InstallSqlOnD.ps1"

Quando Invoke-PSake aciona o script pssakefile.ps1, Invoke-PSake não sabe ou se importa se as tarefas estão dentro do arquivo psake ou foram importadas pelo método Include.

Próximos Passos

O PSake é um orquestrador de script poderoso que pode ser usado para muitos propósitos: construção de software, CI/CD, implantação de pacotes, criação de instaladores e muito mais. O único limite é sua imaginação. Acostumar-se a construir scripts grandes com o PSake obriga você a pensar em tarefas (blocos de construção de código). O conceito de tarefas aproveita a sintaxe do PowerShell, e ao usar tarefas, você enriquece seu conhecimento existente de linha de comando.

O código que você produz com o PSake se torna mais legível, fácil de manter e mais fácil de testar. Após alguma prática, você verá que dividir seus passos em diferentes tarefas torna-os mais fáceis de criar scripts. A pequena quantidade de trabalho extra que isso exige compensa a longo prazo.

Onde você vê o PSake se encaixando em seus projetos de trabalho?

Source:
https://adamtheautomator.com/powershell-psake/