Collectors/Network.ps1
|
function Get-AerNetwork { [CmdletBinding()] param( [Parameter(Mandatory)] [string[]] $SubscriptionIds, [Parameter(Mandatory)] $SubscriptionMap ) function SumQ($q) { try { $r = Invoke-AerArgQuery -SubscriptionIds $SubscriptionIds -Query $q; [int](($r | Select-Object -First 1).n ?? 0) } catch { Write-Warning "[Network.sum] $($_.Exception.Message)"; 0 } } function Get-RestListCount($path) { $n = 0 try { while (-not [string]::IsNullOrWhiteSpace($path)) { $resp = Invoke-AzRestMethod -Method GET -Path $path -ErrorAction Stop if ($resp.StatusCode -ne 200) { break } $body = $resp.Content | ConvertFrom-Json $n += @($body.value).Count $path = if ($body.nextLink) { ([uri]$body.nextLink).PathAndQuery } else { $null } } } catch { Write-Warning "[Network.rest] $($_.Exception.Message)" } $n } # ── Counts by type ─────────────────────────────────────────────────────── $cnt = @{} try { $rows = Invoke-AerArgQuery -SubscriptionIds $SubscriptionIds -Query @' resources | where type in~ ( 'microsoft.network/virtualnetworks','microsoft.network/virtualnetworkgateways', 'microsoft.network/expressroutecircuits','microsoft.network/privateendpoints', 'microsoft.network/applicationgateways','microsoft.network/frontdoors','microsoft.cdn/profiles', 'microsoft.network/loadbalancers','microsoft.network/azurefirewalls', 'microsoft.network/networksecuritygroups','microsoft.network/publicipaddresses', 'microsoft.network/routetables','microsoft.network/ddosprotectionplans', 'microsoft.network/trafficmanagerprofiles','microsoft.apimanagement/service', 'microsoft.network/dnszones','microsoft.network/privatednszones') | summarize c = count() by type = tolower(type) '@ foreach ($r in $rows) { $cnt[$r.type] = [int]$r.c } } catch { Write-Warning "[Network.counts] $($_.Exception.Message)" } function C($t) { [int]($cnt[$t] ?? 0) } # ── VNet totals: subnets + peerings ────────────────────────────────────── $subnetTotal = 0; $peerTotal = 0 try { $t = Invoke-AerArgQuery -SubscriptionIds $SubscriptionIds -Query @' resources | where type =~ 'microsoft.network/virtualnetworks' | summarize Subnets = sum(array_length(properties.subnets)), Peerings = sum(array_length(properties.virtualNetworkPeerings)) '@ $row = $t | Select-Object -First 1 if ($row) { $subnetTotal = [int]($row.Subnets ?? 0); $peerTotal = [int]($row.Peerings ?? 0) } } catch { Write-Warning "[Network.vnetTotals] $($_.Exception.Message)" } # ── IP utilization: capacity vs used, computed in KQL (single safe row) ── # IPv4 only; capacity = 2^(32-mask) per subnet, used = ipConfigurations count. $cap = 0.0; $used = 0; $resvSubnets = 0 try { $u = Invoke-AerArgQuery -SubscriptionIds $SubscriptionIds -Query @' resources | where type =~ 'microsoft.network/virtualnetworks' | mv-expand subnet = properties.subnets | extend prefix = tostring(subnet.properties.addressPrefix) | where isnotempty(prefix) and prefix !contains ':' | extend mask = toint(split(prefix, '/')[1]) | where isnotempty(mask) | extend cap = tolong(pow(2, 32 - mask)) | extend ipc = toint(array_length(subnet.properties.ipConfigurations)) | summarize Capacity = sum(cap), Used = sum(ipc), Subnets = count() '@ $row = $u | Select-Object -First 1 if ($row) { $cap = [double]($row.Capacity ?? 0); $used = [int]($row.Used ?? 0); $resvSubnets = [int]($row.Subnets ?? 0) } } catch { Write-Warning "[Network.ipUsage] $($_.Exception.Message)" } $reserved = 5 * $resvSubnets # Azure reserves 5 addresses per subnet $occupied = $used + $reserved $free = [math]::Max(0, $cap - $occupied) $pct = if ($cap -gt 0) { [math]::Round($occupied / $cap * 100, 1) } else { 0 } $frontDoor = (C 'microsoft.network/frontdoors') + (C 'microsoft.cdn/profiles') # Applications configured behind each balancer type (backends / endpoints / APIs) $lbApps = SumQ "resources | where type =~ 'microsoft.network/loadbalancers' | summarize n = sum(array_length(properties.backendAddressPools))" $agwApps = SumQ "resources | where type =~ 'microsoft.network/applicationgateways' | summarize n = sum(array_length(properties.backendAddressPools))" $tmApps = SumQ "resources | where type =~ 'microsoft.network/trafficmanagerprofiles' | summarize n = sum(array_length(properties.endpoints))" # Front Door: classic backend pools (ARG) + Std/Premium origin groups (REST per profile, sub-resource not in ARG) $afdApps = SumQ "resources | where type =~ 'microsoft.network/frontdoors' | summarize n = sum(array_length(properties.backendPools))" foreach ($p in (Invoke-AerArgQuery -SubscriptionIds $SubscriptionIds -Query "resources | where type =~ 'microsoft.cdn/profiles' and sku.name in~ ('Standard_AzureFrontDoor','Premium_AzureFrontDoor') | project id, subscriptionId, resourceGroup, name")) { $afdApps += Get-RestListCount "/subscriptions/$($p.subscriptionId)/resourceGroups/$($p.resourceGroup)/providers/Microsoft.Cdn/profiles/$($p.name)/originGroups?api-version=2023-05-01" } # API Management: published APIs (REST per service, sub-resource not in ARG) $apimApps = 0 foreach ($s in (Invoke-AerArgQuery -SubscriptionIds $SubscriptionIds -Query "resources | where type =~ 'microsoft.apimanagement/service' | project id, subscriptionId, resourceGroup, name")) { $apimApps += Get-RestListCount "/subscriptions/$($s.subscriptionId)/resourceGroups/$($s.resourceGroup)/providers/Microsoft.ApiManagement/service/$($s.name)/apis?api-version=2022-08-01" } [pscustomobject]@{ Counts = [pscustomobject]@{ Vnet = C 'microsoft.network/virtualnetworks' Subnets = $subnetTotal Peerings = $peerTotal Gateways = C 'microsoft.network/virtualnetworkgateways' ExpressRoute = C 'microsoft.network/expressroutecircuits' PrivateEndpoints = C 'microsoft.network/privateendpoints' AppGateway = C 'microsoft.network/applicationgateways' FrontDoor = $frontDoor LoadBalancer = C 'microsoft.network/loadbalancers' AzureFirewall = C 'microsoft.network/azurefirewalls' Nsg = C 'microsoft.network/networksecuritygroups' PublicIp = C 'microsoft.network/publicipaddresses' RouteTables = C 'microsoft.network/routetables' DdosPlans = C 'microsoft.network/ddosprotectionplans' TrafficManager = C 'microsoft.network/trafficmanagerprofiles' } IpUsage = [pscustomobject]@{ Capacity = [long]$cap Used = [int]$used Reserved = [int]$reserved Occupied = [long]$occupied Free = [long]$free PercentUsed = $pct SubnetCount = $resvSubnets } Dns = [pscustomobject]@{ Public = C 'microsoft.network/dnszones' Private = C 'microsoft.network/privatednszones' } Balancers = @( [pscustomobject]@{ Type = 'Load Balancer (ALB)'; Count = $lbApps } [pscustomobject]@{ Type = 'App Gateway (AGW)'; Count = $agwApps } [pscustomobject]@{ Type = 'Front Door (AFD)'; Count = $afdApps } [pscustomobject]@{ Type = 'Traffic Manager (ATM)'; Count = $tmApps } [pscustomobject]@{ Type = 'API Management (APIM)'; Count = $apimApps } ) } } |