Public/Find-AzureUtilsOrphanResource.ps1
|
function Find-AzureUtilsOrphanResource { <# .SYNOPSIS Finds orphaned Azure resources (unused, unassociated). .DESCRIPTION Uses Azure Resource Graph to find resources that appear to be orphaned and explains why in a 'Reason' column. Returns one object per resource (also shown as a table on the console). Covered categories: Disk unattached managed disks NetworkInterface NICs not attached to a VM or private endpoint PublicIP public IPs with no IP configuration / NAT gateway NetworkSecurityGroup NSGs not associated to NICs or subnets RouteTable route tables not associated to subnets These are heuristics; review before acting. .PARAMETER SubscriptionId One or more subscription IDs. Default: every enabled subscription. .PARAMETER ManagementGroupId One or more management groups to scan (requires Az.ResourceGraph). .PARAMETER Type Limit the orphan categories to check. Defaults to all of them. .EXAMPLE Find-AzureUtilsOrphanResource .EXAMPLE Find-AzureUtilsOrphanResource -Type Disk, PublicIP | Sort-Object SubscriptionName, ResourceGroup .OUTPUTS AzureUtils.OrphanResource #> [CmdletBinding(DefaultParameterSetName = 'Subscriptions')] [OutputType('AzureUtils.OrphanResource')] param( [Parameter(ParameterSetName = 'Subscriptions')] [string[]] $SubscriptionId, [Parameter(ParameterSetName = 'ManagementGroup', Mandatory)] [string[]] $ManagementGroupId, [ValidateSet('Disk', 'NetworkInterface', 'PublicIP', 'NetworkSecurityGroup', 'RouteTable')] [string[]] $Type = @('Disk', 'NetworkInterface', 'PublicIP', 'NetworkSecurityGroup', 'RouteTable') ) $null = Assert-AzureUtilsContext $resolved = Resolve-AzureUtilsScope -SubscriptionId $SubscriptionId -ManagementGroupId $ManagementGroupId if ($resolved.Type -eq 'Subscription' -and -not $resolved.HasSubscriptions) { Write-Warning 'No accessible subscriptions in scope.' return } $query = New-AzureUtilsOrphanResourceQuery -Type $Type $nameMap = $resolved.NameMap $scope = $resolved.Scope Write-Verbose "Orphan query:`n$query" Invoke-AzureUtilsGraphQuery -Query $query @scope | ForEach-Object { $subId = [string]$_.subscriptionId [pscustomobject]@{ PSTypeName = 'AzureUtils.OrphanResource' Name = $_.name ResourceType = $_.type ResourceGroup = $_.resourceGroup Location = $_.location SubscriptionName = if ($nameMap.ContainsKey($subId)) { $nameMap[$subId] } else { $subId } SubscriptionId = $subId Reason = $_.reason Tags = ConvertTo-AzureUtilsHashtable -InputObject $_.tags ResourceId = $_.id } } } |