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 de script manuais, tarefas agendadas e muito mais. É hora de trazer alguma ordem para o caos e implementar o mecanismo de orquestração de automação conhecido como PowerShell PSake.

O PSake é um mecanismo de orquestração escrito como um módulo PowerShell que adiciona ordem aos seus scripts e dá a você total controle sobre o que é executado quando e em quais condições. Embora o PSake seja uma ferramenta de automação de build e seu caso de uso principal seja em scripts de build (geralmente executados por um servidor de build em cenários de automação de lançamento), geralmente é negligenciado em cenários de scripting do dia a dia. Vamos mudar isso.

Neste tutorial, você vai 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ê siga junto. Se você quiser seguir exatamente como coberto, 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á seguir alguns passos para configurá-lo.

  1. Extraia o arquivo zip do PSake baixado do GitHub.
  2. Mova a pasta src para dentro do conteúdo do arquivo ZIP extraído 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, estará pronto para continuar.

Relacionado: Entendendo e Construindo Módulos do PowerShell

Criando um Script Básico PSake do PowerShell

Para entender o PSake, você precisa construir algo. Vamos construir 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, você 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 arquivo psakefile.ps1. Você passa um nome de tarefa ou uma lista de tarefas separadas por vírgula 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 arquivo psakefile.ps1.

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

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

Enquanto você mantiver o nome psakefile.ps1 e definir o console para a pasta onde ele está localizado, você pode omitir o parâmetro BuildFile e seu valor.

  1. A execução de Invoke-PSake mostrará a saída do PSake no console. Quando você executar as tarefas em psakefile.ps1, verá uma saída semelhante ao que vê abaixo.
Psake script output

A saída consiste nesses componentes:

  1. 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 succeeded… 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 PSake

Na seção anterior, você não fez muito além de invocar um script PSake falso. Agora, baseie-se nesse conhecimento e crie um script PSake que instale o SQL!

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

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

Vamos ver a seguir como podemos aproveitar o PSake para o trabalho.

Projetando os Blocos de Construção

O PSake trata-se de orquestrar tarefas. Cada tarefa deve ter seu próprio nome único e idealmente deve realizar uma única operação atômica, como uma função do PowerShell. Usando este 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á simplesmente estruturando as tarefas e criando o arquivo PSake. Você vai perceber as referências Write-Host nas tarefas abaixo; você irá adicionar mais tarde às tarefas.

Você deve sempre 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ê deverá obter um resultado como o seguinte:

PSake script output

Adicionando uma PreCondição

Talvez você precise realizar alguma ação apenas se uma determinada condição for atendida. No script de instalação do SQL do exemplo 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 booleano True ou False que dita se essa tarefa será executada ou não.

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

Em cada linha de task, você pode ver que cada tarefa possui 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 Action e Description, uma tarefa também suporta esses parâmetros:

  • PreCondition – Bloco de script que retorna um valor booleano. Em Falso, a tarefa específica é pulada. (Um exemplo de uso é mostrado acima).
  • PostCondition Etapa de validação. Um bloco de script que retorna um valor booleano. Falso significa que a validação falhou e faz com que todo o script pare.
  • PreAction – Um bloco de script para ser executado antes da tarefa.
  • PostAction Um bloco de script para ser executado imediatamente após a conclusão bem-sucedida da tarefa.
  • ContinueOnError Parâmetro de comutação. Se usado, quaisquer erros que possam ocorrer durante a execução da tarefa não farão com que todo o script pare.
  • Depends O nome de uma tarefa (ou uma lista de nomes de tarefas) que deve ser executada antes que a tarefa atual seja executada. O PSake usará essas informações para executar as dependências de tarefas na ordem correta. Por exemplo, se a tarefa A depender da tarefa B, então o mecanismo do PSake executará B antes de A.

No início, o mecanismo de dependência parece uma boa ideia. Isso ajuda a definir tarefas em uma ordem lógica. No entanto, usando o parâmetro Depends, diferentes tarefas são interligadas, tornando mais difícil testá-las de forma independente mais tarde. Mas, como 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 Depends pode ser evitado completamente.

Vamos ver a seguir um exemplo de uso para alguns desses parâmetros de 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. Segundo, 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 quer que você possa 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 Pester para confirmar que o arquivo ZIP de configuração do SQL existe em uma pasta depois de executar a tarefa DownloadSql. Nesse caso, você cria um teste Pester simples e invoca a tarefa DownloadSql dentro do teste e verifica o arquivo ZIP imediatamente após ele ser executado.

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. Normalmente, 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 PSake, você pode usar um bloco Properties que define pares chave/valor, os quais o PSake disponibiliza dentro de cada tarefa no arquivo.

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

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

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

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

}

Quando você invoca o arquivo PSake com Invoke-PSake, você verá 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 preferir passar parâmetros para uma tarefa através de 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 um dos pares de chave/valor que você gostaria de substituir. Em seguida, passe a hashtable para o parâmetro Properties. O motor PSake usará os valores na hashtable passada sobre aqueles especificados no bloco Properties dentro do script psakefile.ps1.

Observe as diferenças de 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 grandes tarefas de automação. 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 do PowerShell do Inferno

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ê antecipa a adição de muitas tarefas ao longo do tempo, 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
	
}

Depois de mover as tarefas, 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 nem se importa se as tarefas estão dentro do arquivo pssake ou foram importadas pelo método Include.

Próximos Passos

O PSake é um orquestrador de scripts 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 é a sua imaginação. Se acostumar a construir scripts grandes com o PSake faz com que você pense 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 mais fácil escrevê-los. A pequena quantidade de trabalho extra que isso leva se paga a longo prazo.

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

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