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 CurrentUser

Connect to Azure before running the script:

Connect-AzAccount

The 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.csv

Each row includes:

  • SubscriptionName
  • SubscriptionId
  • ResourceGroup
  • VNetName
  • VNetLocation
  • VNetAddressSpace
  • VNetId
  • SubnetName
  • SubnetAddressPrefixes
  • SubnetId
  • SubnetProvisioningState
  • NetworkSecurityGroupName
  • NetworkSecurityGroupId
  • RouteTableName
  • RouteTableId
  • NatGatewayName
  • NatGatewayId
  • ServiceEndpoints
  • ServiceEndpointPolicies
  • Delegations
  • PrivateEndpointNetworkPolicies
  • PrivateLinkServiceNetworkPolicies
  • DefaultOutboundAccess
  • IpConfigurationsCount

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

  • SubnetAddressPrefixes supports 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.
  • IpConfigurationsCount is 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.