Получение данных о бэкапах виртуальных машин в Azure

Опубликовано: 06.02.2021
Автор: Виталий Бочкарев
Поддержать автора статьи по этой ссылке

В облачном сервисе Microsoft Azure при запросе информации о виртуальных серверах через PowerShell-скрипт или Python API не выдается информация об их резервных копиях, так как механизм резервного копирования основан на отдельном сервисе.

Чтобы обойти это ограничение, я использую промежуточный PowerShell-скрипт, который запрашивает сервис Recovery Services Vault обо всех имеющихся в нем точках восстановления серверов и сохраняет эту информацию в json-файл. Данный файл я формирую один раз в несколько часов, так как информация о бэкапах меняется не очень часто. Впоследствии скрипты, которые запрашивают информацию о виртуальных машинах в Azure, подхватывают этот файл, сопоставляют имена серверов с точками восстановления из json-файла, выдают результат, который содержит как стандартные свойства сервера, так и информацию по резервным копиям каждого сервера.

# ------------------------------------------------------------------------------------------------
# Functions

Function Write-ScriptLog {
  Param(
    [CmdletBinding()] 
    [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [String]$Message,
    [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
    [String]$LogFile
  )
  Process {
    $LogMessage = Get-Date -uformat "%d.%m.%Y %H:%M:%S"
    $LogMessage += "`t"
    $LogMessage += $Message
    $LogMessage | Out-File -FilePath $LogFile -Append
  }
}#End Function

# ------------------------------------------------------------------------------------------------

# Получение пути к скрипту
$ScriptFolder = $MyInvocation.MyCommand.Path.SubString(0,($MyInvocation.MyCommand.Path.Length - $MyInvocation.MyCommand.Name.Length))
# Формирование пути к лог-файлу
$LogFile = $ScriptFolder + $MyInvocation.MyCommand.Name.SubString(0,($MyInvocation.MyCommand.Name.Length - 4)) + ".log"
$JsonFile = $ScriptFolder + $MyInvocation.MyCommand.Name.SubString(0,($MyInvocation.MyCommand.Name.Length - 4)) + ".json"
# Создание лог-файла
Out-File -FilePath $LogFile
Write-ScriptLog -LogFile $LogFile -Message ($MyInvocation.MyCommand.Name + " started")
# Чтение аргументов из командной строки
Write-ScriptLog -LogFile $LogFile -Message "Reading input arguments"
If ($args.length -ne 3) {
  Write-ScriptLog -LogFile $LogFile -Message "Wrong number of agruments"
  Write-ScriptLog -LogFile $LogFile -Message "Using default values"
  $AZU_TENANT_ID = 'abcdefjh-1234-abcd-1234-abcdefjhigkl'
  $AZU_CLIENT_ID = 'hjfedcba-4321-dcba-4321-lkgihjfedcba'
  $AZU_SECRET_KEY = '123.abc.1234567.abcdefj.123456789'
} else {
  $AZU_TENANT_ID = $args[0]
  $AZU_CLIENT_ID = $args[1]
  $AZU_SECRET_KEY = $args[2]
}
Write-ScriptLog -LogFile $LogFile -Message "  azu_tenant_id is $AZU_TENANT_ID"
Write-ScriptLog -LogFile $LogFile -Message "  azu_client_id is $AZU_CLIENT_ID"
Write-ScriptLog -LogFile $LogFile -Message "  aqzu_secret_key is $AZU_SECRET_KEY"
Write-ScriptLog -LogFile $LogFile -Message "  output json-file is $JsonFile"
# вход в Azure
Write-ScriptLog -LogFile $LogFile -Message "Logging in to Azure"
$AZU_SECRET_KEY_SEC = ConvertTo-SecureString $AZU_SECRET_KEY -AsPlainText -Force
$pscredential = New-Object -TypeName System.Management.Automation.PSCredential($AZU_CLIENT_ID, $AZU_SECRET_KEY_SEC)
Disconnect-AzAccount
Connect-AzAccount -ServicePrincipal -Credential $pscredential -Tenant $AZU_TENANT_ID  | Out-Null
# создание пустого списка свойств резервного копирования серверов
$data = New-Object System.Collections.Generic.List[System.Object]
# получение всех коллекций резервного копирования
Write-ScriptLog -LogFile $LogFile -Message "Reading recovery services vaults"
$vault_list = Get-AzRecoveryServicesVault
Write-ScriptLog -LogFile $LogFile -Message ($vault_list.length.ToString() + " vaults found")
ForEach ($vault_item in $vault_list) {
  # получение контейнеров резервного копирования для каждой коллекции
  Write-ScriptLog -LogFile $LogFile -Message ("  Reading containers of " + $vault_item.Name)
  $container_list = Get-AzRecoveryServicesBackupContainer -ContainerType "AzureVM" -BackupManagementType "AzureVM" -VaultId $vault_item.ID
  Write-ScriptLog -LogFile $LogFile -Message ("   " + $container_list.length.ToString() + " containers found")
  foreach ($container_item in $container_list) {
    # получение объекта резервного копирования сервера
    Write-ScriptLog -LogFile $LogFile -Message ("    Reading properties of " + $container_item.FriendlyName)
    $backup_item = Get-AzRecoveryServicesBackupItem -Container $container_item -WorkloadType AzureVM -VaultId $vault_item.ID
    # получение свойств объекта резервного копирования
    $id = $backup_item.Id
    $vm_name = ($backup_item.ContainerName -split ";")[2].ToString().ToLower()
    $vm_rgp_name = ($backup_item.ContainerName -split ";")[1].ToString().ToLower()
    $container_name = $backup_item.ContainerName
    $policy_name = $backup_item.ProtectionPolicyName
    $vault_name = $vault_item.Name
    $vault_rgp_name = ($vault_item.ID -split "/")[4].ToString().ToLower()
    $id = ('/' + $vault_rgp_name + '/' + $vault_name + '/' + $container_name)
    $status = $backup_item.ProtectionStatus.ToString().ToLower()
    $latest_backup = [datetime]::parseexact($backup_item.LatestRecoveryPoint, 'MM/dd/yyyy HH:mm:ss', $null)
    # составление словаря свойств резервного копирования сервера
    $backup_properties = New-Object System.Object
    $backup_properties | Add-member -MemberType NoteProperty -Name id -Value $id
    $backup_properties | Add-member -MemberType NoteProperty -Name vm_name -Value $vm_name
    $backup_properties | Add-Member -MemberType NoteProperty -Name vm_rgp_name -Value $vm_rgp_name
    $backup_properties | Add-member -MemberType NoteProperty -Name container_name -Value $container_name
    $backup_properties | Add-member -MemberType NoteProperty -Name policy_name -Value $policy_name
    $backup_properties | Add-Member -MemberType NoteProperty -Name vault_name -Value $vault_name
    $backup_properties | Add-Member -MemberType NoteProperty -Name vault_rgp_name -Value $vault_rgp_name
    $backup_properties | Add-Member -MemberType NoteProperty -Name status -Value $status
    $backup_properties | Add-Member -MemberType NoteProperty -Name latest_backup -Value $latest_backup
    # добавление полученных свойств в список свойств резервного копирования серверов
    $data.Add($backup_properties)
  }
}
Write-ScriptLog -LogFile $LogFile -Message "Reading data from Azure is complete"
Write-ScriptLog -LogFile $LogFile -Message "Deleteing the output file if it exists"
If (Test-Path $JsonFile) { Remove-Item -Path $JsonFile }
Write-ScriptLog -LogFile $LogFile -Message ("Saving json-file " + $JsonFile)
$data | ConvertTo-Json | Out-File -FilePath $JsonFile -Encoding "utf8"
# ------------------------------------------------------------------------------------------------
Write-ScriptLog -LogFile $LogFile -Message "----- The script finished -----"

 

Результат работы скрипта - json-файл с данными о серверах и их бэкапах

[
    {
        "id":  "/rgp-n-aaa-project1/rsv-n-aaa-project1-backupvault/iaasvmcontainerv2;rgp-n-aaa-project1;wsAAA056",
        "vm_name":  "wsAAA056",
        "vm_rgp_name":  "rgp-n-aaa-project1",
        "container_name":  "iaasvmcontainerv2;rgp-n-aaa-project1;wsazn056",
        "policy_name":  "pol-VM-Daily-10pm-4WeeksRetention",
        "vault_name":  "rsv-n-aaa-project1-backupvault",
        "vault_rgp_name":  "rgp-n-aaa-project1",
        "status":  "healthy",
        "latest_backup":  "\/Date(1612459418000)\/"
    },
    {
        "id":  "/rgp-n-aaa-project1/rsv-n-aaa-project1-backupvault/iaasvmcontainerv2;rgp-n-aaa-project1;wsAAA057",
        "vm_name":  "wsAAA057",
        "vm_rgp_name":  "rgp-n-aaa-project1",
        "container_name":  "iaasvmcontainerv2;rgp-n-aaa-project1;wsazn057",
        "policy_name":  "pol-VM-Weekly-10pm-4WeeksRetention",
        "vault_name":  "rsv-n-aaa-project1-backupvault",
        "vault_rgp_name":  "rgp-n-aaa-project1",
        "status":  "healthy",
        "latest_backup":  "\/Date(1612459319000)\/"
    }
]