클라우드 환경에서는 사용하지 않는 리소스를 중지하는 것만으로도 상당한 비용 절감 효과를 얻을 수 있습니다.
이러한 작업을 수동으로 하게 된다면 비효율적일 뿐만 아니라 누락되기 쉽습니다.
Azure Automation을 이용하여 반복 작업을 자동화함으로써, 시간 또는 정책 기반으로 리소스를 안정적으로 제어할 수 있습니다.
이 문서에서는 Azure Automation을 이용해 주요 Azure 리소스를 On/Off 하는 방법을 살펴봅니다.
Azure VM의 경우 기본적으로 자동종료 기능을 제공합니다.
하지만 이 기능은 종료만 지원하기 때문에 매번 VM을 켜서 사용해야하는 번거로움이 있습니다.
이를 대체하고 더 나아가 효율적인 운영을 위해 Azure Automation을 이용해 주요 Azure 리소스를 On/Off 합니다.
1.Automation 계정 생성
Azure Automation 계정 리소스를 생성합니다.

2.새 Runbook 을 작성합니다.
Runbook은 직접 작성하거나 사용자들이 직접 작성하여 게시하는 런북갤러리에서 적절한 스크립트를 찾아 적용할 수 있습니다.

이 문서에서는 Managed Identity를 사용한 스크립트로 작성했습니다.
Managed Identity를 사용하면 별도의 자격증명 관리가 필요 없어 보안성이 높습니다.
이를 위해 Automation을 만드는 과정에서 관리ID 사용을 체크합니다.

구분 | 시스템 할당 (System-assigned) | 사용자 할당 (User-assigned) |
생명주기 | Automation 계정과 함께 생성/삭제 | 독립적으로 존재 (별도 리소스) |
개수 | Automation 계정당 1개만 가능 | 여러 개 생성 가능 |
재사용성 | 해당 Automation 계정만 사용 | 여러 리소스에서 공유 가능 |
삭제 시 | Automation 삭제 시 자동 삭제됨 | Automation 삭제해도 ID는 유지됨 |
권한 관리 | 각 Automation마다 개별 설정 | 한 번 설정하면 모든 곳에 적용 |
설정 복잡도 | 간단 (토글 하나) | 약간 복잡 (먼저 ID 생성 필요) |
비용 | 무료 | 무료 |
적합한 경우 | 단일 Automation 전용 권한 | 여러 리소스가 동일 권한 필요 |
런북을 생성하면 바로 편집 화면으로 넘어갑니다.
오른쪽에 코드를 입력하고 저장 후 게시까지 누릅니다.
게시를 누르지 안으면 초안으로 간주되고 실제 적용은 되지 않은 상태이므로 반드시 게시까지 눌러줍니다.

Param(
[parameter(Mandatory = $true)]
[String] $ResourceGroupName,
[parameter(Mandatory = $true)]
[ValidateSet('start', 'stop')]
[String] $Operation
)
# Verify if the Resource Group and Application Gateway exists
try {
Disable-AzContextAutosave -Scope Process
#System Managed Identity
Write-Output "Logging into Azure using System Managed Identity"
$AzureContext = (Connect-AzAccount -Identity).context
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext
}
catch {
Write-Error -Message $_.Exception
throw $_.Exception
}
Write-Output "Performing $Operation operation on Resource Group: $ResourceGroupName"
switch -CaseSensitive ($Operation) {
'start' {
# VM Start
Write-Output "Starting all VMs in Resource Group $ResourceGroupName"
$VMs = Get-AzVM -ResourceGroupName $ResourceGroupName
# VM 존재 여부 확인
if ($VMs.Count -eq 0) {
Write-Warning "No VMs found in Resource Group $ResourceGroupName"
exit
}
Write-Output "Found $($VMs.Count) VM(s) to start"
$Jobs = @()
# 에러 핸들링과 Job 수집
foreach ($VM in $VMs) {
try {
Write-Output "Initiating start for VM: $($VM.Name)"
$Jobs += Start-AzVM -ResourceGroupName $ResourceGroupName -Name $VM.Name -AsJob -ErrorAction Stop
}
catch {
Write-Error "Failed to initiate start for VM $($VM.Name): $($_.Exception.Message)"
}
}
# 작업 완료 대기 및 결과 로깅
if ($Jobs.Count -gt 0) {
Write-Output "Waiting for all start operations to complete..."
$Jobs | Wait-Job | Out-Null
Write-Output "`n--- Start Operation Results ---"
foreach ($Job in $Jobs) {
$Result = Receive-Job -Job $Job
if ($Job.State -eq 'Completed') {
Write-Output "✓ SUCCESS: $($Job.Name) started successfully"
}
else {
Write-Error "✗ FAILED: $($Job.Name) - State: $($Job.State)"
}
}
# 정리
$Jobs | Remove-Job
# 요약 통계
$SuccessCount = ($Jobs | Where-Object {$_.State -eq 'Completed'}).Count
$FailedCount = $Jobs.Count - $SuccessCount
Write-Output "`n=== Summary ==="
Write-Output "Total VMs: $($Jobs.Count) | Successful: $SuccessCount | Failed: $FailedCount"
}
}
'stop' {
# VM Stop
Write-Output "Stopping all VMs in Resource Group $ResourceGroupName"
$VMs = Get-AzVM -ResourceGroupName $ResourceGroupName
# VM 존재 여부 확인
if ($VMs.Count -eq 0) {
Write-Warning "No VMs found in Resource Group $ResourceGroupName"
exit
}
Write-Output "Found $($VMs.Count) VM(s) to stop"
$Jobs = @()
# 에러 핸들링과 Job 수집
foreach ($VM in $VMs) {
try {
Write-Output "Initiating stop for VM: $($VM.Name)"
$Jobs += Stop-AzVM -ResourceGroupName $ResourceGroupName -Name $VM.Name -Force -AsJob -ErrorAction Stop
}
catch {
Write-Error "Failed to initiate stop for VM $($VM.Name): $($_.Exception.Message)"
}
}
# 작업 완료 대기 및 결과 로깅
if ($Jobs.Count -gt 0) {
Write-Output "Waiting for all stop operations to complete..."
$Jobs | Wait-Job | Out-Null
Write-Output "`n--- Stop Operation Results ---"
foreach ($Job in $Jobs) {
$Result = Receive-Job -Job $Job
if ($Job.State -eq 'Completed') {
Write-Output "✓ SUCCESS: $($Job.Name) stopped successfully"
}
else {
Write-Error "✗ FAILED: $($Job.Name) - State: $($Job.State)"
}
}
# 정리
$Jobs | Remove-Job
# 요약 통계
$SuccessCount = ($Jobs | Where-Object {$_.State -eq 'Completed'}).Count
$FailedCount = $Jobs.Count - $SuccessCount
Write-Output "`n=== Summary ==="
Write-Output "Total VMs: $($Jobs.Count) | Successful: $SuccessCount | Failed: $FailedCount"
}
}
}
Write-Output "`n$Operation operation completed for Resource Group: $ResourceGroupName"런북 게시 후 원하는 일정을 적용하기 위해 “일정에 연결” 작업을 해줍니다.

일정은ON/OFF 각각 적용해야합니다.
하기 설정은 매주 월요일 오전 08:00에 VM을 켜고 매주 금요일 20:00에 VM을 끄도록 설정합니다.
즉, 월요일 지정한 시간에 VM을 켜면 토요일 지정한 시간까지 VM은 꺼지지 않고 계속해서 동작합니다.
매일 또는 특정일에 끄도록 설정하려면 요일 선택을 통해 조정할 수 있습니다.

