fbpx

Automatizando backup no Postgres com PowerShell

Automatizando backup no Postgres com PowerShell

👊😎 Saudações, galera!

Estou trabalhando em um projeto full-stack em que o SGBD Posgres está sendo executado em um servidor Windows Server.

É um sistema multitentant, ou seja, vários clientes, em que cada um deles possui uma base de dados.

Obviamente, precisamos fazer o backup de cada uma dessas bases de dados, mantendo cada cópia de segurança em um arquivo. Assim, criei um script integrando diversas ferramentas com o objetivo de automatizar essa operação. Vejamos:

  • PowerShell: interface de linha de comando destinada a administradores de sistemas, além de ser uma poderosa linguagem de scripts;
  • pg_dump: utilitário de linha de comando do Postgres para criar backup;
  • Agendador de tarefas: feramenta do Windows que permite agendar a execução periódica de programas e scripts.

1 – Verificando o PowerShell

A versão do PowerShell que usei para fazer esse script é a 7.x. Por se tratar de um script simples, no contexto do PowerShell, que não usa nada específico da versão, deve funcionar também na versão antiga, Windows PowerShell 5.x.

Ao abrir o console do PowerShell, será exibida a versão atual. Para saber mais informações, digite o comando Get-Host:

2 – Verificando o Postgres

Para verificar a versão do Postgres, tenha certeza de que o serviço dele está ativo. Depois, basta digitar o comando pqsl –version.

3 – Política de Execução do PowerShell

A política de execução são regras do PowerShell usadas para controlar a execução de arquivos .ps1 (scripts). Elas não impedem a execução de comandos interativos no console — apenas scripts e arquivos de configuração.

Digite o comando Get-ExecutionPolicy para verificar a política atual.

Essas são as políticas de execução do PowerShell.

PolíticaDescrição
Restricted🚫 Não permite execução de scripts. (Padrão no Windows PowerShell)
AllSigned✅ Permite scripts assinados por um editor confiável.
RemoteSigned✅ Scripts locais podem ser executados. Scripts baixados precisam ser assinados.
Unrestricted⚠️ Permite qualquer script, mas alerta ao executar scripts baixados.
Bypass🔓 Nenhuma restrição. Nem alertas são exibidos.
Undefined❓ Não há política definida — herda de políticas superiores (ex: GPO).

Para a execução do script de backup proposto aqui, vamos usar Unrestricted. Para isso, use o comando Set-ExecutionPolicy Unrestricted – para o comando ser executado, é necessário executar o console do PowerShell como Administrador.

4 – Enfim, o Script!

O script a seguir usa o utilitário pg_dump do próprio Postgres para fazer backup dos bancos de dados.

#caminho do binário do posgres
$pgBinPath = "$env:ProgramFiles\PostgreSQL\17\bin"

# Caminho para salvar os backups
$backupPath = "C:\_backup"
# cria a pasta, caso não exista
New-Item -ItemType Directory -Force -Path $backupPath | Out-Null

# Credenciais do Banco de dados
$bdHost = "localhost"
$bdPort = 5432
$bdUser = "postgres"
$bdPassword = "postdba"

# Define uma variável de ambiente para evitar prompt a cada chamada do comando pg_dump
$env:PGPASSWORD = $bdPassword

# conecta-se ao postgres para obter os nomes dos bancos, exceto os padrões
$dbList = & "$pgBinPath\psql.exe" -h $bdHost -p $bdPort -U $bdUser -d postgres -t -c "SELECT datname FROM pg_database WHERE datistemplate = false AND datname NOT IN ('postgres');"

# Limpa espaços e divide em array
$dbNames = $dbList -split "`n" | ForEach-Object { $_.Trim() } | Where-Object { $_ }

# itera sobre o array de nomes, executando o pg_dump em cada um deles
foreach ($db in $dbNames) {
    $date = Get-Date -Format "yyyyMMdd_HHmmss"
    $fileName = "$backupPath\$db-$date.sql"
    & "$pgBinPath\pg_dump.exe" -h $bdHost -p $bdPort -U $bdUser -F p -d $db -f $fileName
    Write-Host "Backup feito para a base: $db"
}

#exclui os arquivos gerados há mais de 2 dias
$targetDate = (Get-Date).AddDays(-2).Date
 Get-ChildItem -Path $backupPath -File |
    Where-Object { $_.LastWriteTime.Date -eq $targetDate } | Remove-Item

# Limpa variável de ambiente
Remove-Item Env:\PGPASSWORD

Salve o script em qualquer pasta, com o tipo .ps1 (PowerShell Script).

Veja aqui alguns comandlets do PowerShell que são extremamente úteis para desenvolvedores.

5 – Agendando execução automática

No Windows, o aplicativo Agendador de Tarefas (Task Scheduler) é o responsável por permitir execuções automáticas de processos, aplicações e scripts.

Os gatilhos de execução podem ser horários determinados ou até mesmo eventos do Sistema Operacional.

No nosso caso, vamos criar uma tarefa para executar o script de backup duas vezes ao dia.

1 – Abra o gerenciador de tarefas e clique em Create Task (Criar Tarefa)

2 – Coloque um nome para a tarefa. A descrição é opcional. Em Security Options (Opções de Segurança), selecione se a tarefa será executada somente quanto o usuário estiver logado ou não.

3 – Clique na Aba Trigger (Gatilho), e depois, clique no botão New Trigger,

4 – Depois, precisamos configurar o gatilho para que seja executado diariamente. Note que você pode configurar vários gatilhos, dependendo de com foi a decisão de execução.

No exemplo a seguir, configuramos um gatilho diário, com uma data específica para iniciar.

Depois de clicar em OK, vamos clicar na aba Actions e depois no botão New.

Agora vamos configurar a ação, ou seja, o que será executado. No nosso caso, será um script PowerShell, então, veja a figura a seguir:

  • Action: Start a program
  • Program/Script: o executável do PowerShell
  • Ad arguments: o script ps1 que será executado.

Depois disso, clique em OK.

Agora que a tarefa foi criada, você pode executá-la para testar se tudo está OK. Para isso, volte no início, procure sua tarefa na lista de tarefas, clique com o botão direito nela e clique em Run (Executar).

6 – Protegendo a senha com o arquivo pgpass.conf

Uma recomendação de segurança é não expor a senha do Postgres diretamente no Script. Para isso, podemos usar o arquivo pgpass.conf.

Quando usamos um comando do Postgres, como o pg_dump ou pg_restore, ele procura automaticamente as senhas necessárias nesse arquivo.

No Windows, por padrão, esse arquivo fica em %APPDATA%\postgresql\pgpass.conf. O APPDATA é uma variável de ambiente que aponta para a pasta <NomeDeUsuário>\AppData\Roaming\postgresql\pgpass.conf

No Linux esse arquivo fica em ~/.pgpass

Caso o arquivo não exista, ele pode ser criado.

O arquivo pgpass deve ter a seguinte estrutura:

host:port:database:username:password

É possível configurar várias linhas, ou seja, vários bancos de dados. Por exemplo:

localhost:5432:empresa01:admin:123456
localhost:5432:empresa02:admin:999999
192.168.0.122:5433:empresaXYZ:admin:admin123

Também podemos usar caracteres curinga. No exemplo a seguir, definimos que podemos nos conectar a todas as bases de dados com o mesmo nome de usuário e senha:

localhost:5432:*:admin:senha_mestre

Uma das vantagens de usar o pgpass.conf, além de não expor a senha diretamente no script, é o fato de que você pode determinar nele quais bancos de dados serão feitos o backup. No meu caso, escolhi duas bases de dados locais, então meu arquivo ficou assim:

localhost:5432:tenant_002:postgres:postdba
localhost:5432:bookstore:postgres:postdba

Aqui convém destacar que o arquivo pgpass.conf é padrão do Postgres, mas poderíamos usar um outro arquivo de senhas, segundo um padrão que nós mesmos definíssemos. Poderíamos, por exemplo, usar um arquivo em formato json.

7 – Script adaptado para o arquivo pgpass.conf

Como não estamos mais criando uma variável de ambiente configurada em tempo de execução do script, precisamos adaptá-lo. Veja como ele ficou no código comentado a seguir:

#caminho do binário do posgres
$pgBinPath = "$env:ProgramFiles\PostgreSQL\17\bin"

# Caminho para salvar os backups
$backupPath = "C:\_backup"
# cria a pasta, caso não exista
New-Item -ItemType Directory -Force -Path $backupPath | Out-Null

# Pega as linhas do pgpass.conf
$lines = Get-Content "$env:APPDATA\postgresql\pgpass.conf"

# cria uma lista de objeto customizado com as configurações de cada linha
$entries = $lines | ForEach-Object {
    # a separação das partes é ao encontrar dois pontos (:)
    $parts = $_ -split ":"
    # pegamos todas as partes para criar a lista, mas poderia ser somente algumas
    [PSCustomObject]@{
        Host     = $parts[0]
        Port     = $parts[1]
        Database = $parts[2]
        Username = $parts[3]
        Password = $parts[4]
    }
}

# itera sobre a lista, executando o pg_dump para cada banco de dados
foreach ($db in $entries){
    # pega a data atual
    $date = Get-Date -Format "yyyyMMdd_HHmmss"
    # cria o nome do arquivo
    $fileName = "$backupPath\$($db.Database)-$date.sql"
    # faz o pg_dump
    & "$pgBinPath\pg_dump.exe" -h $db.Host -p $db.Port -U $db.Username -F p -d $db.Database -f $fileName
}

#exclui os arquivos gerados há mais de 2 dias
$targetDate = (Get-Date).AddDays(-2).Date
 Get-ChildItem -Path $backupPath -File |
    Where-Object { $_.LastWriteTime.Date -eq $targetDate } | Remove-Item

Conclusão

De fato, poderíamos criar várias tarefas e vários scripts, cada um faria o backup de um base de dados específico, sem a necessidade usar o PowerShell.

Entretanto, gerenciar dezenas de scripts pode se tornar uma tarefa difícil e que toma muito tempo. Sendo assim, a integração com o PowerShell ajuda em muitos cenários, ainda mais considerando o uso do arquivo pgpass.conf, que possibilita determinar as senhas para diversas bases de dados.

👊😎 Espero ter ajudado! Até a próxima!

Jorge Luís Gregório

Jorge Luís Gregório

Professor e entusiasta de tecnologia, estudioso da cultura NERD e fã de quadrinhos, animes e games. Mais um pai de menino, casado com a mulher mais linda da galáxia e cristão convicto. Gosto de ler ficção científica e discutir tecnologia, filmes, seriados, teologia, filosofia e política. Quer falar sobre esses e diversos outros assuntos? Venha comigo!