-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAzureCapacityWatcher.ps1
186 lines (155 loc) · 7.62 KB
/
AzureCapacityWatcher.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
<#PSScriptInfo
.VERSION 1.0.0
.GUID 484bbc9d-b032-4b06-86b1-8c19e3699edb
.AUTHOR JDMSFT
.COMPANYNAME JDMSFT
.COPYRIGHT (c) 2021 JDMSFT. All Right Reserved.
.TAGS AzureAutomation Runbook Azure Capacity Notification Watcher alert
.LICENSEURI https://github.com/jdmsft/AzureCapacityWatcher/blob/master/LICENSE
.PROJECTURI https://github.com/jdmsft/AzureCapacityWatcher
.ICONURI
.EXTERNALMODULEDEPENDENCIES
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.RELEASENOTES
.PRIVATEDATA
#>
<#
.SYNOPSIS
Azure Capacity Watcher for Azure Automation (aka AzureCapacityWatcher)
.DESCRIPTION
Azure Capacity Watcher (for Azure Automation) : Fetch Azure Capacity informations (Compute, Network and Storage quotas) and send a mail alert via Office 365 mail account for resource capacity above threshold.
.PARAMETER Location
Mandatory (with default of "francecentral").
Specify the location (region)
.PARAMETER Threshold
Mandatory (with default of "75").
Specify the resource capacity threshold.
.PARAMETER ShowConsoleOutput
Mandatory (with default of "$true").
Enable or Disable the console output
.PARAMETER ShowBeyondThresholdOnly
Mandatory (with default of "$false").
Show only resource with capacity above threshold
.PARAMETER AzureAutomationConnectionName
Mandatory (with default of "AzureRunAsAccount").
Specify the Automation connection used to read resources
.PARAMETER ExchangeOnlineMail
Mandatory (with default of "$false").
Enable or Disable the mail alert using Exchange Online (Office 365).
.PARAMETER ExchangeOnlineAutomationCredential
Optional
Specify Exchange Online Automation Credential (account used to send mail alert)
.PARAMETER ExchangeOnlineRecipient
Optional
Specify Exchange Online recipient (account who receive mail alert)
.NOTES
PREREQUSITES (see https://github.com/jdmsft/AzureCapacityWatcher#prerequisites for full details)
/!\ REQUIRE AZURE AUTOMATION /!\
Use this script as Azure Automation PowerShell runbook
/!\ REQUIRE AZURE SERVICE PRINCIPAL /!\
Like many apps / runbooks in Azure, this runbook needs a service principal to run (also known as Automation RunAs Account / Automation Connection).
/!\ REQUIRE AZURE AUTOMATION ASSETS (Shared Resources) /!\
* Module : Az.Accounts, Az.Compute, Az.Network and Az.Storage
* Connection : Azure (to read resources capacity)
* Certificate : used by above connection to authenticate
* Schedule : to automate your runbook execution, you should define an Automation schedule associated to this runbook for a recurring mail alert.
PS MODULE DEPENDENCIES
Az.Accounts (tested on v2.5.3)
Az.Compute (tested on v4.17.0)
Az.Network (tested on v4.11.0)
Az.Storage (testeed on v3.11.0)
#>
param (
[string]$Location = 'francecentral',
[int]$Threshold = 75,
[boolean]$ShowConsoleOutput = $true,
[boolean]$ShowBeyondThresholdOnly = $false,
[string]$AzureAutomationConnectionName = 'AzureRunAsAccount',
[boolean]$ExchangeOnlineMail = $false,
[string]$ExchangeOnlineAutomationCredential,
[string]$ExchangeOnlineRecipient
)
If ($PSPrivateMetadata.JobId)
{
Write-Verbose "Runbook environment : Azure Automation"
Write-Verbose "Azure Connector for Azure Automation v1.0.0`n(c) 2020 - 2021 JDMSFT. All right Reserved."
$ConnectorTimer = [system.diagnostics.stopwatch]::StartNew()
Try
{
Write-Verbose "[CONNECTOR] Connecting to Azure ..."
$AutomationConnection = Get-AutomationConnection -Name $AzureAutomationConnectionName
Connect-AzAccount `
-TenantId $AutomationConnection.TenantId `
-ApplicationId $AutomationConnection.ApplicationId `
-CertificateThumbprint $AutomationConnection.CertificateThumbprint `
| Out-Null
}
Catch
{
If (!$AutomationConnection)
{
$ErrorMessage = "Connection $AutomationConnectionName not found."
throw $ErrorMessage
}
Else
{
Write-Error $($_) ; throw "[$($_.InvocationInfo.ScriptLineNumber)] $($_.InvocationInfo.Line.TrimStart()) >> $($_)"
}
}
$ConnectorTimer.Stop()
Write-Verbose "[CONNECTOR] Elapsed time : $($ConnectorTimer.Elapsed)"
}
$ComputeStorageCategory = @('DiskAccessCount', 'DiskAccessCount', 'DiskEncryptionSetCount', 'Gallery', 'GalleryImage', 'GalleryImageVersion', 'PremiumDiskCount', 'PremiumSnapshotCount', 'PremiumZRSDiskCount', , 'StandardSSDStorageDisks', 'StandardSSDStorageSnapshots', 'StandardSSDZRSStorageDisks', 'StandardStorageSnapshots', 'UltraSSDDiskCount', 'UltraSSDDiskSizeInGB', 'ZRSSnapshotCount')
$output = @()
Get-AzSubscription | % {
Select-AzSubscription $_ | Out-Null
$SubscriptionName = $_.Name
# Compute
Get-AzVMUsage -Location $Location | % {
$Remain = ($_.Limit - $_.CurrentValue)
If ($_.Limit -ne 0) { $Usage = ($_.CurrentValue / $_.Limit) } Else { $Usage = 0 }
If ($_.Name.Value -notin $ComputeStorageCategory) { $Category = 'Compute' } Else { $Category = 'Storage' }
$output += [PSCustomObject]@{SubscriptionName = $SubscriptionName ; Location = $Location ; Category = $Category ; Resource = $_.Name.LocalizedValue ; UsageRaw = $Usage ; Usage =
$Usage.tostring("P") ; TotalUsed = $_.CurrentValue ; TotalRemaining = $Remain ; Limit = $_.Limit
}
}
# Storage
Get-AzStorageUsage -Location $Location | % {
$Remain = ($_.Limit - $_.CurrentValue)
If ($_.Limit -ne 0) { $Usage = ($_.CurrentValue / $_.Limit) } Else { $Usage = 0 }
$output += [PSCustomObject]@{SubscriptionName = $SubscriptionName ; Location = $Location ; Category = 'Storage' ; Resource = $_.LocalizedName ; UsageRaw = $Usage ; Usage =
$Usage.tostring("P") ; TotalUsed = $_.CurrentValue ; TotalRemaining = $Remain ; Limit = $_.Limit
}
}
# Network
Get-AzNetworkUsage -Location $Location | % {
If ($_.Name.Value -ne 'NetworkWatchers')
{
$Remain = ($_.Limit - $_.CurrentValue)
If ($_.Limit -ne 0) { $Usage = ($_.CurrentValue / $_.Limit) } Else { $Usage = 0 }
$output += [PSCustomObject]@{SubscriptionName = $SubscriptionName ; Location = $Location ; Category = 'Network' ; Resource = $_.Name.LocalizedValue ; UsageRaw = $Usage ; Usage =
$Usage.tostring("P") ; TotalUsed = $_.CurrentValue ; TotalRemaining = $Remain ; Limit = $_.Limit
}
}
}
}
# Console
If ($ShowBeyondThresholdOnly) { $output = $output | ? {($_.UsageRaw * 100) -ge $Threshold} | select * -ExcludeProperty UsageRaw | sort SubscriptionName, Location, Category, Resource}
Else { $output = $output | select * -ExcludeProperty UsageRaw | sort SubscriptionName, Location, Category, Resource }
If ($ShowConsoleOutput) {$output | ft -AutoSize}
# Mail
If ($ExchangeOnlineMail)
{
$MailSubject = "Azure Capacity Watcher : resource(s) capacity beyond threshold ($Threshold%) !"
$MailCredential = Get-AutomationPSCredential -Name $ExchangeOnlineAutomationCredential
$MailBody = ($output | ConvertTo-Html | Out-String) + "`n`nRECOMMENDATION : Please manage the number of the Azure resources involved in your subscription(s) or submit a new request to expand these limits (soft limit only)."
Write-Output "[RUNBOOK] Sending mail from Exchange Online ..."
Send-MailMessage -Credential $MailCredential -SmtpServer smtp.office365.com -Port 587 `
-To $ExchangeOnlineRecipient `
-Subject $MailSubject `
-Body $MailBody `
-From $MailCredential.UserName `
-BodyAsHtml `
-UseSsl
}