Azure Resource Graph : 10 requêtes pour inventorier et surveiller Azure

Inventoriez VM, disques non attachés, IP publiques, tags et serveurs Arc avec dix requêtes en lecture seule, leur interprétation et une collecte paginée.

01

Voir le parc Azure sans modifier les ressources

Combien de VM avons-nous, quels disques attendent une décision, et quels serveurs Arc ne communiquent plus comme prévu? Azure Resource Graph (ARG) permet de poser ces questions sur plusieurs abonnements. Voici dix requêtes en lecture seule, avec leur interprétation et les vérifications à faire avant d’agir.

ARG utilise un sous-ensemble de Kusto Query Language (KQL), mais ce guide ne porte pas sur Advanced Hunting de Defender. Il explore la configuration des ressources Azure, pas la télémétrie de sécurité des postes. Ce n’est pas non plus Microsoft Graph, utilisé pour les identités et les licences Microsoft 365.

02

Prérequis : périmètre explicite et lecture seulement

Vous pouvez commencer dans Azure Portal > Resource Graph Explorer : choisissez les abonnements, collez une requête et exécutez-la. Pour les scripts ci-dessous, utilisez PowerShell et les modules Az.Accounts et Az.ResourceGraph installés selon votre procédure approuvée. Consignez les versions utilisées; ne mettez pas à jour les modules pendant une collecte.

L’identité doit avoir la lecture Azure RBAC sur les ressources visées; Reader à la portée requise convient à ce diagnostic. Contributor ou Owner n’est pas nécessaire. Les résultats restent limités par les droits : une collecte réussie peut être partielle sans le signaler. Faites confirmer la liste des abonnements par leur propriétaire.

ARG est un service gratuit soumis à des quotas. Les ressources Azure et les services ajoutés pour planifier, stocker ou alerter peuvent être facturés séparément. Aucun achat de licence Defender ou Microsoft Graph n’est requis pour ces requêtes d’inventaire.

Connexion et exécution d’une requête
# Setup only: install approved Az.Accounts / Az.ResourceGraph versions beforehand
Import-Module Az.Accounts
Import-Module Az.ResourceGraph
Get-Module Az.Accounts,Az.ResourceGraph | Select-Object Name,Version
$tenantId = '11111111-1111-1111-1111-111111111111' # fictional
$subscriptionIds = @('22222222-2222-2222-2222-222222222222') # fictional
Connect-AzAccount -Tenant $tenantId -ErrorAction Stop
Get-AzContext | Select-Object Account,Tenant,Subscription
Get-AzSubscription -TenantId $tenantId -ErrorAction Stop |
  Select-Object Id,Name,State
# Paste ONE numbered query into this literal here-string:
$query = @'
Resources
| project id, name, type, subscriptionId
| order by id asc
'@
$page = Search-AzGraph -Query $query -Subscription $subscriptionIds -First 1000 -ErrorAction Stop
$page.Data
03

Lire les résultats sans leur faire dire plus

Resources contient des propriétés indexées, pas un état transactionnel instantané. Après un changement, confirmez la valeur courante avec le fournisseur de ressource. La casse des chemins de propriétés compte; un champ manquant peut aussi venir de la version d’API indexée. Inspectez le schéma et une ressource connue avant de généraliser un filtre.

Les dix requêtes partagent la même exigence de lecture RBAC, sans accès aux données des VM, aux clés de stockage ni aux secrets. Remplacez seulement les exemples fictifs et les conventions de tags. Ne placez jamais de secret dans un tag ou un export.

04

1. Compter les ressources par abonnement et type

Comparez cette répartition au périmètre attendu. Une ligne agrégée ne représente pas une ressource et ce comptage n’inclut pas toutes les données des services (fichiers, messages ou objets applicatifs).

Requête ARG — lecture seule
Resources
| summarize resourceCount=count() by subscriptionId, type
| order by subscriptionId asc, type asc
05

2. Inventorier les machines virtuelles Azure

Utilisez id comme clé de rapprochement avec la CMDB, pas seulement le nom. ProvisioningState décrit le provisionnement; Succeeded ne prouve pas que Windows, Linux ou l’application répond. Cette sélection exclut les instances de VM Scale Sets.

Requête ARG — lecture seule
Resources
| where type =~ 'microsoft.compute/virtualmachines'
| project id, name, subscriptionId, resourceGroup, location,
    vmSize=tostring(properties.hardwareProfile.vmSize),
    osType=tostring(properties.storageProfile.osDisk.osType),
    provisioningState=tostring(properties.provisioningState)
| order by id asc
06

3. Trouver les disques managés non attachés

Non attaché n’est pas inutile : disque de récupération, migration ou réserve. Confirmez l’état courant avec Compute, le propriétaire, la sauvegarde et les dépendances avant toute décision. Ne calculez pas une économie exacte à partir des Go seuls.

Requête ARG — lecture seule
Resources
| where type =~ 'microsoft.compute/disks'
| where tostring(properties.diskState) =~ 'Unattached'
| project id, name, subscriptionId, resourceGroup, location,
    diskGB=toint(properties.diskSizeGB), sku=tostring(sku.name),
    managedBy, timeCreated=todatetime(properties.timeCreated)
| order by id asc
07

4. Examiner les adresses IP publiques

Conservez aussi les IP sans adresse attribuée. Une IP publique ne prouve pas qu’un port est accessible : vérifiez associations, pare-feu, NSG, routes et configuration du service. Des champs d’association vides ne suffisent pas à conclure qu’elle est orpheline.

Requête ARG — lecture seule
Resources
| where type =~ 'microsoft.network/publicipaddresses'
| project id, name, subscriptionId, resourceGroup, location,
    ip=tostring(properties.ipAddress), sku=tostring(sku.name),
    allocation=tostring(properties.publicIPAllocationMethod),
    ipConfigurationId=tostring(properties.ipConfiguration.id),
    natGatewayId=tostring(properties.natGateway.id)
| order by id asc
08

5. Repérer les tags de gouvernance manquants

Owner et Environment sont les clés fictives de notre convention. Adaptez leur casse et les valeurs autorisées. Certains types ne prennent pas en charge les tags; contrôlez l’applicabilité avant de déclarer une non-conformité. Les tags du groupe ne sont pas automatiquement copiés sur ses ressources.

Requête ARG — lecture seule
Resources
| extend owner=tostring(tags['Owner']),
    environment=tostring(tags['Environment'])
| where isempty(owner) or isempty(environment)
| project id, name, type, subscriptionId, resourceGroup, owner, environment
| order by id asc
09

6. Ajouter le nom des abonnements

La jointure gauche conserve les ressources même sans nom d’abonnement trouvé. Gardez subscriptionId comme identifiant stable; un libellé peut changer. Une jointure mal normalisée ou plusieurs lignes par clé peut multiplier les résultats.

Requête ARG — lecture seule
Resources
| join kind=leftouter (
    ResourceContainers
    | where type =~ 'microsoft.resources/subscriptions'
    | project subscriptionId, subscriptionName=name
  ) on subscriptionId
| project id, name, type, subscriptionId, subscriptionName, resourceGroup, location
| order by id asc
10

7. Inventorier les serveurs Azure Arc

Ces lignes représentent les machines inscrites à Arc, pas tous les serveurs locaux. Un champ absent peut refléter le schéma ou l’indexation. Comparez les versions d’agent à la documentation Arc; ne comparez pas des numéros de version comme des chaînes alphabétiques.

Requête ARG — lecture seule
Resources
| where type =~ 'microsoft.hybridcompute/machines'
| project id, name, subscriptionId, resourceGroup, location,
    status=tostring(properties.status),
    agentVersion=tostring(properties.agentVersion),
    osName=tostring(properties.osName),
    osVersion=tostring(properties.osVersion)
| order by id asc
11

8. Prioriser les statuts Arc à vérifier

Un statut autre que Connected déclenche une vérification : maintenance prévue, machine retirée, réseau, proxy ou agent. Cela ne démontre pas à lui seul une panne du système. Validez avec le propriétaire et les diagnostics de connectivité Arc sans supprimer l’inscription.

Requête ARG — lecture seule
Resources
| where type =~ 'microsoft.hybridcompute/machines'
| extend arcStatus=tostring(properties.status)
| where isempty(arcStatus) or arcStatus !~ 'Connected'
| project id, name, subscriptionId, resourceGroup, arcStatus
| order by id asc
12

9. Lister les comptes de stockage et leurs contrôles déclarés

Ces propriétés orientent une revue, sans constituer un verdict d’exposition. Distinguez accès réseau public, accès anonyme aux blobs, authentification et endpoints privés. Une valeur vide doit être résolue auprès du fournisseur de ressource, pas interprétée comme un contrôle activé ou désactivé.

Requête ARG — lecture seule
Resources
| where type =~ 'microsoft.storage/storageaccounts'
| project id, name, subscriptionId, resourceGroup, location,
    publicNetworkAccess=tostring(properties.publicNetworkAccess),
    allowBlobPublicAccess=tostring(properties.allowBlobPublicAccess),
    supportsHttpsTrafficOnly=tostring(properties.supportsHttpsTrafficOnly),
    minimumTlsVersion=tostring(properties.minimumTlsVersion)
| order by id asc
13

10. Repérer les déploiements à examiner

Ce filtre est volontairement ciblé; tous les types n’exposent pas ce champ ni les mêmes états. Consultez ensuite Activity Log et l’opération du fournisseur concerné. L’absence de résultat n’atteste ni disponibilité, ni conformité, ni santé applicative.

Requête ARG — lecture seule
Resources
| extend provisioningState=tostring(properties.provisioningState)
| where provisioningState in~ ('Failed', 'Canceled')
| project id, name, type, subscriptionId, resourceGroup, provisioningState
| order by id asc
14

Pagination : 1 000 lignes ne font pas un inventaire complet

Une réponse retourne au maximum 1 000 lignes. Pour les listes, conservez id et un tri stable, sans take, limit ou sample, puis suivez SkipToken. Une agrégation comme la requête 1 produit des groupes, pas des lignes de ressources; ne lui appliquez pas aveuglément une routine d’export de ressources.

L’exemple exporte des colonnes communes seulement; ajoutez les champs spécifiques de la requête à Select-Object. Une absence de token n’est pas une preuve universelle d’exhaustivité : certaines formes de requête empêchent la pagination. Contrôlez aussi les compteurs et les indicateurs de troncature disponibles dans votre client.

Collecte paginée — lecture cloud, écriture CSV locale
# Use a row-level query from 2–10, retaining id and order by id.
# Same query and subscription list on every page; no take/limit/sample.
$rows = [System.Collections.Generic.List[object]]::new()
$token = $null
do {
  $parameters = @{
    Query=$query; Subscription=$subscriptionIds; First=1000
    ErrorAction='Stop'
  }
  if ($token) { $parameters.SkipToken = $token }
  $page = Search-AzGraph @parameters
  foreach ($row in $page.Data) { $rows.Add($row) }
  $token = $page.SkipToken
} while ($token)
# Local output only; choose an approved restricted directory.
$rows | Select-Object id,name,type,subscriptionId,resourceGroup,location |
  Export-Csv -LiteralPath './azure-inventory.csv' -NoTypeInformation -Encoding utf8
15

Un exemple de suivi utile, sans correction automatique

Consignez l’ID complet, la requête, le périmètre, l’heure de collecte, l’observation et le responsable. Une priorité dépend du risque métier, pas du nombre de lignes. Ne transformez jamais directement un export en boucle Remove-AzResource.

Observation fictiveValidationAction proposée
disk-recovery-01 non attachéPropriétaire, plan de reprise, état Compute courantConserver jusqu’à validation du besoin et des sauvegardes
srv-arc-demo non ConnectedMaintenance, agent, proxy, connectivitéOuvrir un diagnostic ciblé, pas supprimer Arc
Owner manquant sur vm-demo-01Type compatible, équipe responsablePréparer un tag pilote approuvé
16

Passer à la surveillance, puis aux changements contrôlés

  • Pilotez sur un abonnement connu : comparez quelques IDs au portail et au fournisseur, puis validez les totaux avant d’étendre le périmètre.
  • Pour une collecte récurrente, utilisez une identité managée lorsque disponible, avec lecture limitée. Protégez les exports, définissez leur rétention et surveillez aussi les échecs de collecte.
  • ARG n’est pas un moteur de disponibilité ou de métriques. Complétez avec Azure Monitor, Activity Log et les diagnostics adaptés; une requête sauvegardée seule n’envoie pas d’alerte. Validez statut de disponibilité et coût de toute intégration d’alerte retenue.
  • Avant un changement : nouvelle lecture du fournisseur, propriétaire, dépendances, sauvegarde, ticket, fenêtre et pilote. Enregistrez la configuration précédente; définissez le test et le retour arrière avant l’écriture.
  • Pour un tag pilote, restaurez uniquement la clé modifiée en préservant les changements concurrents. Pour une suppression de disque, il n’existe pas de simple annulation : une restauration testée est indispensable. Ce guide ne fournit aucune suppression.
  • Sur erreur 403, examinez identité et périmètre sans élargir automatiquement les droits. Sur limitation de débit, respectez les délais et quotas signalés; espacez les requêtes. Sur champ vide, vérifiez schéma et casse avant de conclure.
17

Transformer l’inventaire en gouvernance

Ces requêtes donnent une base de travail pour la CMDB, les responsabilités et les revues de coûts ou de configuration. Elles ne remplacent pas un audit complet ni une supervision de bout en bout. Un accompagnement infrastructure Azure peut aider à définir le périmètre, fiabiliser les collectes et convertir les constats en changements mesurés.