Azure DevOps API获取AAD组成员返回数量不全问题咨询
问题原因
你遇到的成员拉取不全问题,是接口特性未做对应处理导致的,和用户特殊属性配置无关:
- 你当前使用的6.1-preview版本接口默认分页返回结果,单页不会返回全量直接成员,且该预览版本对分页令牌的处理存在已知bug,很容易漏返回结果
- 该接口默认仅返回目标组下的直接成员,不会自动递归展开嵌套在组内的子AAD组/DevOps组。你在Azure Portal和DevOps前端看到的成员数,是自动计算了所有嵌套子组成员的总数,仅发一次请求自然拿不到全量数据
- 额外注意:你贴的请求URL末尾多了一个多余的右括号
),实际调用时记得移除,避免触发异常返回。
解决方案
按以下逻辑调整调用方式即可拉取全量成员:
- 替换接口版本为7.1正式版,不要使用任何preview版本的Graph接口
- 增加分页处理逻辑:每次请求带上
$top=100参数拉取单页最大量结果,请求后检查响应头的X-MS-ContinuationToken字段,如果存在值就作为下一次请求的continuationToken参数传入,直到响应头没有该字段时,才拿全了当前组的所有直接成员 - 增加嵌套组递归逻辑:遍历拿到的直接成员时,判断成员类型,如果是组类型对象就递归执行分页拉取逻辑,直到所有层级的子组都遍历完成;如果是用户类型对象就收集到结果集中,注意加已处理组的标记,避免循环嵌套组导致死循环
PowerShell参考实现代码
# 配置基础参数 $orgName = "替换为你的Azure DevOps组织名" $pat = "替换为你的个人访问令牌,需授予Graph读取权限" $targetGroupDescriptor = "替换为目标AAD组的subjectDescriptor" $base64Auth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($pat)")) $requestHeaders = @{Authorization = "Basic $base64Auth"} $allMemberUsers = @() $processedGroupList = @() # 记录已处理的组,避免循环嵌套导致死循环 function Get-AllGroupMembers { param([string]$currentGroupDescriptor) # 跳过已经处理过的组 if ($processedGroupList -contains $currentGroupDescriptor) { return } $processedGroupList += $currentGroupDescriptor $nextPageToken = $null do { # 拼接请求地址 $requestUri = "https://vssps.dev.azure.com/$orgName/_apis/graph/Memberships/$currentGroupDescriptor?direction=down&`$top=100&api-version=7.1" if ($nextPageToken) { $requestUri += "&continuationToken=$nextPageToken" } # 发请求,保留响应头拿分页令牌 $response = Invoke-WebRequest -Uri $requestUri -Headers $requestHeaders -Method Get $pageResult = $response.Content | ConvertFrom-Json # 遍历当前页成员 foreach ($member in $pageResult.value) { $memberDsp = $member.memberDescriptor # 判断为组类型,递归拉取 if ($memberDsp -like "aad.gp*" -or $memberDsp -like "vssgp.*") { Get-AllGroupMembers -currentGroupDescriptor $memberDsp } # 判断为用户类型,拉取用户详情加入结果集 elseif ($memberDsp -like "aad.*" -or $memberDsp -like "usp.*") { $userDetailUri = "https://vssps.dev.azure.com/$orgName/_apis/graph/users/$memberDsp?api-version=7.1" $userDetail = Invoke-RestMethod -Uri $userDetailUri -Headers $requestHeaders -Method Get $allMemberUsers += $userDetail } } # 读取下一页令牌 $nextPageToken = $response.Headers.'X-MS-ContinuationToken' } while ($nextPageToken) } # 执行拉取 Get-AllGroupMembers -currentGroupDescriptor $targetGroupDescriptor # 导出为CSV文件,可按需调整要导出的字段 $allMemberUsers | Select-Object displayName, mailAddress, principalName, originId | Export-Csv -Path "AAD组全量成员.csv" -NoTypeInformation -Encoding UTF8
注意事项
- 个人访问令牌需要授予组织范围的Graph读取权限,不要用项目范围的令牌,否则会漏读未分配到对应项目的用户
- 如果组织开启了用户可见性限制策略,需要确认调用接口所用的身份有查看全组织用户的权限,否则只会返回权限范围内的可见用户
内容的提问来源于stack exchange,提问作者user19364865
相关产品推荐
相关产品推荐

