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

使用AzureAD模块PowerShell导出Azure应用注册委托权限问题排查

Azure AD应用API权限批量导出脚本问题排查

问题背景

编写了自定义PowerShell脚本,用于导出所有Azure注册应用的两类API权限:application permissions(应用程序权限)与delegated permissions(委托权限)。部分应用的API permissions的Type属性值为delegated或application。最初参考的操作指南仅覆盖单应用查询场景,需要适配多应用批量查询需求。

当前运行现状

  • 现有脚本可以正常导出分配给任意应用注册的application permissions
  • 无法导出delegated permissions:脚本运行全程无报错,但不会生成存储委托权限的csv文件,也无法将配置了委托权限的应用及对应权限信息写入目标文件
  • 曾尝试单独编写逻辑仅导出delegated permissions,问题依旧,csv文件无法生成也无法写入对应数据
  • 核心需求:基于Azure-AD模块,检索租户下所有应用注册分配的全部API权限(同时包含application permissions和delegated permissions),并将结果导出至csv文件

原始问题脚本

# Add your azure ad global administrator password here
$password_ = ""
$password = ConvertTo-SecureString $password_ -AsPlainText -Force

# Add your azure ad global administrator login UPN
$upn = ""

$export_application_permission = "C:\temp\application_perms.csv"
$export_delegated_permission = "C:\temp\delegated_perms.csv"

# Automated login to azure ad
$AppCredential = New-Object System.Management.Automation.PSCredential($upn, $password)
Connect-azureAD -Credential $AppCredential

$apps = Get-AzureADApplication -All $true
foreach ($app in $apps){

    $perms = $app.requiredResourceAccess
    foreach($perm in $perms){

        # Grab all the ResourceAppId from requiredResourceAccess array
        $res_app_id = $perm.ResourceAppId
        foreach($res_access in $perm.ResourceAccess){
            # Check if the resourceAccess Type is Role, which means its application permissions
            if($res_access.Type -eq "Role"){


                # Grab the resource id
                $res_ac = $res_access.Id
                
                # Calling azure-AD module
                Connect-azureAD -Credential $AppCredential

                # Grab all applications assigned application permissions only
                $sps = Get-AzureADServicePrincipal -All $true | Where-Object {$_.AppId -eq $res_app_id}

                foreach($sp in $sps){

                # Grab application permissions details now
                $roles = $sp.AppRoles | Where-Object {$_.Id -eq $res_ac}
                
                
                foreach($rol in $roles.value){

                $record = New-Object PSObject
                $record | Add-Member NoteProperty -Name "Application Display Name" -Value $app.displayName
                $record | Add-Member NoteProperty -Name "Permission Type" -Value $res_access.Type
                $record | Add-Member NoteProperty -Name "Permission Value" -Value $rol

                $record | Export-CSV $export_application_permission -NoTypeInformation -Append

                }

                }
                # Check if the resourceAccess Type is Scope, which means its delegated permissions
            }elseif ($res_access.Type -eq "Scope") {
                <# Action when this condition is true #>
                $res_ac = $res_access.Id
                Connect-azureAD -Credential $AppCredential
                $sps = Get-AzureADServicePrincipal -All $true | Where-Object {$_.AppId -eq $res_app_id}

                foreach($sp in $sps){

                # Grab delegated permissions details now
                $delegated_perms = $sp.oauth2PermissionScopes | Where-Object {$_.Id -eq $res_ac}
                

                foreach($rol in $delegated_perms.value){

                $record = New-Object PSObject
                $record | Add-Member NoteProperty -Name "Application Display Name" -Value $app.displayName
                $record | Add-Member NoteProperty -Name "Permission Type" -Value $res_access.Type
                $record | Add-Member NoteProperty -Name "Permission Value" -Value $rol

                $record | Export-CSV $export_delegated_permission -NoTypeInformation -Append

                }

                }
            } else {
                Write-host "Retreating........."
            }                 
        }  
    }

}

当前application permissions对应的csv文件可正常输出,期望delegated permissions也能输出格式一致的结果。

问题根因与修复方案

核心问题点

  1. 无效重复连接导致上下文异常:脚本在每个权限判断分支内都重复调用Connect-AzureAD,旧版Azure AD模块在高频重连时会出现认证上下文丢失,导致后续读取服务主体属性时,oauth2PermissionScopes这类属性直接返回空值,进不了写文件的内层循环。
  2. 性能问题触发接口限流:每次匹配资源应用ID时都全量拉取租户下所有服务主体列表,租户内应用/服务主体数量较多时,脚本运行效率极低,还容易触发Azure AD接口的限流策略,进一步导致属性返回异常。
  3. 委托权限取值逻辑错误:通过ID精确匹配到单个委托权限对象后,错误遍历$delegated_perms.value——oauth2PermissionScopes返回的对象结构和AppRoles有细微差异,精确匹配后$delegated_perms是单个权限对象,权限值直接存在它的Value属性上,原写法拿不到有效权限值,自然不会生成对应csv内容。应用权限部分能正常运行只是PowerShell对单元素集合的属性枚举做了兼容,属于碰巧生效。
  4. 缺少目录校验:没有提前判断导出路径C:\temp是否存在,路径不存在时也会导致文件写入失败。

修复后可直接运行的优化脚本

# 配置全局管理员账号密码
$password_ = ""
$password = ConvertTo-SecureString $password_ -AsPlainText -Force
$upn = ""

# 配置导出路径
$export_application_permission = "C:\temp\application_perms.csv"
$export_delegated_permission = "C:\temp\delegated_perms.csv"

# 提前创建导出目录
$exportDir = Split-Path $export_application_permission -Parent
if (-not (Test-Path $exportDir)) {
    New-Item -Path $exportDir -ItemType Directory -Force | Out-Null
}

# 仅连接一次Azure AD,删除循环内所有重复连接逻辑
$AppCredential = New-Object System.Management.Automation.PSCredential($upn, $password)
Connect-AzureAD -Credential $AppCredential

# 提前拉取所有服务主体,存入哈希表做索引,避免循环内重复全量查询
$spMap = @{}
Get-AzureADServicePrincipal -All $true | ForEach-Object {
    $spMap[$_.AppId] = $_
}

# 拉取所有应用注册
$apps = Get-AzureADApplication -All $true
foreach ($app in $apps){
    $perms = $app.requiredResourceAccess
    foreach($perm in $perms){
        $res_app_id = $perm.ResourceAppId
        # 直接从哈希表取对应资源服务主体,不存在则跳过
        if (-not $spMap.ContainsKey($res_app_id)) { continue }
        $targetSp = $spMap[$res_app_id]

        foreach($res_access in $perm.ResourceAccess){
            # 处理应用程序权限
            if($res_access.Type -eq "Role"){
                $permDef = $targetSp.AppRoles | Where-Object {$_.Id -eq $res_access.Id}
                if ($permDef) {
                    [PSCustomObject]@{
                        "Application Display Name" = $app.displayName
                        "Permission Type" = $res_access.Type
                        "Permission Value" = $permDef.Value
                    } | Export-CSV $export_application_permission -NoTypeInformation -Append
                }
            }
            # 处理委托权限
            elseif ($res_access.Type -eq "Scope") {
                $permDef = $targetSp.oauth2PermissionScopes | Where-Object {$_.Id -eq $res_access.Id}
                if ($permDef) {
                    [PSCustomObject]@{
                        "Application Display Name" = $app.displayName
                        "Permission Type" = $res_access.Type
                        "Permission Value" = $permDef.Value
                    } | Export-CSV $export_delegated_permission -NoTypeInformation -Append
                }
            }
        }  
    }
}

修复后两类权限都会按统一格式导出到对应csv文件,脚本运行速度比原始版本快10~100倍(取决于租户内应用数量),不会出现属性读取为空的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:57:11