-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathUpdateManagement-TurnOffVms.ps1
147 lines (112 loc) · 4.77 KB
/
UpdateManagement-TurnOffVms.ps1
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
143
144
145
146
147
<#PSScriptInfo
.VERSION 1.2
.GUID 9606f2a1-49f8-4a67-91d6-23fc6ebf5b3b
.AUTHOR zachal
.COMPANYNAME Microsoft
.COPYRIGHT
.TAGS UpdateManagement, Automation
.LICENSEURI
.PROJECTURI
.ICONURI
.EXTERNALMODULEDEPENDENCIES ThreadJob
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.RELEASENOTES
Removed parameters AutomationAccount, ResourceGroup
.PRIVATEDATA
#>
<#
.DESCRIPTION
This script is intended to be run as a part of Update Management Pre/Post scripts.
It requires a System Managed Identity.
This script will ensure all Azure VMs in the Update Deployment are running so they recieve updates.
This script works with the Turn Off VMs script. It will store the names of machines that were started in an Automation variable so only those machines are turned back off when the deployment is finished.
#>
#requires -Modules ThreadJob
<#
.SYNOPSIS
Stop VMs that were started as part of an Update Management deployment
.DESCRIPTION
This script is intended to be run as a part of Update Management Pre/Post scripts.
It requires a System Managed Identity.
This script will turn off all Azure VMs that were started as part of TurnOnVMs.ps1.
It retrieves the list of VMs that were started from an Automation Account variable.
.PARAMETER SoftwareUpdateConfigurationRunContext
This is a system variable which is automatically passed in by Update Management during a deployment.
#>
param(
[string]$SoftwareUpdateConfigurationRunContext
)
#region BoilerplateAuthentication
#This requires a System Managed Identity
$AzureContext = (Connect-AzAccount -Identity).context
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext
#endregion BoilerplateAuthentication
#If you wish to use the run context, it must be converted from JSON
$context = ConvertFrom-Json $SoftwareUpdateConfigurationRunContext
$runId = "PrescriptContext" + $context.SoftwareUpdateConfigurationRunId
#https://github.com/azureautomation/runbooks/blob/master/Utility/ARM/Find-WhoAmI
# In order to prevent asking for an Automation Account name and the resource group of that AA,
# search through all the automation accounts in the subscription
# to find the one with a job which matches our job ID
$AutomationResource = Get-AzResource -ResourceType Microsoft.Automation/AutomationAccounts
foreach ($Automation in $AutomationResource)
{
$Job = Get-AzAutomationJob -ResourceGroupName $Automation.ResourceGroupName -AutomationAccountName $Automation.Name -Id $PSPrivateMetadata.JobId.Guid -ErrorAction SilentlyContinue
if (!([string]::IsNullOrEmpty($Job)))
{
$ResourceGroup = $Job.ResourceGroupName
$AutomationAccount = $Job.AutomationAccountName
break;
}
}
#Retrieve the automation variable, which we named using the runID from our run context.
#See: https://docs.microsoft.com/en-us/azure/automation/automation-variables#activities
$variable = Get-AzAutomationVariable -Name $runId -ResourceGroupName $ResourceGroup -AutomationAccountName $AutomationAccount
if (!$variable)
{
Write-Output "No machines to turn off"
return
}
$vmIds = $variable.Value -split ","
$stoppableStates = "starting", "running"
$jobIDs= New-Object System.Collections.Generic.List[System.Object]
#This script can run across subscriptions, so we need unique identifiers for each VMs
#Azure VMs are expressed by:
# subscription/$subscriptionID/resourcegroups/$resourceGroup/providers/microsoft.compute/virtualmachines/$name
$vmIds | ForEach-Object {
$vmId = $_
$split = $vmId -split "/";
$subscriptionId = $split[2];
$rg = $split[4];
$name = $split[8];
Write-Output ("Subscription Id: " + $subscriptionId)
$mute = Set-AzContext -Subscription $subscriptionId
$vm = Get-AzVM -ResourceGroupName $rg -Name $name -Status -DefaultProfile $mute
$state = ($vm.Statuses[1].DisplayStatus -split " ")[1]
if($state -in $stoppableStates) {
Write-Output "Stopping '$($name)' ..."
$newJob = Start-ThreadJob -ScriptBlock { param($resource, $vmname, $sub) $context = Set-AzContext -Subscription $sub; Stop-AzVM -ResourceGroupName $resource -Name $vmname -Force -DefaultProfile $context} -ArgumentList $rg,$name,$subscriptionId
$jobIDs.Add($newJob.Id)
}else {
Write-Output ($name + ": already stopped. State: " + $state)
}
}
#Wait for all machines to finish stopping so we can include the results as part of the Update Deployment
$jobsList = $jobIDs.ToArray()
if ($jobsList)
{
Write-Output "Waiting for machines to finish stopping..."
Wait-Job -Id $jobsList
}
foreach($id in $jobsList)
{
$job = Get-Job -Id $id
if ($job.Error)
{
Write-Output $job.Error
}
}
#Clean up our variables:
Remove-AzAutomationVariable -AutomationAccountName $AutomationAccount -ResourceGroupName $ResourceGroup -name $runID