Graph API批量端点POST报错及分页获取全量结果求助
解决Graph API Batch请求的"Method not allowed"错误及分页问题
问题诊断
你遇到的"Method not allowed"错误主要来自两个容易忽略的小问题:
- AccessToken变量引用错误:获取token后,你在请求头里用了
$accesstoken,但实际Invoke-RestMethod返回的token字段是access_token,对应变量是$oauth.access_token——这会导致Authorization头无效,甚至直接被端点拒绝。 - Batch URL错误:你的
$batchUrl定义里包含未初始化的$batch变量,导致最终请求的URL变成了https://graph.microsoft.com/v1.0/(空变量拼接后丢失了$batch后缀),而Graph API的根端点不接受POST请求,自然返回Method Not Allowed。
另外,你的代码还缺少对@odata.nextLink的分页处理,无法获取超过1000条的全量用户数据,我也一起帮你补上这个逻辑。
修正后的完整代码
下面是修复了上述问题,并且添加了分页逻辑的PowerShell脚本:
# CHANGE THESE VALUES $TenantID = 'tenantid' #The Directory ID from Azure AD $ClientID = 'clientid' #The Application ID of the registered app $ClientSecret = 'secret' #The secret key of the registered app # ------------------------------------------------------ # DO NOT CHANGE THESE $body = @{grant_type="client_credentials";scope="https://graph.microsoft.com/.default";client_id=$ClientID;client_secret=$ClientSecret} $oauth = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token" -Body $body # 修复AccessToken变量引用错误 $requestHeaders = @{'Authorization'= "Bearer $($oauth.access_token)"; "Content-Type" = "application/json"} # 修复Batch URL错误(用反引号转义$batch,避免PowerShell解析为变量) $batchUrl = "https://graph.microsoft.com/v1.0/`$batch" # ------------------------------------------------------ # 定义SKU ID对应的请求模板,方便维护 $skuRequests = @( @{SkuId = "19ec0d23-8335-4cbd-94ac-6050e30712fa"; Name = "E2"}, @{SkuId = "05e9a617-0261-4cee-bb44-138d3ef5d965"; Name = "E3"}, @{SkuId = "06ebc4ee-1bb5-47dd-8120-11324bc54e06"; Name = "E5"} ) # 存储所有请求的全量结果,按SKU分类 $allResults = @{} foreach ($sku in $skuRequests) { $allResults[$sku.Name] = @() # 初始化第一个请求的相对路径,设置$top=999(Graph API单页最大返回量) $nextLink = "/users?`$select=userprincipalname,displayname,extension_335d4df9847945fbaa472c8b8fbb5d75_employeeNumber,employeeid,department,accountenabled,signInActivity&`$filter=assignedLicenses/any(x:x/skuId+eq+$($sku.SkuId))&`$top=999" while ($nextLink) { $myBatchRequests = @() [int]$requestID = 0 $requestID++ # 处理nextLink:如果是后续分页链接,去掉开头的?(Batch API要求相对路径) $requestUrl = if ($nextLink.StartsWith('?')) { $nextLink.Substring(1) } else { $nextLink } # 添加当前页请求到batch $myRequest = [pscustomobject][ordered]@{ url = $requestUrl id = $requestID method = "GET" } $myBatchRequests += $myRequest $allBatchRequests = [pscustomobject][ordered]@{ requests = $myBatchRequests } $batchBody = $allBatchRequests | ConvertTo-Json -Depth 10 try { $batchResponse = Invoke-RestMethod -Method POST -Uri $batchUrl -Body $batchBody -Headers $requestHeaders # 提取当前页的用户数据 $pageResults = $batchResponse.responses[0].body.value $allResults[$sku.Name] += $pageResults # 更新nextLink:去掉根URL,只保留相对路径供下一次Batch请求使用 $nextLink = $batchResponse.responses[0].body.'@odata.nextLink' -replace '^https://graph.microsoft.com/v1.0', '' } catch { Write-Error "处理$($sku.Name)请求时出错: $_" $nextLink = $null # 出错后终止当前SKU的分页循环 } } } # 输出全量结果 $allResults
关键修复与说明
- 修复Authorization头:将
$($accesstoken)改为$($oauth.access_token),确保携带有效的访问令牌。 - 修复Batch URL:用反引号
转义$batch,避免PowerShell将其解析为变量,正确的URL是https://graph.microsoft.com/v1.0/$batch`。 - 分页处理逻辑:
- 对每个SKU的请求循环检查
@odata.nextLink,直到没有下一页为止。 - 将nextLink转换为相对路径(去掉根URL),符合Batch API的请求格式要求。
- 每页请求使用
$top=999(Graph API单页最大返回量),减少总请求次数。
- 对每个SKU的请求循环检查
- 结果存储:用哈希表按SKU名称分类存储全量用户数据,方便后续筛选或导出。
额外注意事项
- 确保你的Azure AD应用已授予
User.Read.All的应用权限(客户端凭证流需要应用权限而非委派权限),并且已完成管理员同意。 - 如果遇到Graph API速率限制错误,可以在循环中添加
Start-Sleep -Seconds 1延迟,避免触发限流。
内容的提问来源于stack exchange,提问作者jpbcx43
相关产品推荐
相关产品推荐

