-
Notifications
You must be signed in to change notification settings - Fork 456
/
Invoke-ResourcePostRemoval.ps1
157 lines (139 loc) · 8.19 KB
/
Invoke-ResourcePostRemoval.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
<#
.SYNOPSIS
Remove any artifacts that remain of the given resource
.DESCRIPTION
Remove any artifacts that remain of the given resource. For example, some resources such as key vaults usually go into a soft-delete state from which we want to purge them from.
.PARAMETER ResourceId
Mandatory. The resourceID of the resource to remove
.PARAMETER Type
Mandatory. The type of the resource to remove
.EXAMPLE
Invoke-ResourcePostRemoval -Type 'Microsoft.KeyVault/vaults' -ResourceId '/subscriptions/.../resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/myVault'
Purge the resource 'myVault' of type 'Microsoft.KeyVault/vaults' with ID '/subscriptions/.../resourceGroups/validation-rg/providers/Microsoft.KeyVault/vaults/myVault' if no purge protection is enabled
#>
function Invoke-ResourcePostRemoval {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory = $true)]
[string] $ResourceId,
[Parameter(Mandatory = $true)]
[string] $Type
)
switch ($Type) {
'Microsoft.AppConfiguration/configurationStores' {
$subscriptionId = $ResourceId.Split('/')[2]
$resourceName = Split-Path $ResourceId -Leaf
# Fetch service in soft-delete
$getPath = '/subscriptions/{0}/providers/Microsoft.AppConfiguration/deletedConfigurationStores?api-version=2021-10-01-preview' -f $subscriptionId
$getRequestInputObject = @{
Method = 'GET'
Path = $getPath
}
$softDeletedConfigurationStore = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.configurationStoreId -eq $ResourceId }
if ($softDeletedConfigurationStore) {
# Purge service
$purgePath = '/subscriptions/{0}/providers/Microsoft.AppConfiguration/locations/{1}/deletedConfigurationStores/{2}/purge?api-version=2021-10-01-preview' -f $subscriptionId, $softDeletedConfigurationStore.properties.location, $resourceName
$purgeRequestInputObject = @{
Method = 'POST'
Path = $purgePath
}
Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose
if ($PSCmdlet.ShouldProcess(('App Configuration Store with ID [{0}]' -f $softDeletedConfigurationStore.properties.configurationStoreId), 'Purge')) {
$response = Invoke-AzRestMethod @purgeRequestInputObject
if ($response.StatusCode -ne 200) {
throw ('Purge of resource [{0}] failed with error code [{1}]' -f $ResourceId, $response.StatusCode)
}
}
}
break
}
'Microsoft.KeyVault/vaults' {
$resourceName = Split-Path $ResourceId -Leaf
$matchingKeyVault = Get-AzKeyVault -InRemovedState | Where-Object { $_.resourceId -eq $ResourceId }
if ($matchingKeyVault -and -not $matchingKeyVault.EnablePurgeProtection) {
Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose
if ($PSCmdlet.ShouldProcess(('Key Vault with ID [{0}]' -f $matchingKeyVault.Id), 'Purge')) {
try {
$null = Remove-AzKeyVault -ResourceId $matchingKeyVault.Id -InRemovedState -Force -Location $matchingKeyVault.Location -ErrorAction 'Stop'
} catch {
if ($_.Exception.Message -like '*DeletedVaultPurge*') {
Write-Warning ('Purge protection for key vault [{0}] enabled. Skipping. Scheduled purge date is [{1}]' -f $resourceName, $matchingKeyVault.ScheduledPurgeDate)
} else {
throw $_
}
}
}
}
break
}
'Microsoft.CognitiveServices/accounts' {
$resourceGroupName = $ResourceId.Split('/')[4]
$resourceName = Split-Path $ResourceId -Leaf
$matchingAccount = Get-AzCognitiveServicesAccount -InRemovedState | Where-Object { $_.AccountName -eq $resourceName }
if ($matchingAccount) {
Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose
if ($PSCmdlet.ShouldProcess(('Cognitive services account with ID [{0}]' -f $matchingAccount.Id), 'Purge')) {
$null = Remove-AzCognitiveServicesAccount -InRemovedState -Force -Location $matchingAccount.Location -ResourceGroupName $resourceGroupName -Name $matchingAccount.AccountName
}
}
break
}
'Microsoft.ApiManagement/service' {
$subscriptionId = $ResourceId.Split('/')[2]
$resourceName = Split-Path $ResourceId -Leaf
# Fetch service in soft-delete
$getPath = '/subscriptions/{0}/providers/Microsoft.ApiManagement/deletedservices?api-version=2021-08-01' -f $subscriptionId
$getRequestInputObject = @{
Method = 'GET'
Path = $getPath
}
$softDeletedService = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.serviceId -eq $ResourceId }
if ($softDeletedService) {
# Purge service
$purgePath = '/subscriptions/{0}/providers/Microsoft.ApiManagement/locations/{1}/deletedservices/{2}?api-version=2020-06-01-preview' -f $subscriptionId, $softDeletedService.location, $resourceName
$purgeRequestInputObject = @{
Method = 'DELETE'
Path = $purgePath
}
Write-Verbose ('[*] Purging resource [{0}] of type [{1}]' -f $resourceName, $Type) -Verbose
if ($PSCmdlet.ShouldProcess(('API management service with ID [{0}]' -f $softDeletedService.properties.serviceId), 'Purge')) {
$null = Invoke-AzRestMethod @purgeRequestInputObject
}
}
break
}
'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems' {
# Remove protected VM
# Required if e.g. a VM was listed in an RSV and only that VM is removed
$vaultId = $ResourceId.split('/backupFabrics/')[0]
$resourceName = Split-Path $ResourceId -Leaf
$softDeleteStatus = (Get-AzRecoveryServicesVaultProperty -VaultId $vaultId).SoftDeleteFeatureState
if ($softDeleteStatus -ne 'Disabled') {
if ($PSCmdlet.ShouldProcess(('Soft-delete on RSV [{0}]' -f $vaultId), 'Set')) {
$null = Set-AzRecoveryServicesVaultProperty -VaultId $vaultId -SoftDeleteFeatureState 'Disable'
}
}
$backupItemInputObject = @{
BackupManagementType = 'AzureVM'
WorkloadType = 'AzureVM'
VaultId = $vaultId
Name = $resourceName
}
if ($backupItem = Get-AzRecoveryServicesBackupItem @backupItemInputObject -ErrorAction 'SilentlyContinue') {
Write-Verbose (' [-] Removing Backup item [{0}] from RSV [{1}]' -f $backupItem.Name, $vaultId) -Verbose
if ($backupItem.DeleteState -eq 'ToBeDeleted') {
if ($PSCmdlet.ShouldProcess('Soft-deleted backup data removal', 'Undo')) {
$null = Undo-AzRecoveryServicesBackupItemDeletion -Item $backupItem -VaultId $vaultId -Force
}
}
if ($PSCmdlet.ShouldProcess(('Backup item [{0}] from RSV [{1}]' -f $backupItem.Name, $vaultId), 'Remove')) {
$null = Disable-AzRecoveryServicesBackupProtection -Item $backupItem -VaultId $vaultId -RemoveRecoveryPoints -Force
}
}
# Undo a potential soft delete state change
$null = Set-AzRecoveryServicesVaultProperty -VaultId $vaultId -SoftDeleteFeatureState $softDeleteStatus.TrimEnd('d')
break
}
### CODE LOCATION: Add custom post-removal operation here
}
}