functions/Get-AzSMUnusedPrivateEndpoints.ps1
|
function global:Get-AzSMUnusedPrivateEndpoints { <# .SYNOPSIS List Private Endpoints with no connections in a subscription. .DESCRIPTION List Private Endpoints with no connections in a subscription or a single resource group. The connected resource of each Private Link connection is queried before an endpoint is returned. A Private Endpoint is returned when it has no connection that is Approved or Pending to a resource that still exists. If a connected resource cannot be queried for a reason other than not found, such as no access, the endpoint is treated as in use and a warning is written. .PARAMETER SubscriptionID Azure subscription ID in the format, 00000000-0000-0000-0000-000000000000 .PARAMETER ResourceGroupName A single Azure resource group name to scope query to .OUTPUTS Microsoft.Azure.Commands.Network.Models.PSPrivateEndpoint .EXAMPLE Get-AzSMUnusedPrivateEndpoints -SubscriptionID 00000000-0000-0000-0000-000000000000 Get a list of Private Endpoints with no connections in a subscription. .EXAMPLE Get-AzSMUnusedPrivateEndpoints -SubscriptionID 00000000-0000-0000-0000-000000000000 -ResourceGroupName MyResourceGroup Get a list of Private Endpoints with no connections in a single resource group. .EXAMPLE Get-AzSMUnusedPrivateEndpoints -SubscriptionID 00000000-0000-0000-0000-000000000000 | Remove-AzPrivateEndpoint -Force Remove Private Endpoints with no connections in a subscription without confirmation. .NOTES * CAN be piped to Remove-AzPrivateEndpoint. * When piping to remove resources, include the -force parameter to supress prompts. .LINK #> [CmdletBinding( DefaultParameterSetName='SubscriptionID', ConfirmImpact='Low' )] param( [Parameter(Mandatory=$true)][string] $SubscriptionID, [Parameter(Mandatory=$false)][string] $ResourceGroupName ) $null = Set-AzContext -SubscriptionId $SubscriptionID Write-Debug ('Subscription ID: {0}' -f $SubscriptionID) $unusedEndpoints = New-Object System.Collections.ArrayList #Cache connected resource lookups, many endpoints can connect to the same resource. $resourceExists = @{} if ($ResourceGroupName.Length -gt 0) { $endpoints=Get-AzPrivateEndpoint -ResourceGroupName $ResourceGroupName } else { $endpoints=Get-AzPrivateEndpoint } foreach ($endpoint in $endpoints) { $connected = $false $connections = @(@($endpoint.PrivateLinkServiceConnections) + @($endpoint.ManualPrivateLinkServiceConnections) | Where-Object {$null -ne $_}) foreach ($connection in $connections) { $connectedResourceId = $connection.PrivateLinkServiceId if ([string]::IsNullOrEmpty($connectedResourceId)) { continue } if (-not $resourceExists.ContainsKey($connectedResourceId)) { try { $resource = Get-AzResource -ResourceId $connectedResourceId -ErrorAction Stop $resourceExists[$connectedResourceId] = $null -ne $resource } catch { if ($_.Exception.Message -match 'NotFound|not found|could not be found') { $resourceExists[$connectedResourceId] = $false } else { Write-Warning ('Could not query connected resource {0} for Private Endpoint {1}, treating as in use. {2}' -f $connectedResourceId, $endpoint.Name, $_.Exception.Message) $resourceExists[$connectedResourceId] = $true } } } Write-Debug ('Private Endpoint: {0} Connected resource: {1} Exists: {2} Status: {3}' -f $endpoint.Name, $connectedResourceId, $resourceExists[$connectedResourceId], $connection.PrivateLinkServiceConnectionState.Status) if ($resourceExists[$connectedResourceId] -and $connection.PrivateLinkServiceConnectionState.Status -in 'Approved','Pending') { $connected = $true break } } if (-not $connected) { $null = $unusedEndpoints.Add($endpoint) } } Return $unusedEndpoints } Export-ModuleMember -Function Get-AzSMUnusedPrivateEndpoints |