[CmdletBinding()]
param()
if (-not (Get-AzContext)) {
throw "Not connected to Azure. Run 'Connect-AzAccount' first."
}
$subscriptionIds = (Get-AzSubscription | Where-Object State -eq 'Enabled').Id
if (-not $subscriptionIds) {
Write-Warning "No enabled subscriptions found."
return
}
Write-Verbose "Querying $($subscriptionIds.Count) subscription(s) via Resource Graph..."
function Invoke-Arg {
param(
[Parameter(Mandatory)] [string] $Query,
[Parameter(Mandatory)] [string] $Category
)
$results = Search-AzGraph -Query $Query -Subscription $subscriptionIds -First 1000
foreach ($row in $results) {
$row | Add-Member -NotePropertyName ResourceCategory -NotePropertyValue $Category -PassThru
}
}
$publicIps = @'
Resources
| where type == "microsoft.network/publicipaddresses"
| extend AttachedTo = tostring(properties.ipConfiguration.id)
| project
Name = name,
ResourceGroup = resourceGroup,
SubscriptionId = subscriptionId,
Location = location,
Detail = strcat(
"IP=", tostring(properties.ipAddress),
" | Sku=", tostring(sku.name),
" | AttachedTo=", iif(isempty(AttachedTo), "UNATTACHED", AttachedTo))
'@
$storage = @'
Resources
| where type == "microsoft.storage/storageaccounts"
| where properties.publicNetworkAccess != "Disabled"
| project
Name = name,
ResourceGroup = resourceGroup,
SubscriptionId = subscriptionId,
Location = location,
Detail = strcat(
"PublicAccess=", tostring(properties.publicNetworkAccess),
" | AllowBlobPublic=", tostring(properties.allowBlobPublicAccess),
" | MinTls=", tostring(properties.minimumTlsVersion))
'@
$appServices = @'
Resources
| where type == "microsoft.web/sites"
| where properties.publicNetworkAccess != "Disabled"
| project
Name = name,
ResourceGroup = resourceGroup,
SubscriptionId = subscriptionId,
Location = location,
Detail = strcat(
"Kind=", kind,
" | DefaultHost=", tostring(properties.defaultHostName),
" | HttpsOnly=", tostring(properties.httpsOnly))
'@
$sqlServers = @'
Resources
| where type == "microsoft.sql/servers"
| where properties.publicNetworkAccess == "Enabled"
| project
Name = name,
ResourceGroup = resourceGroup,
SubscriptionId = subscriptionId,
Location = location,
Detail = strcat("FQDN=", tostring(properties.fullyQualifiedDomainName))
'@
$keyVaults = @'
Resources
| where type == "microsoft.keyvault/vaults"
| where properties.publicNetworkAccess != "Disabled"
| project
Name = name,
ResourceGroup = resourceGroup,
SubscriptionId = subscriptionId,
Location = location,
Detail = strcat(
"NetworkAcls=", tostring(properties.networkAcls.defaultAction),
" | RBAC=", tostring(properties.enableRbacAuthorization))
'@
$aks = @'
Resources
| where type == "microsoft.containerservice/managedclusters"
| where isnull(properties.apiServerAccessProfile.enablePrivateCluster)
or properties.apiServerAccessProfile.enablePrivateCluster == false
| project
Name = name,
ResourceGroup = resourceGroup,
SubscriptionId = subscriptionId,
Location = location,
Detail = strcat(
"K8sVersion=", tostring(properties.kubernetesVersion),
" | FQDN=", tostring(properties.fqdn))
'@
$results = [System.Collections.Generic.List[object]]::new()
$queries = @(
@{ Name = 'PublicIP'; Query = $publicIps },
@{ Name = 'Storage'; Query = $storage },
@{ Name = 'AppService'; Query = $appServices },
@{ Name = 'SqlServer'; Query = $sqlServers },
@{ Name = 'KeyVault'; Query = $keyVaults },
@{ Name = 'AKS'; Query = $aks }
)
foreach ($q in $queries) {
Write-Verbose "Querying: $($q.Name)"
try {
$rows = Invoke-Arg -Query $q.Query -Category $q.Name
if ($rows) { $results.AddRange([object[]]$rows) }
}
catch {
Write-Warning "Query for '$($q.Name)' failed: $_"
}
}
$subLookup = @{}
Get-AzSubscription | ForEach-Object { $subLookup[$_.Id] = $_.Name }
$results | ForEach-Object {
$_ | Add-Member -NotePropertyName Subscription `
-NotePropertyValue ($subLookup[$_.SubscriptionId]) `
-PassThru
} |
Sort-Object ResourceCategory, Subscription, ResourceGroup, Name |
Select-Object ResourceCategory, Subscription, ResourceGroup, Name, Location, Detail