public/core/Invoke-MtAzureResourceGraphRequest.ps1
|
<# .SYNOPSIS Invoke a query request to the Azure Resource Graph. .DESCRIPTION This function allows you to query resources across Azure subscriptions using Azure Resource Graph. It provides a simplified interface for resource discovery and exploration. .EXAMPLE Invoke-MtAzureResourceGraphRequest -Query "Resources | where type =~ 'Microsoft.Compute/virtualMachines'" Lists all Azure virtual machines .EXAMPLE Invoke-MtAzureResourceGraphRequest -Query "ResourceContainers | where type=='microsoft.resources/subscriptions'" Lists all Azure subscriptions .LINK https://maester.dev/docs/commands/Invoke-MtAzureResourceGraphRequest #> function Invoke-MtAzureResourceGraphRequest { [CmdletBinding()] param( # The Resource Graph query to execute using KQL (Kusto Query Language) [Parameter(Mandatory = $true)] [string] $Query, # The API version to use for the Azure Resource Graph REST API [Parameter(Mandatory = $false)] [string] $ApiVersion = '2021-03-01' ) # Get the Azure Resource Manager URL from the current Azure context to ensure connecting to the correct Azure environment (Public, Government, etc.) $resourceUrl = (Get-AzContext).Environment.ResourceManagerUrl # Build the complete URL for the Azure Resource Graph API endpoint $resourceGraphUrl = "$($resourceUrl)providers/Microsoft.ResourceGraph/resources?api-version=$($ApiVersion)" Write-Verbose "Resource Graph URL: $resourceGraphUrl" Write-Verbose "Retrieving all results with pagination" $allResults = New-Object 'System.Collections.Generic.List[psobject]' # Initialize pagination variables $currentSkip = 0 # How many records to skip (for pagination) $pageSize = 1000 # Maximum page size for Azure Resource Graph $skipToken = $null # Token for proper pagination (Azure-specific) # Start pagination loop - continues until all data is retrieved do { $requestOptions = @{ '$skip' = $currentSkip # Skip this many records (for subsequent pages) '$top' = $pageSize # Return this many records per page } # Add skipToken if available (Azure's preferred pagination method) if ($skipToken) { $requestOptions['$skipToken'] = $skipToken } $body = @{ query = $Query options = $requestOptions } | ConvertTo-Json -Depth 5 Write-Verbose "Querying Azure Resource Graph (skip: $currentSkip, top: $pageSize)" $result = Invoke-AzRestMethod -Method POST -Uri $resourceGraphUrl -Payload $body # Check if the request was successful (HTTP status codes 200-299) if ($result.StatusCode -ge 200 -and $result.StatusCode -lt 300) { $response = $result.Content | ConvertFrom-Json # Check if the response contains data and handle different response formats from Azure Resource Graph if ($response.data) { if ($response.data -is [array]) { # Multiple results: cast to PSObject array and add all items efficiently $allResults.AddRange([PSObject[]]$response.data) } else { # Single result: add the single object to our list $allResults.Add($response.data) } } else { Write-Verbose "No data found in response" } # Prepare for next iteration of pagination $currentSkip += $pageSize # Check if there are more results to fetch $skipToken = $response.'$skipToken' $hasMoreResults = $null -ne $skipToken } else { Write-Error "Error querying Azure Resource Graph. Status code: $($result.StatusCode). Content: $($result.Content)" return $null } } while ($hasMoreResults) # Continue looping while there are more results to fetch Write-Verbose "Total results retrieved: $($allResults.Count)" # Convert the Generic List to a PowerShell array and return it return $allResults.ToArray() } |