Private/CloudGraphHelpers.ps1
|
#requires -Version 5.1 function Get-CloudDataProperty { [CmdletBinding()] param( [AllowNull()] [object]$InputObject, [Parameter(Mandatory)] [string]$Name ) $exists = $false $value = $null if ($null -ne $InputObject) { if ($InputObject -is [System.Collections.IDictionary]) { foreach ($key in $InputObject.Keys) { if ([string]::Equals([string]$key, $Name, [System.StringComparison]::OrdinalIgnoreCase)) { $exists = $true $value = $InputObject[$key] break } } } else { $property = $InputObject.PSObject.Properties[$Name] if ($null -ne $property) { $exists = $true $value = $property.Value } } } return [PSCustomObject]@{ Exists = $exists Value = $value } } function Invoke-CloudPolicyInsightsQuery { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$SubscriptionId ) $azRestCommand = Get-Command -Name 'Invoke-AzRestMethod' -ErrorAction SilentlyContinue $graphRequestCommand = Get-Command -Name 'Invoke-MgGraphRequest' -ErrorAction SilentlyContinue if ($null -ne $azRestCommand) { $transport = 'Invoke-AzRestMethod' } elseif ($null -ne $graphRequestCommand) { $transport = 'Invoke-MgGraphRequest' } else { throw "No Azure Policy query transport is available. Install Az.Accounts and run Connect-AzAccount. Required Azure Resource Manager scope: https://management.azure.com/user_impersonation; required authorization: Reader or Microsoft.PolicyInsights/policyStates/read on the subscription." } $escapedSubscriptionId = [System.Uri]::EscapeDataString($SubscriptionId) $requestPath = "/subscriptions/$escapedSubscriptionId/providers/Microsoft.PolicyInsights/policyStates/latest/queryResults?api-version=2019-10-01&`$top=1000" $requestUri = "https://management.azure.com$requestPath" $states = @() $seenRequests = @{} while ($true) { if ($seenRequests.ContainsKey($requestUri)) { throw 'Azure Policy Insights returned a repeated pagination link.' } $seenRequests[$requestUri] = $true if ($transport -eq 'Invoke-AzRestMethod') { $azResponse = Invoke-AzRestMethod -Method POST -Path $requestPath -ErrorAction Stop $contentProperty = Get-CloudDataProperty -InputObject $azResponse -Name 'Content' if ($contentProperty.Exists -and $contentProperty.Value -is [string]) { if ([string]::IsNullOrWhiteSpace($contentProperty.Value)) { throw 'Azure Policy Insights returned an empty response body.' } $page = $contentProperty.Value | ConvertFrom-Json -ErrorAction Stop } else { $page = $azResponse } } else { $page = Invoke-MgGraphRequest -Method POST -Uri $requestUri -ErrorAction Stop } if ($page -is [string]) { if ([string]::IsNullOrWhiteSpace($page)) { throw 'Azure Policy Insights returned an empty response body.' } $page = $page | ConvertFrom-Json -ErrorAction Stop } $valueProperty = Get-CloudDataProperty -InputObject $page -Name 'value' if (-not $valueProperty.Exists -or $null -eq $valueProperty.Value) { throw "Azure Policy Insights response did not contain a 'value' array." } $states += @($valueProperty.Value) $nextProperty = Get-CloudDataProperty -InputObject $page -Name '@odata.nextLink' if (-not $nextProperty.Exists) { $nextProperty = Get-CloudDataProperty -InputObject $page -Name 'nextLink' } $nextLink = [string]$nextProperty.Value if ([string]::IsNullOrWhiteSpace($nextLink)) { break } $absoluteUri = $null if ([System.Uri]::TryCreate($nextLink, [System.UriKind]::Absolute, [ref]$absoluteUri)) { $requestPath = $absoluteUri.PathAndQuery $requestUri = $absoluteUri.AbsoluteUri } elseif ($nextLink.StartsWith('/')) { $requestPath = $nextLink $requestUri = "https://management.azure.com$nextLink" } else { throw "Azure Policy Insights returned an invalid pagination link: $nextLink" } } return [PSCustomObject]@{ States = $states Transport = $transport } } |