You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Graph API导出Azure应用注册的委托与应用权限

问题原因

原脚本无法导出全量权限数据,核心问题如下:

  • 未处理Graph API分页逻辑:默认单页最多返回100条条目,会遗漏大量应用注册、服务主体数据
  • Where-Object筛选语法错误:匹配条件未按要求使用脚本块包裹,导致权限匹配逻辑失效
  • 逻辑覆盖不全:仅实现了委托权限的部分匹配逻辑,未覆盖应用权限匹配、资源名称/权限名称关联、结果收集、CSV导出的完整流程
  • 匹配逻辑不合理:使用模糊匹配-match做权限ID、资源ID的匹配,容易出现匹配错误,ID为固定Guid值应使用精确匹配-eq
修正后完整脚本
# 依赖:提前安装MSAL.ps模块,安装命令:Install-Module MSAL.PS -Scope CurrentUser
# 前置要求:脚本使用的Azure AD应用注册需授予Application.Read.All、Directory.Read.All应用权限,并完成管理员同意
$connectiondetails = @{
    'clientid'     = "" # 填入你的应用程序(客户端)ID
    'tenantid'     = "" # 填入你的租户ID
    'clientSecret' = "" | ConvertTo-SecureString -AsPlainText -Force # 填入你的客户端密钥
}

$token = Get-MsalToken @connectiondetails
$accessToken = $token.AccessToken

# 配置CSV导出路径
$delegatedPermsExportPath = "C:\temp\delegatedpermissions.csv"
$applicationPermsExportPath = "C:\temp\applicationpermissions.csv"

# 通用方法:拉取Graph API全量分页数据
function Get-GraphAllPages {
    param(
        [string]$Uri,
        [string]$AccessToken
    )
    $headers = @{ Authorization = "bearer $AccessToken" }
    $allResults = @()
    $nextLink = $Uri
    while (-not [string]::IsNullOrEmpty($nextLink)) {
        $response = Invoke-RestMethod -Method Get -Uri $nextLink -ContentType "application/json" -Headers $headers
        $allResults += $response.value
        $nextLink = $response.'@odata.nextLink'
    }
    return $allResults
}

# 1. 拉取全量应用注册数据
$allApps = Get-GraphAllPages -Uri "https://graph.microsoft.com/v1.0/applications" -AccessToken $accessToken

# 2. 拉取全量服务主体数据,构建权限映射表
$allServicePrincipals = Get-GraphAllPages -Uri "https://graph.microsoft.com/v1.0/serviceprincipals" -AccessToken $accessToken
# 资源AppId映射:Key=资源AppId,Value=资源显示名称
$resourceMap = @{}
# 委托权限映射:Key=资源AppId|权限Id,Value=权限值
$delegatedPermMap = @{}
# 应用权限映射:Key=资源AppId|权限Id,Value=权限值
$appPermMap = @{}

foreach ($sp in $allServicePrincipals) {
    $resourceMap[$sp.appId] = $sp.displayName
    # 处理委托权限(oauth2PermissionScopes)
    foreach ($scope in $sp.oauth2PermissionScopes) {
        $key = "{0}|{1}" -f $sp.appId, $scope.id
        $delegatedPermMap[$key] = $scope.value
    }
    # 处理应用权限(appRoles)
    foreach ($role in $sp.appRoles) {
        $key = "{0}|{1}" -f $sp.appId, $role.id
        $appPermMap[$key] = $role.value
    }
}

# 3. 遍历所有应用注册,关联权限信息
$finalDelegatedPerms = @()
$finalAppPerms = @()

foreach ($app in $allApps) {
    foreach ($resourceAccess in $app.requiredResourceAccess) {
        $resourceAppId = $resourceAccess.resourceAppId
        $resourceName = if ($resourceMap.ContainsKey($resourceAppId)) { $resourceMap[$resourceAppId] } else { "未知资源($resourceAppId)" }
        foreach ($permEntry in $resourceAccess.resourceAccess) {
            $permKey = "{0}|{1}" -f $resourceAppId, $permEntry.id
            # 委托权限
            if ($permEntry.type -eq "Scope") {
                $permName = if ($delegatedPermMap.ContainsKey($permKey)) { $delegatedPermMap[$permKey] } else { "未知权限($($permEntry.id))" }
                $finalDelegatedPerms += [PSCustomObject]@{
                    应用显示名称 = $app.displayName
                    应用客户端ID = $app.appId
                    资源显示名称 = $resourceName
                    权限类型     = "委托权限"
                    权限名称     = $permName
                    权限ID       = $permEntry.id
                }
            }
            # 应用权限
            if ($permEntry.type -eq "Role") {
                $permName = if ($appPermMap.ContainsKey($permKey)) { $appPermMap[$permKey] } else { "未知权限($($permEntry.id))" }
                $finalAppPerms += [PSCustomObject]@{
                    应用显示名称 = $app.displayName
                    应用客户端ID = $app.appId
                    资源显示名称 = $resourceName
                    权限类型     = "应用权限"
                    权限名称     = $permName
                    权限ID       = $permEntry.id
                }
            }
        }
    }
}

# 4. 导出为CSV文件,使用UTF8编码避免乱码
$finalDelegatedPerms | Export-Csv -Path $delegatedPermsExportPath -NoTypeInformation -Encoding UTF8
$finalAppPerms | Export-Csv -Path $applicationPermsExportPath -NoTypeInformation -Encoding UTF8

Write-Host "导出完成,委托权限文件:$delegatedPermsExportPath,应用权限文件:$applicationPermsExportPath"
使用说明
  • 运行前先安装MSAL.PS模块,执行命令Install-Module MSAL.PS -Scope CurrentUser
  • 在脚本配置段填入你自己的客户端ID、租户ID、客户端密钥
  • 确保使用的应用注册已经授予Application.Read.All、Directory.Read.All的应用权限,并完成管理员同意
  • 提前创建C:\temp目录,或自行修改导出路径为你本地存在的目录
  • 脚本会自动处理分页拉取全量数据,对于租户中已删除资源对应的残留权限ID,会标记为「未知资源」「未知权限」方便排查

内容的提问来源于stack exchange,提问作者Bernietechy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 18:48:25