Skip to content

Instantly share code, notes, and snippets.

@heaths
Last active April 1, 2021 20:18
Show Gist options
  • Save heaths/a3810f36a56177ae1cbe4cf57af0b02f to your computer and use it in GitHub Desktop.
Save heaths/a3810f36a56177ae1cbe4cf57af0b02f to your computer and use it in GitHub Desktop.
Example script to delete expired or non-standard named resource groups
#!/usr/bin/env pwsh
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
#Requires -Version 6.0
#Requires -PSEdition Core
#Requires -Modules @{ModuleName='Az.Accounts'; ModuleVersion='1.6.4'}
#Requires -Modules @{ModuleName='Az.Resources'; ModuleVersion='1.8.0'}
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
[OutputType([Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResourceGroup])]
param (
[Parameter()]
[ValidatePattern('^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$')]
[string] $SubscriptionId,
[Parameter()]
[switch] $Force,
[Parameter()]
[switch] $AsJob,
[Parameter()]
[switch] $PassThru
)
# By default stop for any error.
if (!$PSBoundParameters.ContainsKey('ErrorAction')) {
$ErrorActionPreference = 'Stop'
}
# Do not check $Force in conditions below which elides the prompts for -WhatIf.
# See https://docs.microsoft.com/powershell/scripting/learn/deep-dives/everything-about-shouldprocess#shouldprocess--force
if ($Force) {
$ConfirmPreference = 'None'
}
# Support actions to invoke on exit.
$exitActions = @({
if ($exitActions.Count -gt 1) {
Write-Verbose 'Running registered exit actions'
}
})
# This script is intended for interactive users. Make sure they are logged in or fail.
$context = Get-AzContext
if (!$context) {
Write-Error 'You must be already logged in to use this script. Run Connect-AzAccount and try again.' -Category PermissionDenied -RecommendedAction 'Run Connect-AzAccount and try again.'
}
$currentSubscriptionId = $context.Subscription.Id
# If no subscription was specified, try to select the Azure SDK Developer Playground subscription.
# Ignore errors to leave the automatically selected subscription.
if ($SubscriptionId) {
if ($currentSubscriptionId -ne $SubscriptionId) {
Write-Verbose "Selecting subscription '$SubscriptionId'"
$null = Select-AzSubscription -Subscription $SubscriptionId -WhatIf:$false
$exitActions += {
Write-Verbose "Selecting previous subscription '$currentSubscriptionId'"
$null = Select-AzSubscription -Subscription $currentSubscriptionId -WhatIf:$false
}
# Update the context.
$context = Get-AzContext
}
} else {
if ($currentSubscriptionId -ne $context.Subscription.Id) {
Write-Verbose "Attempting to select subscription 'Azure SDK Developer Playground (faa080af-c1d8-40ad-9cce-e1a450ca5b57)'"
$null = Select-AzSubscription -Subscription 'faa080af-c1d8-40ad-9cce-e1a450ca5b57' -ErrorAction Ignore -WhatIf:$false
# Update the context.
$context = Get-AzContext
}
$SubscriptionId = $context.Subscription.Id
$PSBoundParameters['SubscriptionId'] = $SubscriptionId
}
# Use cache of well-known team subs without having to be authenticated.
$wellKnownSubscriptions = @{
'faa080af-c1d8-40ad-9cce-e1a450ca5b57' = 'Azure SDK Developer Playground'
'a18897a6-7e44-457d-9260-f2854c0aca42' = 'Azure SDK Engineering System'
'2cd617ea-1866-46b1-90e3-fffb087ebf9b' = 'Azure SDK Test Resources'
}
# Print which subscription is currently selected.
$subscriptionName = $context.Subscription.Id
if ($wellKnownSubscriptions.ContainsKey($subscriptionName)) {
$subscriptionName = '{0} ({1})' -f $wellKnownSubscriptions[$subscriptionName], $subscriptionName
}
Write-Verbose "Using subscription '$subscriptionName'"
try {
Write-Verbose "Getting all resource groups in subscription '$subscriptionName'"
$resourceGroups = Get-AzResourceGroup
foreach ($resourceGroup in $resourceGroups) {
if ($resourceGroup.Tags -and $resourceGroup.Tags.ContainsKey('DeleteAfter')) {
$deleteAfter = [DateTimeOffset]::MaxValue
if ([DateTimeOffset]::TryParse($resourceGroup.Tags['DeleteAfter'], [ref] $deleteAfter) -and $deleteAfter -lt [DateTimeOffset]::Now) {
if ($PSCmdlet.ShouldProcess($resourceGroup.ResourceGroupName, 'Delete expired resource group')) {
if ($PassThru) {
$resourceGroup
}
$null = Remove-AzResourceGroup $resourceGroup.ResourceGroupName -Force:$true -AsJob:$AsJob
} elseif ($WhatIfPreference -and $PassThru) {
$resourceGroup
}
}
} elseif ($resourceGroup.ResourceGroupName -notmatch 'rg-.*') {
if ($PSCmdlet.ShouldProcess($resourceGroup.ResourceGroupName, 'Delete resource group with non-standard name')) {
if ($PassThru) {
$resourceGroup
}
# $null = Remove-AzResourceGroup $resourceGroup.ResourceGroupName -Force:$true -AsJob:$AsJob
} elseif ($WhatIfPreference -and $PassThru) {
$resourceGroup
}
}
}
} finally {
$exitActions.Invoke()
}
<#
.SYNOPSIS
Deletes resource groups that have expired or do not match standard naming conventions.
.DESCRIPTION
A resource group that contains a "DeleteAfter" tag will be checked if it has expired.
A resource group may also be deleted if it does not match the standard naming convention 'rg-.*'.
You can pass -WhatIf to see which ones would be deleted without actually deleting them.
You must be logged into Azure to run this command.
.PARAMETER SubscriptionId
The subscription ID from which to enumerate resource groups. By default this is your current subscription.
.PARAMETER Force
Do not prompt to delete resource groups. If passed with -WhatIf, -WhatIf takes precedence.
.PARAMETER AsJob
Delete resource groups in a background job.
By default, the script will wait for each resource group to be deleted.
.PARAMETER PassThru
Returns the resource groups that will be deleted. You can use this with -WhatIf to discover all invalidated resource groups.
.EXAMPLE
Remove-AzSdResourceGroups -WhatIf
See what would be deleted without actually deleting them.
.EXAMPLE
Remove-AzSdkResourceGroups -Force -AsJob; Get-Job
Forcibly remove all invalidated resource groups in a job then see which jobs are running.
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment