forked from sg3-141-592/AzureStartStopVMs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrunbook.ps1
More file actions
142 lines (113 loc) · 4.78 KB
/
runbook.ps1
File metadata and controls
142 lines (113 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
Param(
[parameter(Mandatory=$true)]
[String] $subscriptionId,
[parameter(Mandatory=$true)]
[String] $accountId
)
Import-Module PSDates
$errorActionPreference = "Stop"
# Global used to await VM stopping jobs
$global:vmJobList = @()
# Constants
$STOP_TAG = "automated_stop"
$START_TAG = "automated_start"
function ManageVMPowerState{
param(
[Object]$VirtualMachine,
[string]$DesiredState
)
Write-Output "[$($VirtualMachine.Name)]: Managing VM PowerState"
# Retrieve VM with current status
$eachVM = Get-AzVM -ResourceGroupName $VirtualMachine.ResourceGroupName -Name $VirtualMachine.Name -Status
$currentStatus = $eachVM.Statuses | Where-Object Code -like "PowerState*"
$currentStatus = $currentStatus.Code -replace "PowerState/",""
# If should be started and isn't, start VM
if($DesiredState -eq "Started" -and $currentStatus -notmatch "running")
{
Write-Output "[$($VirtualMachine.Name)]: Starting VM"
$global:vmJobList += $eachVM | Start-AzVM -AsJob
}
# If should be stopped and isn't, stop VM
elseif($DesiredState -eq "StoppedDeallocated" -and $currentStatus -ne "deallocated")
{
Write-Output "[$($VirtualMachine.Name)]: Stopping VM"
$global:vmJobList += $eachVM | Stop-AzVM -Force -AsJob
}
# Otherwise, current power state is correct
else
{
Write-Output "[$($VirtualMachine.Name)]: Current state [$currentStatus] is correct."
}
}
$currentTime = (Get-Date).ToUniversalTime()
Write-Output "Runbook started..."
Write-Output "Current UTC time: [$($currentTime.ToString("dddd, yyyy MMM dd HH:mm:ss"))] "
try
{
"Logging in to Azure..."
Connect-AzAccount -Identity -AccountId "$accountId" -Subscription "$subscriptionId" | Out-Null
"Login successful.."
}
catch {
Write-Error -Message $_.Exception
throw $_.Exception
}
try {
# Get VM Data
$allVMs = Get-AzResource -ResourceType "Microsoft.Compute/VirtualMachines" -TagName "$STOP_TAG"
foreach ($vm in $allVMs) {
Write-Output "[$($vm.Name)] Processing VM ..."
# Retrieve the VM start and shutdown schedule
$stop_schedule = $($vm.Tags)."$STOP_TAG"
$start_schedule = $($vm.Tags)."$START_TAG"
# Start schedules are optional on VMs
$has_start_schedule = ![string]::IsNullOrWhiteSpace($start_schedule)
if([string]::IsNullOrWhiteSpace($stop_schedule))
{
Write-Output "[$($vm.Name)] Skipping due to invalid/empty value in $STOP_TAG"
continue
}
if((Test-CrontabSchedule -crontab "$stop_schedule").Valid -eq $false)
{
Write-Output "[$($vm.Name)] Skipping this VM due to invalid cron schedule: $stop_schedule"
}
if($has_start_schedule -eq $true)
{
if((Test-CrontabSchedule -crontab "$start_schedule").Valid -eq $false)
{
Write-Output "[$($vm.Name)] Skipping this VM due to invalid cron schedule: $start_schedule"
}
Write-Output "[$($vm.Name)] Start schedule is: $start_schedule"
}
Write-Output "[$($vm.Name)] Stop schedule is: $stop_schedule"
# See what the target stop time is for the VM on current schedule
$nextStopTime = Get-CronNextOccurrence "$stop_schedule" -StartTime $currentTime.Date -EndTime $currentTime.Date.AddDays(1)
Write-Output "[$($vm.Name)] Target stop time is: $nextStopTime"
# If VM has a start time and a stop time
if ($has_start_schedule -eq $true) {
# See what the target start time is for the VM on current schedule
$nextStartTime = Get-CronNextOccurrence "$start_schedule" -StartTime $currentTime.Date -EndTime $currentTime.Date.AddDays(1)
Write-Output "[$($vm.Name)] Target start time is: $nextStartTime"
# If we are between the start and stop times the VM should be running
if (($currentTime -ge $nextStartTime) -And ($currentTime -le $nextStopTime)) {
ManageVMPowerState -VirtualMachine $vm -DesiredState "Started"
} else {
ManageVMPowerState -VirtualMachine $vm -DesiredState "StoppedDeallocated"
}
} else {
# If VM just has a stop time defined
if (($currentTime -ge $nextStopTime)) {
ManageVMPowerState -VirtualMachine $vm -DesiredState "StoppedDeallocated"
}
}
}
# Await VM Stop/Start commands
Write-Output $global:vmJobList | Get-Job | Wait-Job | Receive-Job | Format-Table -AutoSize
}
catch {
Write-Error "$($_.Exception.Message)"
throw "Error executing stop/start script"
}
finally {
Write-Output "Runbook finished (Duration: $(("{0:hh\:mm\:ss}" -f ((Get-Date).ToUniversalTime() - $currentTime))))"
}