Core/ResourceGraph.ps1
|
function Invoke-AerArgQuery { [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Query, [Parameter(Mandatory)] [string[]] $SubscriptionIds, [int] $PageSize = 1000 ) $allResults = [System.Collections.Generic.List[object]]::new() $skip = 0 do { $params = @{ Query = $Query Subscription = $SubscriptionIds First = $PageSize ErrorAction = 'Stop' } if ($skip -gt 0) { $params['Skip'] = $skip } $page = @(Search-AzGraph @params) $allResults.AddRange($page) $skip += $page.Count } while ($page.Count -eq $PageSize) return @($allResults) } # Search-AzGraph intermittently returns a single *columnar* object (each # projected column as a parallel array) instead of one object per row. For # scalar-only projections, any array-valued property is the columnar tell → # transpose back into per-row objects. NOTE: only safe for scalar projections; # do NOT use on queries that legitimately return array-valued columns (e.g. a # single VNet row with an addressPrefixes/subnets array) — it would explode them. function Expand-AerRows { param($Result) $rows = @($Result) if ($rows.Count -ne 1 -or -not $rows[0] -or -not $rows[0].PSObject) { return $rows } $c = $rows[0] $arrProps = @($c.PSObject.Properties | Where-Object { $_.Value -is [System.Array] }) if ($arrProps.Count -eq 0) { return $rows } $n = @($arrProps[0].Value).Count $names = $c.PSObject.Properties.Name $expanded = for ($i = 0; $i -lt $n; $i++) { $o = [ordered]@{} foreach ($nm in $names) { $v = $c.$nm; $o[$nm] = if ($v -is [System.Array]) { $v[$i] } else { $v } } [pscustomobject]$o } return @($expanded) } # ARM batch REST runner — chunks requests (≤20 per call) and returns a # name → response map. Each request is [ordered]@{ httpMethod; name; url }. function Invoke-AerArmBatch { param([System.Collections.Generic.List[object]] $Requests) $out = @{} for ($i = 0; $i -lt $Requests.Count; $i += 20) { $end = [math]::Min($i + 19, $Requests.Count - 1) $chunk = $Requests[$i..$end] $payload = @{ requests = @($chunk) } | ConvertTo-Json -Depth 5 try { $resp = Invoke-AzRestMethod -Method POST -Uri "https://management.azure.com/batch?api-version=2020-06-01" -Payload $payload foreach ($rr in @(($resp.Content | ConvertFrom-Json).responses)) { $out[[string]$rr.name] = $rr } } catch { Write-Warning "[Aer.armBatch] $($_.Exception.Message)" } } return $out } # Format a subnet resource id as "vnet / subnet" (case-insensitive). Returns '' # when no subnet id is present — used to surface VNet integration on resources. function Get-AerSubnetLabel { param([string] $SubnetId) if (-not $SubnetId) { return '' } $vnet = if ($SubnetId -match '/virtualNetworks/([^/]+)') { $matches[1] } else { '' } $sub = if ($SubnetId -match '/subnets/([^/]+)') { $matches[1] } else { '' } if ($vnet -and $sub) { "$vnet / $sub" } elseif ($vnet) { $vnet } else { '' } } # Aggregate ARG rows (each with .type lowercased + optional .location) into the # standard category-overview shape used by the section Overview pages. function Get-AerTypeAggregate { [CmdletBinding()] param( $Rows, [hashtable] $TypeMap, [string[]] $CategoryOrder ) $byType = @{}; $labelCat = @{}; $byCat = @{}; $byLoc = @{}; $total = 0 foreach ($r in @($Rows)) { $meta = $TypeMap[$r.type] if (-not $meta) { continue } $total++ $label = $meta.Label; $cat = $meta.Category $byType[$label] = ([int]($byType[$label] ?? 0)) + 1 $labelCat[$label] = $cat $byCat[$cat] = ([int]($byCat[$cat] ?? 0)) + 1 $loc = if ($r.location) { $r.location } else { '—' } $byLoc[$loc] = ([int]($byLoc[$loc] ?? 0)) + 1 } $cats = if ($CategoryOrder) { $CategoryOrder } else { @($byCat.Keys | Sort-Object) } $categories = foreach ($c in $cats) { [pscustomobject]@{ Category = $c; Count = [int]($byCat[$c] ?? 0) } } $byTypeList = $byType.GetEnumerator() | Sort-Object Value -Descending | ForEach-Object { [pscustomobject]@{ Label = $_.Key; Category = $labelCat[$_.Key]; Count = [int]$_.Value } } $byLocation = $byLoc.GetEnumerator() | Sort-Object Value -Descending | Select-Object -First 10 | ForEach-Object { [pscustomobject]@{ Region = $_.Key; Count = [int]$_.Value } } [pscustomobject]@{ Total = $total DistinctTypes = @($byTypeList).Count Categories = @($categories) ByType = @($byTypeList) ByLocation = @($byLocation) } } |