Gerar um arquivo .BAK do SQL Server via Veeam Backup and Replication

Rodrigo Weber
5 min readFeb 3, 2021

Uma das tarefas mais repetitivas do dia a dia de um DBA é gerar um backup do banco de produção em algum filesystem e após isso, restaurar em ambiente de desenvolvimento (ou stage).

Normalmente é realizado um backup full (ou completo) via Management Studio. Caso tenha dúvida em como realizar esse processo, segue um tutorial bem completo do meu colega de trabalho Mateus de Aviz, clicando aqui.

Algumas situações podem ocorrer quando você utiliza o Veeam Backup and Replication como ferramenta de backup e gera um backup full desse modo (infelizmente elas já ocorreram comigo rsrs):

  • Parar de funcionar o backup do transaction log.
  • Parar de funcionar o backup incremental.

Segundo os universitários especialistas de Veeam a qual tenho acesso (rsrsrs) o Veeam sempre necessita ser dono do backup set (conjunto de mídias) então um backup realizado dessa forma "quebra" a sequencia de backup que o Veeam estava utilizando e ele para de funcionar :)

OBS: A única forma de voltar a funcionar o transaction log ou o backup incremental pelo Veeam Backup and Replication, é executando um backup do tipo Active Full (mais demorado e com maior consumo de disco no repositório) dentro do Veeam.

E como podemos evitar essa situação?

Baseado no meu primeiro artigo, criei um novo script em PowerShell para buscar o último backup (Full ou Diff) de determinado banco de dados dentro do repositório do Veeam e gerar um arquivo .BAK que poderá ser restaurado em qualquer servidor destino :)

PS: Ainda não estamos tratando de um restore PiTR (Point in Time Recovery), isso fica para uma próxima.

Pré-Requisitos

  • Acesso via RDP ao servidor onde está instalado o Veeam Backup and Replication.
  • UAC desabilitada nesse servidor.
  • Versão utilizada: Veeam Backup and Replication 10.0.1.4854
  • Credenciais Utilizadas (para fins de exemplo): dominio\teste
  • O servidor de SQL Server onde a base está hospedada originalmente, deverá ter liberada no firewall as portas 1024 até 1035 TCP.

Vamos ao script:

#Get Elevated Permissions
param([switch]$Elevated)

function Test-Admin {
$currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())
$currentUser.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

if ((Test-Admin) -eq $false) {
if ($elevated) {
# tried to elevate, did not work, aborting
} else {
Start-Process powershell.exe -Verb RunAs -ArgumentList (‘-noprofile -noexit -file “{0}” -elevated’ -f ($myinvocation.MyCommand.Definition))
}
exit
}

###################

function button ($title,$sourceVM, $sourceDB, $targerDirectory) {

###################Load Assembly for creating form & button######

[void][System.Reflection.Assembly]::LoadWithPartialName( “System.Windows.Forms”)
[void][System.Reflection.Assembly]::LoadWithPartialName( “Microsoft.VisualBasic”)

#####Define the form size & placement

$form = New-Object “System.Windows.Forms.Form”;
$form.Width = 600;
$form.Height = 160;
$form.Text = $title;
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen;

##############Define text label1
$textLabel1 = New-Object “System.Windows.Forms.Label”;
$textLabel1.Left = 25;
$textLabel1.Top = 15;

$textLabel1.Text = $sourceVM;

##############Define text label2

$textLabel2 = New-Object “System.Windows.Forms.Label”;
$textLabel2.Left = 25;
$textLabel2.Top = 50;
$textLabel2.Text = $sourceDB;

##############Define text label3

$textLabel3 = New-Object “System.Windows.Forms.Label”;
$textLabel3.Left = 25;
$textLabel3.Top = 85;

$textLabel3.Text = $targerDirectory;

############Define text box1 for input
$textBox1 = New-Object “System.Windows.Forms.TextBox”;
$textBox1.Left = 150;
$textBox1.Top = 10;
$textBox1.width = 280;

############Define text box2 for input

$textBox2 = New-Object “System.Windows.Forms.TextBox”;
$textBox2.Left = 150;
$textBox2.Top = 50;
$textBox2.width = 280;

############Define text box3 for input

$textBox3 = New-Object “System.Windows.Forms.TextBox”;
$textBox3.Left = 150;
$textBox3.Top = 90;
$textBox3.width = 280;

#############Define default values for the input boxes
$defaultValue = “”
$textBox1.Text = $defaultValue;
$textBox2.Text = $defaultValue;
$textBox3.Text = “\\discocompartilhado\pasta\”;

#############define OK button
$button = New-Object “System.Windows.Forms.Button”;
$button.Left = 460;
$button.Top = 90;
$button.Width = 100;
$button.Text = “Bora”;

############# This is when you have to close the form after getting values
$eventHandler = [System.EventHandler]{
$textBox1.Text;
$textBox2.Text;
$textBox3.Text;
$form.Close();};

$button.Add_Click($eventHandler) ;

#############Add controls to all the above objects defined
$form.Controls.Add($button);
$form.Controls.Add($textLabel1);
$form.Controls.Add($textLabel2);
$form.Controls.Add($textLabel3);
$form.Controls.Add($textBox1);
$form.Controls.Add($textBox2);
$form.Controls.Add($textBox3);
$ret = $form.ShowDialog();

#################return values

return $textBox1.Text, $textBox2.Text, $textBox3.Text
}

$return= button “Veeam Backup to SQL .BAK File” “Servidor de Origem” “Banco de dados” “Diretorio de Destino”

#Below variables will get the values that had been entered by the user

$return[0]
$return[1]
$return[2]

#################Variables are gonna used to session on Veeam Backup and Replication
$BackupSourceVM = $return[0]
$BackupSourceDB = $return[1]
$BackuptargetDirectory = $return[2]

$data = (Get-Date -Format yyyMMdd)

#THIS IS WHERE THE SCRIPT ACTUALLY STARTS WORKING
Add-PSSnapin VeeamPSSnapIn -ErrorAction SilentlyContinue

#Run the Import-Module cmdlet to import the necessary PowerShell module
#Import-Module Veeam.SQL.PowerShell -ErrorAction SilentlyContinue

#*****CHECK $RESTOREPOINT BEFORE RUNNING CODE BELOW THIS POINT FOR THE FIRST TIME TO MAKE SURE EVERYTHING IS CORRECT TO THIS POINT*****
$restorePoint = Get-VBRApplicationRestorePoint -SQL -Name “$BackupSourceVM” | Sort -Property CreationTime -Descending | Select -First 1

#Starts a session to restore the backup
Start-VESQLRestoreSession -RestorePoint $restorepoint

$session = Get-VESQLRestoreSession

#Checks the availability of restoring the DB
try {
$database = Get-VESQLDatabase -Session $session -Name $BackupSourceDB

} catch {
Stop-VESQLRestoreSession -Session $session
“Couldnt find database”
break
}

$username = “DOMINIO\TESTE”
$password = Get-Content ‘C:\DBRestoreScript\securestring.txt’ | ConvertTo-SecureString
$creds = New-Object -typename System.Management.Automation.PSCredential -ArgumentList $username, $password

#Performs restore to selected directory
try {

$path -SqlCredentials $creds -GuestCredentials $creds
$Arquive = $BackuptargetDirectory + $BackupSourceVM + ‘\’ + $BackupSourceDB + ‘_’ +$data + ‘.bak’
$restoreSession = Export-VESQLDatabase -Database $database -Path $Arquive -Server $BackupSourceVM -GuestCredentials $creds -ToBackupFile -Force

} catch {
Stop-VESQLRestoreSession -Session $session
“Couldnt restore database”
break
}

Stop-VESQLRestoreSession -Session $session

Com o script salvo dentro da pasta C:\DBRestoreScript, ao executar o mesmo deverá executar o Powershell, abrindo a seguinte tela:

Também pode ser criado um atalho para o mesmo e ao clicar com o botão direito, selecionar “Executar com o PowerShell”:

Vamos preencher as informações básicas, digitando o servidor de origem e nome do banco de dados de produção, bem como o diretório onde iremos gravar. No script Powershell, você pode deixar salvo um diretório padrão, que o próprio ao exportar o arquivo .BAK, irá criar uma estrutura de pastas como: diretorio padrão + nome do servidor + nomedobancodedados_data.bak

Após clicar em "Bora" :) é só esperar o processo concluir.

OBS: Esse processo pode ser feito por dentro da ferramenta Veeam Backup and Replication, com uns vários cliques, então prefiro escrever duas linhas de comando e esperar o Veeam fazer o resto :).

Fontes

--

--