Azure subnets: export full inventory
Overview
This PowerShell script searches all enabled Azure subscriptions available to the current account, inventories every virtual network subnet, and exports the results to CSV with useful networking details.
This is useful when you need to quickly identify:
- Which subscriptions, resource groups, and VNets contain each subnet.
- The address space configured on each subnet.
- Which NSG, route table, or NAT Gateway is attached.
- Which service endpoints and delegations are configured.
- Whether private endpoint and private link service network policies are enabled.
What the script does
- Retrieves enabled subscriptions with
Get-AzSubscription. - Switches context into each subscription with
Set-AzContext. - Reads VNets with
Get-AzVirtualNetwork. - Iterates through every subnet in every VNet.
- Normalizes commonly needed properties into flat CSV fields.
- Prints progress to the console while collecting results.
- Exports the final inventory to CSV.
Prerequisites
Install the Azure PowerShell modules if needed:
Install-Module Az -Scope CurrentUserConnect to Azure before running the script:
Connect-AzAccountThe account must have permission to read virtual networks and subnets in the subscriptions being checked.
Output
The CSV is written to:
$HOME/azure-subnets-inventory.csvEach row includes:
SubscriptionNameSubscriptionIdResourceGroupVNetNameVNetLocationVNetAddressSpaceVNetIdSubnetNameSubnetAddressPrefixesSubnetIdSubnetProvisioningStateNetworkSecurityGroupNameNetworkSecurityGroupIdRouteTableNameRouteTableIdNatGatewayNameNatGatewayIdServiceEndpointsServiceEndpointPoliciesDelegationsPrivateEndpointNetworkPoliciesPrivateLinkServiceNetworkPoliciesDefaultOutboundAccessIpConfigurationsCount
PowerShell script
$OutputFile = "$HOME/azure-subnets-inventory.csv"
$Results = [System.Collections.Generic.List[object]]::new()
function Get-ResourceNameFromId {
param(
[string]$ResourceId
)
if ([string]::IsNullOrWhiteSpace($ResourceId)) {
return ""
}
return ($ResourceId -split "/")[-1]
}
$Subscriptions = Get-AzSubscription |
Where-Object { $_.State -eq "Enabled" }
foreach ($Subscription in $Subscriptions) {
Write-Host ""
Write-Host "Processing subscription: $($Subscription.Name) [$($Subscription.Id)]" -ForegroundColor Cyan
try {
Set-AzContext -SubscriptionId $Subscription.Id -ErrorAction Stop | Out-Null
}
catch {
Write-Warning "Unable to switch to subscription $($Subscription.Name): $($_.Exception.Message)"
continue
}
try {
$VNets = @(Get-AzVirtualNetwork -ErrorAction Stop)
}
catch {
Write-Warning "Unable to retrieve VNets in $($Subscription.Name): $($_.Exception.Message)"
continue
}
if ($VNets.Count -eq 0) {
Write-Host " No VNets found." -ForegroundColor DarkGray
continue
}
foreach ($VNet in $VNets) {
$VNetAddressSpace = ""
if ($VNet.AddressSpace.AddressPrefixes) {
$VNetAddressSpace = (
$VNet.AddressSpace.AddressPrefixes |
Sort-Object
) -join "; "
}
if (-not $VNet.Subnets -or $VNet.Subnets.Count -eq 0) {
Write-Host " VNet $($VNet.Name) has no subnets." -ForegroundColor DarkGray
continue
}
foreach ($Subnet in $VNet.Subnets) {
$SubnetAddressPrefixes = ""
if ($Subnet.AddressPrefixes -and $Subnet.AddressPrefixes.Count -gt 0) {
$SubnetAddressPrefixes = (
$Subnet.AddressPrefixes |
Sort-Object
) -join "; "
}
elseif ($Subnet.AddressPrefix) {
$SubnetAddressPrefixes = $Subnet.AddressPrefix
}
$NetworkSecurityGroupId = ""
$RouteTableId = ""
$NatGatewayId = ""
if ($Subnet.NetworkSecurityGroup) {
$NetworkSecurityGroupId = $Subnet.NetworkSecurityGroup.Id
}
if ($Subnet.RouteTable) {
$RouteTableId = $Subnet.RouteTable.Id
}
if ($Subnet.NatGateway) {
$NatGatewayId = $Subnet.NatGateway.Id
}
$ServiceEndpoints = ""
if ($Subnet.ServiceEndpoints) {
$ServiceEndpoints = (
$Subnet.ServiceEndpoints |
ForEach-Object { $_.Service }
) -join "; "
}
$ServiceEndpointPolicies = ""
if ($Subnet.ServiceEndpointPolicies) {
$ServiceEndpointPolicies = (
$Subnet.ServiceEndpointPolicies |
ForEach-Object { $_.Id }
) -join "; "
}
$Delegations = ""
if ($Subnet.Delegations) {
$Delegations = (
$Subnet.Delegations |
ForEach-Object {
if ($_.ServiceName) {
$_.ServiceName
}
else {
$_.Name
}
}
) -join "; "
}
$IpConfigurationsCount = 0
if ($Subnet.IpConfigurations) {
$IpConfigurationsCount = @($Subnet.IpConfigurations).Count
}
Write-Host " $($VNet.Name)/$($Subnet.Name)" -ForegroundColor Green
$Results.Add([PSCustomObject]@{
SubscriptionName = $Subscription.Name
SubscriptionId = $Subscription.Id
ResourceGroup = $VNet.ResourceGroupName
VNetName = $VNet.Name
VNetLocation = $VNet.Location
VNetAddressSpace = $VNetAddressSpace
VNetId = $VNet.Id
SubnetName = $Subnet.Name
SubnetAddressPrefixes = $SubnetAddressPrefixes
SubnetId = $Subnet.Id
SubnetProvisioningState = $Subnet.ProvisioningState
NetworkSecurityGroupName = Get-ResourceNameFromId -ResourceId $NetworkSecurityGroupId
NetworkSecurityGroupId = $NetworkSecurityGroupId
RouteTableName = Get-ResourceNameFromId -ResourceId $RouteTableId
RouteTableId = $RouteTableId
NatGatewayName = Get-ResourceNameFromId -ResourceId $NatGatewayId
NatGatewayId = $NatGatewayId
ServiceEndpoints = $ServiceEndpoints
ServiceEndpointPolicies = $ServiceEndpointPolicies
Delegations = $Delegations
PrivateEndpointNetworkPolicies = $Subnet.PrivateEndpointNetworkPoliciesFlag
PrivateLinkServiceNetworkPolicies = $Subnet.PrivateLinkServiceNetworkPoliciesFlag
DefaultOutboundAccess = $Subnet.DefaultOutboundAccess
IpConfigurationsCount = $IpConfigurationsCount
})
}
}
}
$SortedResults = $Results |
Sort-Object SubscriptionName, ResourceGroup, VNetName, SubnetName
$SortedResults |
Export-Csv `
-Path $OutputFile `
-NoTypeInformation `
-Encoding UTF8
Write-Host ""
Write-Host "===================== RESULTS =====================" -ForegroundColor Cyan
if ($Results.Count -gt 0) {
$SortedResults |
Format-Table `
SubscriptionName,
ResourceGroup,
VNetName,
SubnetName,
SubnetAddressPrefixes,
NetworkSecurityGroupName,
RouteTableName,
NatGatewayName `
-AutoSize
Write-Host ""
Write-Host "Exported $($Results.Count) subnets." -ForegroundColor Green
Write-Host "CSV exported to: $OutputFile" -ForegroundColor Green
}
else {
Write-Host "No subnets were found in enabled subscriptions." -ForegroundColor Yellow
}Notes
SubnetAddressPrefixessupports both single-prefix and multi-prefix subnets.- Service endpoint policies are exported as resource IDs so you can distinguish policies with the same display name in different scopes.
IpConfigurationsCountis useful as a quick signal for whether NICs or private endpoints are currently attached to the subnet.- If one subscription cannot be queried, the script warns and continues with the remaining subscriptions.