PowerShell 技能连载 - Azure Policy 合规治理

适用于 PowerShell 7.0 及以上版本

在多团队、多订阅的云环境中,资源合规性是治理的核心难题。开发团队随手创建了一个 Premium SKU 的 Redis 缓存,费用瞬间翻了十倍;某个资源组忘了打标签,月底账单无法分摊到业务线;还有人不小心把资源部署到了不支持数据驻留的区域。这些问题在单订阅时还能人工检查,到了几十个订阅、上百个资源组的规模,靠人工审计根本忙不过来。

Azure Policy 提供了声明式的合规规则引擎,可以在资源创建或更新时自动评估是否满足预设条件。不满足条件的资源可以被审计记录、拒绝创建,甚至自动修复到合规状态。结合管理组(Management Group)的层级结构,一条策略可以向下继承到所有子订阅,真正做到”治理即代码”。

本文将演示如何通过 PowerShell 完成 Azure Policy 的三大核心操作:策略定义与管理、策略分配与范围控制、合规审计与自动修复。让你从手工巡检的时代彻底迈入自动化合规治理。

策略定义与管理

策略定义是合规治理的基础构建块。Azure 提供了数百个内置策略定义,覆盖了命名规范、SKU 限制、区域约束、强制标记等常见场景。当内置策略无法满足需求时,可以通过自定义策略定义来实现精确的合规规则。下面的脚本演示如何检索内置策略、创建参数化的自定义策略,并将策略组织到策略集(Initiative)中统一管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 连接 Azure
Connect-AzAccount -Subscription 'production-subscription'

# --- 检索常用内置策略定义 ---
# 查找与"允许位置"相关的内置策略
$builtInPolicies = Get-AzPolicyDefinition | Where-Object {
$_.DisplayName -like '*allowed locations*' -or
$_.DisplayName -like '*允许的位置*'
} | Select-Object -First 5 DisplayName, PolicyType, Name

Write-Host '=== 内置策略:允许的位置 ===' -ForegroundColor Cyan
$builtInPolicies | Format-Table -AutoSize

# 查找与"强制标记"相关的内置策略
$tagPolicies = Get-AzPolicyDefinition | Where-Object {
$_.DisplayName -like '*tag*' -and $_.PolicyType -eq 'BuiltIn'
} | Select-Object -First 5 DisplayName, Name

Write-Host '=== 内置策略:标记相关 ===' -ForegroundColor Cyan
$tagPolicies | Format-Table -AutoSize

# --- 创建自定义策略定义:禁止创建未标记成本中心的资源 ---
$policyRule = @{
if = @{
allOf = @(
@{
field = 'type'
notLike = 'Microsoft.Resources/*'
}
@{
field = '[concat(''tags'', ''.'', ''CostCenter'')]'
exists = 'false'
}
)
}
then = @{
effect = 'deny'
}
}

$policyParameters = @{
tagName = @{
type = 'String'
metadata = @{
displayName = '标记名称'
description = '要求必须存在的标记名称'
}
}
}

# 使用参数化的方式构建策略规则
$parameterizedRule = @{
if = @{
allOf = @(
@{
field = 'type'
notLike = 'Microsoft.Resources/*'
}
@{
field = "[concat('tags', '.', parameters('tagName'))]"
exists = 'false'
}
)
}
then = @{
effect = 'deny'
}
}

$customPolicy = New-AzPolicyDefinition `
-Name 'require-mandatory-tag' `
-DisplayName '要求资源必须包含指定标记' `
-Description '拒绝创建未包含指定标记的资源,确保成本分摊和资源归属可追溯' `
-Policy $parameterizedRule `
-Parameter $policyParameters `
-Mode 'Indexed'

Write-Host "自定义策略已创建: $($customPolicy.Name)" -ForegroundColor Green

# --- 创建策略集(Initiative)将多个策略打包管理 ---
$initiativeDefinition = @{
name = 'cost-governance-initiative'
displayName = '成本治理策略集'
description = '统一管理所有与成本控制相关的策略,包括标记、SKU 限制和区域约束'
policyDefinitions = @(
@{
policyDefinitionId = $customPolicy.Id
parameters = @{
tagName = @{ value = 'CostCenter' }
}
}
)
}

# 获取内置的"允许位置"策略
$locationPolicy = Get-AzPolicyDefinition |
Where-Object { $_.Name -eq 'e56962a6-4747-49cd-b67b-bf8b01975c4c' }

if ($locationPolicy) {
$initiativeDefinition.policyDefinitions += @{
policyDefinitionId = $locationPolicy.Id
parameters = @{
listOfAllowedLocations = @{
value = @('eastasia', 'southeastasia', 'eastus', 'westus2')
}
}
}
}

$initiative = New-AzPolicySetDefinition `
-Name $initiativeDefinition.name `
-DisplayName $initiativeDefinition.displayName `
-Description $initiativeDefinition.description `
-PolicyDefinition ($initiativeDefinition.policyDefinitions | ConvertTo-Json -Depth 5)

Write-Host "策略集已创建: $($initiative.Name)" -ForegroundColor Green

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
=== 内置策略:允许的位置 ===
DisplayName PolicyType Name
----------- ---------- ----
允许的资源位置 BuiltIn e56962a6-4747-49cd-b67b-bf8b01975c4c
允许的资源组位置 BuiltIn e765b5de-1225-4ba3-bd56-1ac667b5e923

=== 内置策略:标记相关 ===
DisplayName Name
----------- ----
要求指定标记值 1e30110a-5ceb-460c-a204-f92a36c51380
在资源组中添加标记 96670d01-0a4d-4649-9c89-66d8e766f889
从资源组继承标记 cd3aa116-7824-4a4f-820e-52c5b31d1d0e
要求资源组具有标记 96670d01-0a4d-4649-66d8e766f889
强制添加标记及其默认值 1e30110a-5ceb-460c-a204-f92a36c51380

自定义策略已创建: require-mandatory-tag
策略集已创建: cost-governance-initiative

策略分配与范围控制

策略定义和策略集创建完成后,需要将它们分配到特定的范围才能生效。Azure Policy 支持多层级范围分配:管理组、订阅、资源组,甚至单个资源。策略分配时可以传入参数值来覆盖默认配置,还可以设置豁免(Exemption)来排除特定资源。下面的脚本演示订阅级分配、管理组级批量分配,以及针对特定资源的豁免配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# --- 订阅级策略分配 ---
$subscriptionId = (Get-AzContext).Subscription.Id
$scope = "/subscriptions/$subscriptionId"

# 获取之前创建的策略集
$initiative = Get-AzPolicySetDefinition -Name 'cost-governance-initiative'

# 创建订阅级策略分配
$assignment = New-AzPolicyAssignment `
-Name 'cost-governance-sub' `
-DisplayName '订阅级成本治理策略' `
-Scope $scope `
-PolicySetDefinition $initiative `
-Description '在此订阅中强制执行标记要求和区域限制'

Write-Host "订阅级策略分配已创建: $($assignment.Name)" -ForegroundColor Green

# --- 资源组级策略分配(更精细的控制) ---
$rgScope = "$scope/resourceGroups/rg-production"
$skuPolicy = Get-AzPolicyDefinition |
Where-Object { $_.DisplayName -like '*allowed resource types*' } |
Select-Object -First 1

# 为生产环境资源组分配更严格的策略
$rgAssignment = New-AzPolicyAssignment `
-Name 'production-sku-restriction' `
-DisplayName '生产环境 SKU 限制' `
-Scope $rgScope `
-PolicyDefinition $skuPolicy `
-Description '限制生产环境只允许创建特定资源类型'

Write-Host "资源组级策略分配已创建: $($rgAssignment.Name)" -ForegroundColor Green

# --- 管理组级批量分配(跨订阅统一治理) ---
$mgScope = '/providers/Microsoft.Management/managementGroups/mg-enterprise'

# 获取管理组下的所有订阅
$mgSubscriptions = Get-AzManagementGroupSubscription `
-GroupName 'mg-enterprise' -Expand

Write-Host "管理组下的订阅数量: $($mgSubscriptions.Count)"

# 为管理组分配策略集,所有子订阅自动继承
$mgAssignment = New-AzPolicyAssignment `
-Name 'enterprise-governance' `
-DisplayName '企业级合规治理策略' `
-Scope $mgScope `
-PolicySetDefinition $initiative `
-EnforcementMode 'Default'

Write-Host "管理组级策略分配已创建(子订阅将自动继承)" -ForegroundColor Green

# --- 配置策略豁免 ---
# 对特定资源(如测试环境)豁免标记策略
$exemptionScope = "$scope/resourceGroups/rg-sandbox"
$waiverAssignment = Get-AzPolicyAssignment -Name 'cost-governance-sub'

# 创建策略豁免
$exemption = New-AzPolicyExemption `
-Name 'sandbox-tag-exemption' `
-DisplayName '沙盒环境标记豁免' `
-Scope $exemptionScope `
-PolicyAssignment $waiverAssignment `
-ExemptionCategory 'Waiver' `
-ExpiresOn (Get-Date).AddMonths(6) `
-Description '沙盒环境暂不强制标记要求,6个月后重新评估'

Write-Host "策略豁免已创建,有效期至: $($exemption.Properties.ExpiresOn)" -ForegroundColor Green

# --- 查看所有策略分配 ---
$allAssignments = Get-AzPolicyAssignment | Where-Object {
$_.Scope -like "*$subscriptionId*"
} | Select-Object DisplayName, Scope, EnforcementMode

Write-Host "`n=== 当前订阅下的策略分配 ===" -ForegroundColor Cyan
$allAssignments | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
订阅级策略分配已创建: cost-governance-sub
资源组级策略分配已创建: production-sku-restriction
管理组下的订阅数量: 8
管理组级策略分配已创建(子订阅将自动继承)
策略豁免已创建,有效期至: 2026-09-17

=== 当前订阅下的策略分配 ===
DisplayName Scope EnforcementMode
----------- ----- ---------------
订阅级成本治理策略 /subscriptions/xxxx-xxxx-xxxx Default
生产环境 SKU 限制 /subscriptions/xxxx-xxxx/.../rg-production Default
企业级合规治理策略 /providers/Microsoft.Management/.../mg-enterprise Default

沙盒环境标记豁免已生效,到期时间: 2026-09-17T08:00:00Z

合规审计与自动修复

策略分配完成后,持续的合规监控是确保治理有效性的关键。Azure Policy 会定期评估资源的合规状态,对于不合规的资源可以配置自动修复任务将其修正到合规状态。通过 PowerShell 脚本化的合规审计,可以生成定期的合规报告、追踪合规趋势,并针对高优先级的不合规资源触发修复操作。下面的脚本演示如何查询合规状态、创建修复任务以及生成合规趋势报告。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# --- 查询合规状态 ---
$subscriptionId = (Get-AzContext).Subscription.Id
$scope = "/subscriptions/$subscriptionId"

# 获取所有策略分配的合规状态摘要
$complianceStates = Get-AzPolicyState | Where-Object {
$_.ResourceLocation -and $_.PolicyAssignmentName
} | Group-Object PolicyAssignmentName, ComplianceState | ForEach-Object {
[PSCustomObject]@{
PolicyAssignment = $_.Values[0]
ComplianceState = $_.Values[1]
ResourceCount = $_.Count
}
}

Write-Host '=== 合规状态摘要 ===' -ForegroundColor Cyan
$complianceStates | Sort-Object PolicyAssignment, ComplianceState |
Format-Table -AutoSize

# 查询不合规资源的详细信息
$nonCompliant = Get-AzPolicyState | Where-Object {
$_.ComplianceState -eq 'NonCompliant'
} | Select-Object -First 20 `
ResourceId, ResourceType, ResourceLocation,
PolicyDefinitionName, PolicyAssignmentName,
Timestamp

Write-Host "`n=== 不合规资源(前 20 条)===" -ForegroundColor Yellow
$nonCompliant | Format-Table -AutoSize

# --- 创建自动修复任务 ---
# 获取需要修复的策略分配
$tagAssignment = Get-AzPolicyAssignment -Name 'cost-governance-sub'

# 创建修复任务:为缺少标记的资源自动添加默认标记值
$remediationTask = Start-AzPolicyRemediation `
-Name 'remediate-missing-tags' `
-PolicyAssignmentId $tagAssignment.PolicyAssignmentId `
-ResourceDiscoveryMode 'ExistingNonCompliant' `
-Description '为所有缺少 CostCenter 标记的资源添加默认值'

Write-Host "修复任务已启动: $($remediationTask.Name)" -ForegroundColor Green
Write-Host "待修复资源数: $($remediationTask.ProvisioningState)"

# 轮询修复任务状态
$taskName = $remediationTask.Name
$maxRetries = 12
$retryCount = 0

while ($retryCount -lt $maxRetries) {
Start-Sleep -Seconds 30
$task = Get-AzPolicyRemediation -Name $taskName `
-Scope $scope -ErrorAction SilentlyContinue

if ($task -and $task.ProvisioningState -eq 'Succeeded') {
Write-Host "修复任务完成" -ForegroundColor Green
break
}

$retryCount++
Write-Host "等待修复任务完成... ($retryCount/$maxRetries)"
}

# --- 生成合规趋势报告 ---
function Get-ComplianceTrend {
param(
[string]$Scope,
[int]$Days = 30
)

$startDate = (Get-Date).AddDays(-$Days)
$trend = @()

for ($day = 0; $day -lt $Days; $day += 7) {
$checkDate = $startDate.AddDays($day)
$dateLabel = $checkDate.ToString('yyyy-MM-dd')

# 获取该时间段的合规统计
$states = Get-AzPolicyState | Where-Object {
$_.Timestamp -ge $checkDate -and
$_.Timestamp -lt $checkDate.AddDays(7)
}

$total = ($states | Measure-Object).Count
$compliant = ($states | Where-Object {
$_.ComplianceState -eq 'Compliant'
} | Measure-Object).Count

$complianceRate = if ($total -gt 0) {
[math]::Round(($compliant / $total) * 100, 1)
} else {
0
}

$trend += [PSCustomObject]@{
Week = $dateLabel
TotalResources = $total
Compliant = $compliant
NonCompliant = $total - $compliant
Rate = "$complianceRate%"
}
}

return $trend
}

# 生成最近 30 天的合规趋势
$trendReport = Get-ComplianceTrend -Scope $scope -Days 30

Write-Host "`n=== 合规趋势报告(最近 30 天)===" -ForegroundColor Cyan
$trendReport | Format-Table -AutoSize

# 计算总体合规率
$latestWeek = $trendReport | Select-Object -Last 1
Write-Host "`n最新一周合规率: $($latestWeek.Rate)" -ForegroundColor Green

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
=== 合规状态摘要 ===
PolicyAssignment ComplianceState ResourceCount
--------------- --------------- -------------
cost-governance-sub Compliant 156
cost-governance-sub NonCompliant 23
enterprise-governance Compliant 1024
enterprise-governance NonCompliant 87
production-sku-restriction Compliant 48
production-sku-restriction NonCompliant 3

=== 不合规资源(前 20 条)===
ResourceId ResourceType ResourceLocation Timestamp
--------- ------------ ---------------- ---------
/subs/.../rg-prod/vm-test-01 Microsoft.Compute eastasia 2026-03-17 07:45:00
/subs/.../rg-prod/st-shared-data Microsoft.Storage eastasia 2026-03-17 07:30:00
/subs/.../rg-prod/plan-dev Microsoft.Web eastasia 2026-03-17 07:15:00

修复任务已启动: remediate-missing-tags
待修复资源数: Accepted
等待修复任务完成... (1/12)
等待修复任务完成... (2/12)
修复任务完成

=== 合规趋势报告(最近 30 天)===
Week TotalResources Compliant NonCompliant Rate
---- -------------- --------- ------------ ----
2026-02-15 187 142 45 75.9%
2026-02-22 195 158 37 81.0%
2026-03-01 210 179 31 85.2%
2026-03-08 215 190 25 88.4%
2026-03-15 220 197 23 89.5%

最新一周合规率: 89.5%

注意事项

  1. 策略评估延迟:策略分配创建或更新后,Azure Policy 引擎需要 15 到 30 分钟完成初次评估。在此期间,Azure Portal 中显示的合规状态可能不准确。如果需要立即验证某个资源的合规性,可以使用 Get-AzPolicyState 按 ResourceId 精确查询。

  2. Deny 效果的影响范围:使用 deny 效果的策略会阻止不合规资源的创建和更新操作,这在生产环境中可能影响正常的部署流程。建议先用 audit 效果观察一段时间,确认影响范围后再切换为 deny。可以在策略定义中使用 DefaultMode 来控制效果。

  3. 修复任务的权限要求:自动修复任务使用托管标识来执行资源修改操作。创建修复任务前,必须确保策略定义中配置了正确的 roleDefinitionIds,并且修复任务的托管标识已被授予相应的 RBAC 角色,否则修复任务会因权限不足而失败。

  4. 策略豁免的审批流程:虽然 PowerShell 可以直接创建策略豁免,但在企业环境中建议将豁免请求纳入变更管理流程。可以结合 Azure DevOps Pipeline 或 GitHub Actions 实现豁免的审批和自动化创建,确保每一次豁免都有迹可循。

  5. 策略定义的模式选择:策略定义的 mode 参数决定了策略评估的资源范围。All 模式覆盖所有资源类型,Indexed 模式仅评估支持标记和位置的资源类型。针对标记和位置的策略应使用 Indexed 模式以减少评估开销,而针对 SKU 限制的策略需要使用 All 模式。

  6. 大规模环境的性能优化:在管理组层级管理数百个订阅时,避免为每个订阅单独创建策略分配。优先在管理组层级分配策略集(Initiative),让策略自动向下继承。同时,善用 resourceSelectorselectors 属性来精确控制策略评估的资源范围,减少不必要的评估开销。

PowerShell 技能连载 - Azure Policy 合规管理

适用于 PowerShell 5.1 及以上版本

随着企业云基础设施规模不断膨胀,资源合规性管理成为运维团队的核心挑战。Azure Policy 是微软 Azure 平台提供的治理服务,能够在资源创建和更新时自动执行组织规则,例如限制资源类型、强制标签策略、审核配置基线等。通过 PowerShell 的 Az 模块,我们可以将策略的定义、分配和合规审查全部纳入自动化流水线,实现”基础设施即代码”的治理闭环。

传统的合规审计往往依赖人工巡检或第三方工具,耗时且容易遗漏。Azure Policy 将合规检查前移到资源生命周期中,一旦资源偏离预期状态就会触发警报甚至自动修正。结合 PowerShell 的批量处理能力,管理员可以在几分钟内对数百个订阅进行策略评估,快速定位不合规资源并生成报告,大幅降低安全风险和审计成本。

本文将介绍如何使用 PowerShell 完成 Azure Policy 的常见操作,包括查询策略定义、分配策略到作用域、检索合规状态,以及批量导出合规报告,帮助你构建可重复、可审计的云治理工作流。

查询 Azure Policy 内置定义

Azure 提供了大量内置策略定义,覆盖存储、网络、计算、安全等多个领域。我们可以用 PowerShell 快速搜索并筛选需要的策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 连接 Azure 账户(如已登录可跳过)
Connect-AzAccount

# 搜索与"标签"相关的内置策略定义
$tagPolicies = Get-AzPolicyDefinition | Where-Object {
$_.Properties.DisplayName -match "tag" -and
$_.Properties.PolicyType -eq "BuiltIn"
}

# 输出策略名称和显示名
foreach ($policy in $tagPolicies) {
[PSCustomObject]@{
Name = $policy.Name
DisplayName = $policy.Properties.DisplayName
Category = $policy.Properties.Metadata.category
}
}

执行结果示例:

1
2
3
4
5
Name                                  DisplayName                                Category
---- ----------- --------
1e30110a-5ceb-460c-a204-fsdfsdf Require a tag on resources Tags
8e346d3c-483d-4fef-8d21-dsfsdf Inherit a tag from the resource group Tags
...

通过 Get-AzPolicyDefinition 获取所有策略定义后,用 Where-ObjectDisplayNameCategory 进行筛选,方便找到目标策略。PolicyTypeBuiltIn 表示微软内置策略,Custom 则是用户自定义策略。

分配策略到指定作用域

找到合适的策略后,下一步是将其分配到订阅或资源组级别。以下示例将”要求资源具有环境标签”的内置策略分配到指定资源组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 获取目标资源组信息
$rg = Get-AzResourceGroup -Name "prod-app-rg"

# 获取内置策略定义(要求资源必须带有指定标签)
$policyDef = Get-AzPolicyDefinition | Where-Object {
$_.Properties.DisplayName -eq "Require a tag on resources"
} | Select-Object -First 1

# 构造策略参数:指定必须存在的标签名为 "Environment"
$policyParam = @{
tagName = "Environment"
}

# 分配策略到资源组
$assignment = New-AzPolicyAssignment `
-Name "require-env-tag" `
-DisplayName "要求所有资源带有 Environment 标签" `
-PolicyDefinition $policyDef `
-Scope $rg.ResourceId `
-PolicyParameterObject $policyParam

Write-Host "策略已分配,AssignmentId: $($assignment.PolicyAssignmentId)"

执行结果示例:

1
策略已分配,AssignmentId: /subscriptions/xxxx-xxxx/resourceGroups/prod-app-rg/providers/Microsoft.Authorization/policyAssignments/require-env-tag

New-AzPolicyAssignmentScope 参数支持订阅级别(/subscriptions/{id})、资源组级别(含 /resourceGroups/{name})甚至单个资源级别。PolicyParameterObject 以哈希表形式传递策略所需的参数,不同策略需要的参数各异,可查看策略定义的 Properties.Parameters 了解详情。

检索合规状态

策略分配完成后,需要定期检查资源的合规情况。以下脚本查询指定订阅下所有策略分配的合规状态,并筛选出不合规的资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 获取当前订阅 ID
$subscriptionId = (Get-AzContext).Subscription.Id

# 查询最近一次策略评估的合规状态
$complianceStates = Get-AzPolicyState | Where-Object {
$_.ComplianceState -eq "NonCompliant"
}

# 按策略分配分组统计不合规资源数量
$summary = @{}
foreach ($state in $complianceStates) {
$key = $state.PolicyAssignmentName
if (-not $summary.ContainsKey($key)) {
$summary[$key] = 0
}
$summary[$key]++
}

foreach ($item in $summary.GetEnumerator() | Sort-Object Value -Descending) {
[PSCustomObject]@{
PolicyAssignment = $item.Key
NonCompliantCount = $item.Value
}
}

执行结果示例:

1
2
3
4
5
PolicyAssignment             NonCompliantCount
---------------- -----------------
require-env-tag 12
audit-storage-https 5
deny-public-endpoints 3

Get-AzPolicyState 返回的是策略评估的详细记录,每条记录对应一个资源与一条策略的关系。ComplianceState 字段取值 Compliant(合规)或 NonCompliant(不合规)。按策略分配名称分组统计,可以快速了解哪些策略的不合规资源最多,便于优先处理。

批量导出合规报告

对于审计和归档需求,我们通常需要将合规数据导出为 CSV 文件。以下脚本将所有不合规资源的详细信息导出为结构化报告。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 定义输出路径
$reportDate = Get-Date -Format "yyyyMMdd"
$csvPath = "$HOME/AzurePolicyReport_$reportDate.csv"

# 获取所有不合规状态记录
$nonCompliant = Get-AzPolicyState | Where-Object {
$_.ComplianceState -eq "NonCompliant"
}

# 构造报告对象
$reportRows = foreach ($record in $nonCompliant) {
[PSCustomObject]@{
Timestamp = $record.Timestamp
ResourceId = $record.ResourceId
ResourceType = $record.ResourceType
ResourceGroup = $record.ResourceGroup
PolicyAssignment = $record.PolicyAssignmentName
PolicyDefinition = $record.PolicyDefinitionName
ComplianceState = $record.ComplianceState
}
}

# 导出为 CSV
$reportRows | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8

Write-Host "合规报告已导出: $csvPath"
Write-Host "共 $($reportRows.Count) 条不合规记录"

执行结果示例:

1
2
合规报告已导出: /home/user/AzurePolicyReport_20251110.csv
20 条不合规记录

导出的 CSV 文件包含资源 ID、类型、所属资源组、关联策略等字段,可以直接用 Excel 打开进行筛选和透视分析,也可以导入到 SIEM 或仪表盘系统中做持续监控。

注意事项

  1. 模块版本:确保安装了最新版 Az.PolicyAz.Resources 模块(Install-Module Az.Resources -Force),旧版本可能缺少 Get-AzPolicyState 等关键命令。PowerShell 5.1 用户注意 .NET Framework 版本兼容性。

  2. 权限要求:执行策略相关操作需要订阅级别的 Microsoft.Authorization/policyAssignments/* 权限。建议使用专用的服务主体(Service Principal)并在 CI/CD 流水线中运行,避免使用个人账户。

  3. 合规数据延迟Get-AzPolicyState 返回的是最近一次策略评估引擎扫描的结果,通常有 15-30 分钟的延迟。资源变更后不会立即反映在合规状态中,如需即时验证可手动触发评估:Start-AzPolicyComplianceScan

  4. 大数据量处理:在拥有数千资源的订阅中,Get-AzPolicyState 可能返回海量记录。建议通过 -Filter 参数缩小范围,例如 Get-AzPolicyState -Filter "PolicyAssignmentName eq 'require-env-tag'" 只查询特定策略的合规数据,避免内存溢出。

  5. 策略豁免管理:某些资源可能需要临时豁免策略(如测试环境),可使用 New-AzPolicyExemption 创建豁免记录并设置过期时间,而不是直接删除策略分配,以保持治理完整性。

  6. 自定义策略定义:当内置策略无法满足需求时,可通过 New-AzPolicyDefinition 创建自定义策略。策略规则使用 JSON 格式声明条件与效果(如 Audit、Deny、DeployIfNotExists),建议将策略 JSON 纳入 Git 版本控制,配合 CI/CD 流水线自动部署,确保策略变更可追溯、可回滚。

掌握以上操作后,你可以将 Azure Policy 的日常管理全部纳入 PowerShell 自动化流程,从策略定义到合规监控再到报告导出,形成完整的治理闭环。