scripts/runbooks/Stop-AdeResources.ps1

#Requires -Version 7.0
<#
.SYNOPSIS
    ADE Auto-Stop Runbook — Deallocates all VMs, VMSS, and AKS clusters.
    Intended to run as an Azure Automation runbook on a daily schedule.

.DESCRIPTION
    Uses the Automation Account's system-assigned managed identity (no stored credentials).
    Discovers all resources tagged managedBy=ade under the given prefix.

.PARAMETER ResourcePrefix
    The resource prefix used during ADE deployment. Default: ade

.PARAMETER SubscriptionId
    Override subscription. If empty, uses the Automation Account's default context.

.PARAMETER DryRun
    Log what would be stopped without executing.
#>

param(
    [string]$ResourcePrefix = 'ade',
    [string]$SubscriptionId = '',
    [switch]$DryRun
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

Write-Output "=== ADE Auto-Stop Runbook started at $(Get-Date -Format 'o') ==="
Write-Output "ResourcePrefix: $ResourcePrefix | DryRun: $DryRun"

# Authenticate using the Automation Account's system-assigned managed identity
try {
    Connect-AzAccount -Identity | Out-Null
    Write-Output "Authenticated via managed identity."
} catch {
    throw "Failed to authenticate via managed identity: $_"
}

if ($SubscriptionId) {
    Set-AzContext -SubscriptionId $SubscriptionId | Out-Null
    Write-Output "Switched to subscription: $SubscriptionId"
}

$context = Get-AzContext
Write-Output "Active subscription: $($context.Subscription.Name) [$($context.Subscription.Id)]"

# ── Stop VMs ──────────────────────────────────────────────────────────────────
Write-Output ""
Write-Output "--- Virtual Machines ---"

$vms = Get-AzVM | Where-Object {
    $_.Tags['managedBy'] -eq 'ade' -and $_.ResourceGroupName -like "$ResourcePrefix-*"
}

if (-not $vms) {
    Write-Output "No matching VMs found."
} else {
    foreach ($vm in $vms) {
        $powerState = (Get-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Status).Statuses |
            Where-Object { $_.Code -like 'PowerState/*' } |
            Select-Object -ExpandProperty DisplayStatus

        if ($powerState -like '*running*') {
            Write-Output "Deallocating: $($vm.Name) in $($vm.ResourceGroupName)"
            if (-not $DryRun) {
                Stop-AzVM -ResourceGroupName $vm.ResourceGroupName -Name $vm.Name -Force -NoWait | Out-Null
            }
        } else {
            Write-Output "Already stopped: $($vm.Name) [$powerState]"
        }
    }
}

# ── Stop VMSS ─────────────────────────────────────────────────────────────────
Write-Output ""
Write-Output "--- VM Scale Sets ---"

$vmssList = Get-AzVmss | Where-Object {
    $_.Tags['managedBy'] -eq 'ade' -and $_.ResourceGroupName -like "$ResourcePrefix-*"
}

if (-not $vmssList) {
    Write-Output "No matching VMSS found."
} else {
    foreach ($vmss in $vmssList) {
        Write-Output "Deallocating VMSS: $($vmss.Name) in $($vmss.ResourceGroupName)"
        if (-not $DryRun) {
            Stop-AzVmss -ResourceGroupName $vmss.ResourceGroupName -VMScaleSetName $vmss.Name -Force | Out-Null
        }
    }
}

# ── Stop AKS Clusters ─────────────────────────────────────────────────────────
Write-Output ""
Write-Output "--- AKS Clusters ---"

$aksClusters = Get-AzAksCluster | Where-Object {
    $_.Tags['managedBy'] -eq 'ade' -and $_.ResourceGroupName -like "$ResourcePrefix-*"
}

if (-not $aksClusters) {
    Write-Output "No matching AKS clusters found."
} else {
    foreach ($aks in $aksClusters) {
        if ($aks.PowerState.Code -eq 'Running') {
            Write-Output "Stopping AKS: $($aks.Name) in $($aks.ResourceGroupName)"
            if (-not $DryRun) {
                Stop-AzAksCluster -ResourceGroupName $aks.ResourceGroupName -Name $aks.Name | Out-Null
            }
        } else {
            Write-Output "Already stopped: $($aks.Name) [$($aks.PowerState.Code)]"
        }
    }
}

Write-Output ""
Write-Output "=== ADE Auto-Stop completed at $(Get-Date -Format 'o') ==="