Advanced Resource Graph 查询示例

了解使用 Azure 资源图表进行查询的第一步是对查询语言有基本的了解。 如果还不熟悉 Azure 数据资源管理器,建议查看基础知识,以了解如何撰写所需资源的请求。

我们将逐步介绍以下高级查询:

如果没有 Azure 订阅,可在开始前创建一个试用帐户

语言支持

Azure CLI(通过扩展)和 Azure PowerShell(通过模块)支持 Azure 资源图表。 在运行以下任何查询之前,请检查环境是否已准备就绪。 有关安装和验证所选 shell 环境的步骤,请参阅 Azure CLIAzure PowerShell

显示每个资源类型的 API 版本

在更新期间,Resource Graph 主要使用资源提供程序 API 的最新非预览版本来GET资源属性。 在某些情况下,所使用的 API 版本已被替换,以便在结果中返回更新或更常用的属性。 以下查询详述了用于在每个资源类型上收集属性的 API 版本:

Resources
| distinct type, apiVersion
| where isnotnull(apiVersion)
| order by type asc
az graph query -q "Resources | distinct type, apiVersion | where isnotnull(apiVersion) | order by type asc"

获取虚拟机规模集容量和大小

此查询将查找虚拟机规模集资源,并获取各种详细信息,包括规模集的虚拟机大小和容量。 该查询使用 toint() 函数将容量强制转换为数字,以便进行排序。 最后会将列重命名为自定义命名属性。

Resources
| where type=~ 'microsoft.compute/virtualmachinescalesets'
| where name contains 'contoso'
| project subscriptionId, name, location, resourceGroup, Capacity = toint(sku.capacity), Tier = sku.name
| order by Capacity desc
az graph query -q "Resources | where type=~ 'microsoft.compute/virtualmachinescalesets' | where name contains 'contoso' | project subscriptionId, name, location, resourceGroup, Capacity = toint(sku.capacity), Tier = sku.name | order by Capacity desc"

删除结果中的列

以下查询使用 summarize 按订阅对资源进行计数,使用 join 将其与 ResourceContainers 表中的订阅详细信息合并,然后使用 project-away 删除某些列。

Resources
| summarize resourceCount=count() by subscriptionId
| join (ResourceContainers | where type=='microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId
| project-away subscriptionId, subscriptionId1
az graph query -q "Resources | summarize resourceCount=count() by subscriptionId | join (ResourceContainers | where type=='microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId| project-away subscriptionId, subscriptionId1"

列出所有标签名称

此查询以标记开头,并生成一个 JSON 对象,列出所有唯一标记名称及其对应的类型。

Resources
| project tags
| summarize buildschema(tags)
az graph query -q "Resources | project tags | summarize buildschema(tags)"

按正则表达式匹配的虚拟机

此查询查找与某个正则表达式(称为 regex)匹配的虚拟机。 可以使用 matches regex @ 定义要匹配的正则表达式,即 ^Contoso(.*)[0-9]+$。 该 regex 定义说明如下:

  • ^ - 匹配项必须以该字符串的开头开头。
  • Contoso - 区分大小写的字符串。
  • (.*) - 子表达式匹配:
    • . - 匹配任意单个字符(换行符除外)。
    • * - 匹配前一个元素零次或多次。
  • [0-9] - 匹配数字 0 到 9 的字符组。
  • + - 匹配上一个元素一次或多次。
  • $ - 上一个元素的匹配项必须出现在该字符串的末尾。

按名称进行匹配后,查询将对名称进行投影并按名称升序排序。

Resources
| where type =~ 'microsoft.compute/virtualmachines' and name matches regex @'^Contoso(.*)[0-9]+$'
| project name
| order by name asc
az graph query -q "Resources | where type =~ 'microsoft.compute/virtualmachines' and name matches regex @'^Contoso(.*)[0-9]+\$' | project name | order by name asc"

列出具有特定写入位置的 Azure Cosmos DB

以下查询将范围限定为 Azure Cosmos DB 资源,使用 mv-expand 展开 properties.writeLocations 的属性包,然后投影特定字段,并进一步将结果限制为 properties.writeLocations.locationName 值与“China East”或“China North”匹配的项。

Resources
| where type =~ 'microsoft.documentdb/databaseaccounts'
| project id, name, writeLocations = (properties.writeLocations)
| mv-expand writeLocations
| project id, name, writeLocation = tostring(writeLocations.locationName)
| where writeLocation in ('China East', 'China North')
| summarize by id, name
az graph query -q "Resources | where type =~ 'microsoft.documentdb/databaseaccounts' | project id, name, writeLocations = (properties.writeLocations) | mv-expand writeLocations | project id, name, writeLocation = tostring(writeLocations.locationName) | where writeLocation in ('China East', 'China North') | summarize by id, name"

具有订阅名称的密钥保管库

以下查询展示了 join 的复杂用法,其中将 kind 设置为 leftouter。 查询将联接表限制为订阅资源并具有 project,以仅包括原始字段 SubscriptionId 和重命名为 SubNamename 字段。 字段重命名避免了 join 将其添加为 name1,因为该字段已存在于资源中。 原始表使用 where 进行筛选,以下 project 包括两个表中的列。 查询结果是所有密钥保管库,其中显示密钥保管库的类型、名称以及其所在订阅的名称。

Resources
| join kind=leftouter (ResourceContainers | where type=='microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId
| where type == 'microsoft.keyvault/vaults'
| project type, name, SubName
az graph query -q "Resources | join kind=leftouter (ResourceContainers | where type=='microsoft.resources/subscriptions' | project SubName=name, subscriptionId) on subscriptionId | where type == 'microsoft.keyvault/vaults' | project type, name, SubName"

列出 SQL 数据库及其弹性池

以下查询使用 leftouterjoin 将 SQL 数据库资源与其相关的弹性池关联起来(如果存在的话)。

Resources
| where type =~ 'microsoft.sql/servers/databases'
| project databaseId = id, databaseName = name, elasticPoolId = tolower(tostring(properties.elasticPoolId))
| join kind=leftouter (
    Resources
    | where type =~ 'microsoft.sql/servers/elasticpools'
    | project elasticPoolId = tolower(id), elasticPoolName = name, elasticPoolState = properties.state)
on elasticPoolId
| project-away elasticPoolId1
az graph query -q "Resources | where type =~ 'microsoft.sql/servers/databases' | project databaseId = id, databaseName = name, elasticPoolId = tolower(tostring(properties.elasticPoolId)) | join kind=leftouter ( Resources | where type =~ 'microsoft.sql/servers/elasticpools' | project elasticPoolId = tolower(id), elasticPoolName = name, elasticPoolState = properties.state) on elasticPoolId | project-away elasticPoolId1"

列出具有其网络接口和公共 IP 的虚拟机

此查询使用两个 leftouterjoin 命令将使用资源管理器部署模型创建的虚拟机、其相关网络接口以及与这些网络接口相关的任何公共 IP 地址组合在一起。

Resources
| where type =~ 'microsoft.compute/virtualmachines'
| extend nics=array_length(properties.networkProfile.networkInterfaces)
| mv-expand nic=properties.networkProfile.networkInterfaces
| where nics == 1 or nic.properties.primary =~ 'true' or isempty(nic)
| project vmId = id, vmName = name, vmSize=tostring(properties.hardwareProfile.vmSize), nicId = tostring(nic.id)
| join kind=leftouter (
    Resources
    | where type =~ 'microsoft.network/networkinterfaces'
    | extend ipConfigsCount=array_length(properties.ipConfigurations)
    | mv-expand ipconfig=properties.ipConfigurations
    | where ipConfigsCount == 1 or ipconfig.properties.primary =~ 'true'
    | project nicId = id, publicIpId = tostring(ipconfig.properties.publicIPAddress.id))
on nicId
| project-away nicId1
| summarize by vmId, vmName, vmSize, nicId, publicIpId
| join kind=leftouter (
    Resources
    | where type =~ 'microsoft.network/publicipaddresses'
    | project publicIpId = id, publicIpAddress = properties.ipAddress)
on publicIpId
| project-away publicIpId1
az graph query -q "Resources | where type =~ 'microsoft.compute/virtualmachines' | extend nics=array_length(properties.networkProfile.networkInterfaces) | mv-expand nic=properties.networkProfile.networkInterfaces | where nics == 1 or nic.properties.primary =~ 'true' or isempty(nic) | project vmId = id, vmName = name, vmSize=tostring(properties.hardwareProfile.vmSize), nicId = tostring(nic.id) | join kind=leftouter ( Resources | where type =~ 'microsoft.network/networkinterfaces' | extend ipConfigsCount=array_length(properties.ipConfigurations) | mv-expand ipconfig=properties.ipConfigurations | where ipConfigsCount == 1 or ipconfig.properties.primary =~ 'true' | project nicId = id, publicIpId = tostring(ipconfig.properties.publicIPAddress.id)) on nicId | project-away nicId1 | summarize by vmId, vmName, vmSize, nicId, publicIpId | join kind=leftouter ( Resources | where type =~ 'microsoft.network/publicipaddresses' | project publicIpId = id, publicIpAddress = properties.ipAddress) on publicIpId | project-away publicIpId1"

列出虚拟机上安装的所有扩展

首先,此查询针对虚拟机资源类型使用 extend 以获取大写的 (toupper()) ID、获取操作系统名称和类型,以及获取虚拟机大小。 获取大写的资源 ID 是准备联接另一个属性的好方法。 然后,该查询使用 join,并将 kind 设为 leftouter,通过匹配扩展 ID 的大写形式的 substring 来获取虚拟机扩展。 “/extensions/<ExtensionName>”之前的 ID 部分与虚拟机 ID 的格式相同,因此我们将此属性用于 join。 然后,将 summarizemake_list 一起用于虚拟机扩展的名称,以将 idOSNameOSTypeVMSize 相同的每个扩展名称合并到单个数组属性中。 最后,我们通过 asc 对小写的 OSName 进行 order by 操作。 默认情况下,order by 为降序。

Resources
| where type == 'microsoft.compute/virtualmachines'
| extend
    JoinID = toupper(id),
    OSName = tostring(properties.osProfile.computerName),
    OSType = tostring(properties.storageProfile.osDisk.osType),
    VMSize = tostring(properties.hardwareProfile.vmSize)
| join kind=leftouter(
    Resources
    | where type == 'microsoft.compute/virtualmachines/extensions'
    | extend
        VMId = toupper(substring(id, 0, indexof(id, '/extensions'))),
        ExtensionName = name
) on $left.JoinID == $right.VMId
| summarize Extensions = make_list(ExtensionName) by id, OSName, OSType, VMSize
| order by tolower(OSName) asc
az graph query -q "Resources | where type == 'microsoft.compute/virtualmachines' | extend JoinID = toupper(id), OSName = tostring(properties.osProfile.computerName), OSType = tostring(properties.storageProfile.osDisk.osType), VMSize = tostring(properties.hardwareProfile.vmSize) | join kind=leftouter( Resources | where type == 'microsoft.compute/virtualmachines/extensions' | extend VMId = toupper(substring(id, 0, indexof(id, '/extensions'))), ExtensionName = name ) on \$left.JoinID == \$right.VMId | summarize Extensions = make_list(ExtensionName) by id, OSName, OSType, VMSize | order by tolower(OSName) asc"

在资源组上查找具有特定标记的存储帐户

以下查询使用 inner 将存储帐户连接到具有指定标记名称和标记值(区分大小写)的资源组join

Resources
| where type =~ 'microsoft.storage/storageaccounts'
| join kind=inner (
    ResourceContainers
    | where type =~ 'microsoft.resources/subscriptions/resourcegroups'
    | where tags['Key1'] =~ 'Value1'
    | project subscriptionId, resourceGroup)
on subscriptionId, resourceGroup
| project-away subscriptionId1, resourceGroup1
az graph query -q "Resources | where type =~ 'microsoft.storage/storageaccounts' | join kind=inner ( ResourceContainers | where type =~ 'microsoft.resources/subscriptions/resourcegroups' | where tags['Key1'] =~ 'Value1' | project subscriptionId, resourceGroup) on subscriptionId, resourceGroup | project-away subscriptionId1, resourceGroup1"

如果必须查找不区分大小写的标记名称和标记值,请将 mv-expandbagexpansion 参数配合使用。 此查询使用的配额高于前一查询,因此只在必要的时候使用 mv-expand

Resources
| where type =~ 'microsoft.storage/storageaccounts'
| join kind=inner (
    ResourceContainers
    | where type =~ 'microsoft.resources/subscriptions/resourcegroups'
    | mv-expand bagexpansion=array tags
    | where isnotempty(tags)
    | where tags[0] =~ 'key1' and tags[1] =~ 'value1'
    | project subscriptionId, resourceGroup)
on subscriptionId, resourceGroup
| project-away subscriptionId1, resourceGroup1
az graph query -q "Resources | where type =~ 'microsoft.storage/storageaccounts' | join kind=inner ( ResourceContainers | where type =~ 'microsoft.resources/subscriptions/resourcegroups' | mv-expand bagexpansion=array tags | where isnotempty(tags) | where tags[0] =~ 'key1' and tags[1] =~ 'value1' | project subscriptionId, resourceGroup) on subscriptionId, resourceGroup | project-away subscriptionId1, resourceGroup1"

将两个查询的结果合并为单个结果

以下查询使用 unionResourceContainers 表中获取结果,并将它们添加到 Resources 表中的结果。

ResourceContainers
| where type=='microsoft.resources/subscriptions/resourcegroups' | project name, type  | limit 5
| union  (Resources | project name, type | limit 5)
az graph query -q "ResourceContainers | where type=='microsoft.resources/subscriptions/resourcegroups' | project name, type  | limit 5 | union  (Resources | project name, type | limit 5)"

获取网络接口所属的虚拟网络和子网

使用正则表达式 parse 从资源 ID 属性中获取虚拟网络和子网名称。 虽然 parse 支持从复杂字段获取数据,但如果属性存在,则最好直接访问属性,而不是使用 parse

Resources
| where type =~ 'microsoft.network/networkinterfaces'
| project id, ipConfigurations = properties.ipConfigurations
| mvexpand ipConfigurations
| project id, subnetId = tostring(ipConfigurations.properties.subnet.id)
| parse kind=regex subnetId with '/virtualNetworks/' virtualNetwork '/subnets/' subnet
| project id, virtualNetwork, subnet
az graph query -q "Resources | where type =~ 'microsoft.network/networkinterfaces' | project id, ipConfigurations = properties.ipConfigurations | mvexpand ipConfigurations | project id, subnetId = tostring(ipConfigurations.properties.subnet.id) | parse kind=regex subnetId with '/virtualNetworks/' virtualNetwork '/subnets/' subnet | project id, virtualNetwork, subnet"

按“电源状态”扩展属性汇总虚拟机

此查询使用虚拟机上的扩展属性按电源状态进行汇总。

Resources
| where type == 'microsoft.compute/virtualmachines'
| summarize count() by tostring(properties.extended.instanceView.powerState.code)
az graph query -q "Resources | where type == 'microsoft.compute/virtualmachines' | summarize count() by tostring(properties.extended.instanceView.powerState.code)"

后续步骤