Apagado y Encendido Automático de VMs con PowerShell y Tags en Azure

Introducción:

En entornos de nube como Azure, es fundamental optimizar el uso de recursos para reducir costos y mejorar la eficiencia operativa. Una de las prácticas recomendadas es apagar las máquinas virtuales (VMs) cuando no están en uso y encenderlas solo cuando sea necesario. En este blog, exploraremos cómo automatizar este proceso utilizando Tags en Azure y un script de PowerShell ejecutado desde un Automation Account.

Configuración Inicial:

Antes de sumergirnos en el script, asegúrate de tener un Automation Account configurado en Azure con las credenciales necesarias. El script utiliza un servicio principal para la autenticación.

Automation Accounts

Nos vamos al servicio Automation Accounts (En caso que no exista lo creamos)

El Script:

El script PowerShell proporcionado se encarga de apagar y encender VMs en función de la programación definida en sus Tags. Se inicia sesión en Azure utilizando las credenciales del Automation Account y luego examina las VMs en función de la programación diaria y de fin de semana.

$connectionName = "AzureRunAsConnection"
try
{
    # Get the connection "AzureRunAsConnection "
    $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         

    "Logging in to Azure..."
    Connect-AzAccount `
        -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint 
}
catch {
    if (!$servicePrincipalConnection)
    {
        $ErrorMessage = "Connection $connectionName not found."
        throw $ErrorMessage
    } else{
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}
$Today = Get-Date -Format dd/MM/yyyy
$day = (Get-Date).DayOfWeek
$days = (Get-AzAutomationVariable -ResourceGroupName "Mapal_Infra" -AutomationAccount "mapalinforchestrator" -Name "DaysOfWeek").Value -split ","
$Weekend = (Get-AzAutomationVariable -ResourceGroupName "Mapal_Infra" -AutomationAccount "mapalinforchestrator" -Name "DaysOfWeekend").Value -split ","
#Schedule horario invierno
$Schedule = (Get-AzAutomationJob -ResourceGroupName Mapal_infra -AutomationAccountName mapalinforchestrator | Select-Object * -First 1).CreationTime.AddHours(1).ToString('HH:mm')
#Schedule horario verano
#$Schedule = (Get-AzAutomationJob -ResourceGroupName Mapal_infra -AutomationAccountName mapalinforchestrator | Select-Object * -First 1).CreationTime.AddHours(2).ToString('HH:mm')
Write-Output "Tarea iniciada a las $Schedule"
if ($days -contains $day) {
    $Vms = Get-AzVM | Where-Object {$_.Tags.PowerOff -eq "$Schedule"}
    foreach ($Vm in $Vms) {
        $Status = (Get-AzVM -Name $Vm.Name -Status).PowerState
        if ($Status -eq "VM running" -or "VM stopped") {
        $Name = $Vm.Name
        Stop-AzVM -Name $Vm.Name -ResourceGroupName $Vm.ResourceGroupName -Force
        Write-Output "Apagando servidores..."
        Write-Output "Servidor $Name apagado"
        }
    }
    $Vms = Get-AzVM | Where-Object {$_.Tags.PowerOn -eq "$Schedule"}
    foreach ($Vm in $Vms) {
        $Status = (Get-AzVM -Name $Vm.Name -Status).PowerState
        if ($Status -eq "VM deallocated") {
            Start-AzVM -Name $Vm.Name -ResourceGroupName $Vm.ResourceGroupName
            $Name = $Vm.Name
            Write-Output "Encendiendo servidores..." 
            Write-Output "Servidor $Name encendido"
        }
    }
}
if ($Weekend -contains $day) {
    $Vms = Get-AzVM | Where-Object {($_.Tags.WeekendPowerOn -eq "Yes") -and ($_.Tags.PowerOff -eq "$Schedule")}
    foreach ($Vm in $Vms) {
        $Status = (Get-AzVM -Name $Vm.Name -Status).PowerState
        if ($Status -eq "VM running" -or "VM stopped") {
            $Name = $Vm.Name
            Stop-AzVM -Name $Vm.Name -ResourceGroupName $Vm.ResourceGroupName -Force
            Write-Output "Apagando servidores..."
            Write-Output "Servidor $Name apagado"
        }
    }
    $Vms = Get-AzVM | Where-Object {($_.Tags.WeekendPowerOn -eq "Yes") -and ($_.Tags.PowerOn -eq "$Schedule")}
    foreach ($Vm in $Vms) {
        $Status = (Get-AzVM -Name $Vm.Name -Status).PowerState
        if ($Status -eq "VM deallocated") {
            Start-AzVM -Name $Vm.Name -ResourceGroupName $Vm.ResourceGroupName
            $Name = $Vm.Name
            Write-Output "Encendiendo servidores..." 
            Write-Output "Servidor $Name encendido"
        }
    }
}
else {
        Write-Output "No hay servidores con esta programación."
}

Creamos el certificado

Creamos las conexión

En Schedules creamos cuando queremos que se ejecute el runbook

Programación Diaria:

Las VMs se apagan y encienden según la programación diaria establecida en los Tags «PowerOff» y «PowerOn». El script verifica si el día actual corresponde a los días programados y realiza las operaciones correspondientes.

Programación de Fin de Semana:

Adicionalmente, el script también maneja la programación de fin de semana, donde las VMs pueden tener configuraciones especiales. En este caso, se verifica si el día actual es un día de fin de semana y si la VM está marcada para encenderse o apagarse en ese horario específico.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *