Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
793e0e5
Update custom publishing resources
MariusStorhaug Aug 20, 2023
38e2cf9
Add script for purging machine learning workspace
MariusStorhaug Aug 20, 2023
076fe87
reset settings
MariusStorhaug Aug 20, 2023
0c5896b
remove double space
MariusStorhaug Aug 20, 2023
fd73e7c
fix attempt #1
MariusStorhaug Aug 20, 2023
03c2939
correct spelling of retry
MariusStorhaug Aug 20, 2023
583a976
align with Invoke-ResourceRemoval.ps1
MariusStorhaug Aug 20, 2023
bf37cd5
fix
MariusStorhaug Aug 21, 2023
91c3f53
Reset files
MariusStorhaug Aug 21, 2023
d4de9cd
Update utilities/pipelines/resourceRemoval/helper/Remove-ResourceList…
MariusStorhaug Aug 31, 2023
686e595
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceRemo…
MariusStorhaug Aug 31, 2023
9f5d68c
Restructure
MariusStorhaug Sep 4, 2023
1ba52bc
added break again
MariusStorhaug Sep 4, 2023
e667e34
align outputs/logs
MariusStorhaug Sep 4, 2023
361bf74
Moved out of default to before switch
MariusStorhaug Sep 4, 2023
9edbecb
Merge branch 'main' of https://github.com/MariusStorhaug/ResourceModu…
MariusStorhaug Sep 4, 2023
6b184a9
Apply suggestions from code review
MariusStorhaug Sep 4, 2023
6f30f0c
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceRemo…
MariusStorhaug Sep 4, 2023
576199b
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceRemo…
MariusStorhaug Sep 4, 2023
6f45109
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceRemo…
MariusStorhaug Sep 4, 2023
c15d331
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceRemo…
MariusStorhaug Sep 4, 2023
7b88608
Remove DevTestLab as logic is covered with regular flow now
MariusStorhaug Sep 4, 2023
12953cb
Change logging and removal loop slightly
MariusStorhaug Sep 4, 2023
95f67df
Fixing logic
MariusStorhaug Sep 4, 2023
70b57e8
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceRemo…
AlexanderSehr Sep 4, 2023
27d0f2a
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceLock…
MariusStorhaug Sep 4, 2023
c7095ef
Update utilities/pipelines/resourceRemoval/helper/Invoke-ResourceLock…
MariusStorhaug Sep 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ jobs:
@{ Name = 'Az.CognitiveServices' },
@{ Name = 'Az.Compute' },
@{ Name = 'Az.KeyVault' },
@{ Name = 'Az.MachineLearningServices' },
@{ Name = 'Az.Monitor' },
@{ Name = 'Az.OperationalInsights' },
@{ Name = 'Az.RecoveryServices' }
Expand Down
1 change: 1 addition & 0 deletions .github/actions/templates/setEnvironment/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ runs:
@{ Name = 'Az.CognitiveServices' },
@{ Name = 'Az.Compute' },
@{ Name = 'Az.KeyVault' },
@{ Name = 'Az.MachineLearningServices' },
@{ Name = 'Az.Monitor' },
@{ Name = 'Az.OperationalInsights' },
@{ Name = 'Az.RecoveryServices' }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<#
.SYNOPSIS
Remove resource locks from a resource or a specific resource lock.

.DESCRIPTION
Remove resource locks from a resource or a specific resource lock.

.PARAMETER ResourceId
Mandatory. The resourceID of the resource to check, and remove a resource lock from.

.PARAMETER Type
Optional. The type of the resource. If the resource is a lock, the lock itself will be removed. If the resource is a resource, all locks on the resource will be removed. If not specified, the resource will be checked for locks, and if any are found, all locks will be removed.

.PARAMETER RetryLimit
Optional. The number of times to retry checking if the lock is removed.

.PARAMETER RetryInterval
Optional. The number of seconds to wait between each retry.

.EXAMPLE
Invoke-ResourceLockRemoval -ResourceId '/subscriptions/.../resourceGroups/validation-rg/.../resource-name'

Check if the resource 'resource-name' is locked. If it is, remove the lock.
#>
function Invoke-ResourceLockRemoval {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory = $true)]
[string] $ResourceId,

[Parameter(Mandatory = $false)]
[string] $Type,

[Parameter(Mandatory = $false)]
[int] $RetryLimit = 10,

[Parameter(Mandatory = $false)]
[int] $RetryInterval = 10
)
# Load functions
. (Join-Path $PSScriptRoot 'Invoke-ResourceLockRetrieval.ps1')

$resourceLock = Invoke-ResourceLockRetrieval -ResourceId $ResourceId -Type $Type

$isLocked = $resourceLock.count -gt 0
if (-not $isLocked) {
return
}

$resourceLock | ForEach-Object {
Write-Warning (' [-] Removing lock [{0}] on [{1}] of type [{2}].' -f $_.Name, $_.ResourceName, $_.ResourceType)
if ($PSCmdlet.ShouldProcess(('Lock [{0}] on resource [{1}] of type [{2}].' -f $_.Name, $_.ResourceName, $_.ResourceType ), 'Remove')) {
$null = $_ | Remove-AzResourceLock -Force
}
}

$retryCount = 0
do {
$retryCount++
if ($retryCount -ge $RetryLimit) {
Write-Warning (' [!] Lock was not removed after {1} seconds. Continuing with resource removal.' -f ($retryCount * $RetryInterval))
break
}
Write-Verbose ' [⏱️] Waiting for lock to be removed.' -Verbose
Start-Sleep -Seconds $RetryInterval

# Rechecking the resource locks to see if they have been removed.
$resourceLock = Invoke-ResourceLockRetrieval -ResourceId $ResourceId -Type $Type
$isLocked = $resourceLock.count -gt 0
} while ($isLocked)

Write-Verbose (' [-] [{0}] resource lock(s) removed.' -f $resourceLock.count) -Verbose
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<#
.SYNOPSIS
Gets resource locks on a resource or a specific resource lock.

.DESCRIPTION
Gets resource locks on a resource or a specific resource lock.

.PARAMETER ResourceId
Mandatory. The resourceID of the resource to check or the resource lock to check.

.PARAMETER Type
Optional. The type of the resource.
If the resource is a lock, the lock itself will be returned.
If the resource is not a lock, all locks on the resource will be returned.

.EXAMPLE
Invoke-ResourceLockRetrieval -ResourceId '/subscriptions/.../resourceGroups/validation-rg/.../resource-name'

Check if the resource 'resource-name' is locked. If it is, return the lock.

.EXAMPLE
Invoke-ResourceLockRetrieval -ResourceId '/subscriptions/.../resourceGroups/validation-rg/.../resource-name/providers/Microsoft.Authorization/locks/lock-name' -Type 'Microsoft.Authorization/locks'

Return the lock 'lock-name' on the resource 'resource-name'.

.NOTES
Needed as the AzPwsh cmdlet Get-AzResourceLock does not support getting a specific lock by LockId.
#>
function Invoke-ResourceLockRetrieval {
[OutputType([System.Management.Automation.PSCustomObject])]
param (
[Parameter(Mandatory = $true)]
[string] $ResourceId,

[Parameter(Mandatory = $false)]
[string] $Type = ''
)
if ($Type -eq 'Microsoft.Authorization/locks') {
$lockName = ($ResourceId -split '/')[-1]
$lockScope = ($ResourceId -split '/providers/Microsoft.Authorization/locks')[0]
return Get-AzResourceLock -LockName $lockName -Scope $lockScope -ErrorAction SilentlyContinue
} else {
return Get-AzResourceLock -Scope $ResourceId -ErrorAction SilentlyContinue
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ function Invoke-ResourcePostRemoval {
[string] $Type
)

switch ($type) {
switch ($Type) {
'Microsoft.AppConfiguration/configurationStores' {
$subscriptionId = $resourceId.Split('/')[2]
$subscriptionId = $ResourceId.Split('/')[2]
$resourceName = Split-Path $ResourceId -Leaf

# Fetch service in soft-delete
Expand All @@ -38,7 +38,7 @@ function Invoke-ResourcePostRemoval {
Method = 'GET'
Path = $getPath
}
$softDeletedConfigurationStore = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.configurationStoreId -eq $resourceId }
$softDeletedConfigurationStore = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.configurationStoreId -eq $ResourceId }

if ($softDeletedConfigurationStore) {
# Purge service
Expand All @@ -47,6 +47,7 @@ function Invoke-ResourcePostRemoval {
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) {
Expand All @@ -61,7 +62,7 @@ function Invoke-ResourcePostRemoval {

$matchingKeyVault = Get-AzKeyVault -InRemovedState | Where-Object { $_.resourceId -eq $ResourceId }
if ($matchingKeyVault -and -not $matchingKeyVault.EnablePurgeProtection) {
Write-Verbose ("Purging key vault [$resourceName]") -Verbose
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'
Expand All @@ -77,19 +78,20 @@ function Invoke-ResourcePostRemoval {
break
}
'Microsoft.CognitiveServices/accounts' {
$resourceGroupName = $resourceId.Split('/')[4]
$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]
$subscriptionId = $ResourceId.Split('/')[2]
$resourceName = Split-Path $ResourceId -Leaf

# Fetch service in soft-delete
Expand All @@ -98,7 +100,7 @@ function Invoke-ResourcePostRemoval {
Method = 'GET'
Path = $getPath
}
$softDeletedService = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.serviceId -eq $resourceId }
$softDeletedService = ((Invoke-AzRestMethod @getRequestInputObject).Content | ConvertFrom-Json).value | Where-Object { $_.properties.serviceId -eq $ResourceId }

if ($softDeletedService) {
# Purge service
Expand All @@ -107,6 +109,7 @@ function Invoke-ResourcePostRemoval {
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
}
Expand All @@ -116,7 +119,7 @@ function Invoke-ResourcePostRemoval {
'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]
$vaultId = $ResourceId.split('/backupFabrics/')[0]
$resourceName = Split-Path $ResourceId -Leaf
$softDeleteStatus = (Get-AzRecoveryServicesVaultProperty -VaultId $vaultId).SoftDeleteFeatureState
if ($softDeleteStatus -ne 'Disabled') {
Expand All @@ -132,7 +135,7 @@ function Invoke-ResourcePostRemoval {
Name = $resourceName
}
if ($backupItem = Get-AzRecoveryServicesBackupItem @backupItemInputObject -ErrorAction 'SilentlyContinue') {
Write-Verbose ('Removing Backup item [{0}] from RSV [{1}]' -f $backupItem.Name, $vaultId) -Verbose
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')) {
Expand Down
Loading