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

如何通过PowerShell调用MS Graph API获取合作伙伴租户用户与设备

跨合作伙伴租户批量查询用户、设备数据的实现方案

问题根因

之前的脚本无法跨租户访问的核心原因有两个:

  • 令牌获取逻辑错误:脚本中传入自有合作伙伴租户ID获取的令牌,仅具备访问自身租户资源的权限,无法直接访问委托管理的客户租户资源
  • 权限配置链路不完整:仅在自有Azure AD中给应用注册配置Graph权限不够,必须将应用关联到合作伙伴中心的CSP/委派管理体系,完成跨租户权限的全局同意,才可以覆盖所有关联客户租户。

前置配置要求

  • 应用注册需要关联到你的合作伙伴中心账号,不能仅在自有Azure AD中独立创建
  • 为应用授予以下Microsoft Graph应用程序权限(不要选委派权限),并在合作伙伴中心为所有关联GDAP关系的租户完成管理员同意,无需单独登录每个客户租户做授权:
    • Directory.Read.All:用于拉取所有关联客户租户列表
    • User.Read.All:用于读取客户租户用户数据
    • Device.Read.All:用于读取客户租户设备数据
  • 确保应用被加入到对应GDAP关系配置的授权安全组中,否则会出现部分租户无权限访问的问题。

可直接运行的PowerShell脚本

# 首次运行先安装依赖模块,已安装可跳过
Install-Module MSAL.PS, Microsoft.Graph.Authentication -Scope CurrentUser -Force

Import-Module MSAL.PS

# 替换为你自己的配置参数
$ClientId = "应用注册的客户端ID"
$PartnerTenantId = "你的合作伙伴租户ID"
$ClientSecret = "应用注册的客户端密钥" | ConvertTo-SecureString -AsPlainText -Force
$GraphScope = "https://graph.microsoft.com/.default"
$OutputPath = "C:\Temp\PartnerTenantDataExport.csv" # 结果导出路径

# 1. 获取合作伙伴租户令牌,拉取所有关联客户租户列表
$partnerToken = Get-MsalToken -ClientId $ClientId `
                              -ClientSecret $ClientSecret `
                              -TenantId $PartnerTenantId `
                              -Scope $GraphScope

$customerList = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/contracts?`$select=customerId,displayName,defaultDomainName" `
                                  -Headers @{Authorization = "Bearer $($partnerToken.AccessToken)"} `
                                  -Method Get

$result = @()
# 2. 遍历所有客户租户,拉取对应用户、设备数据
foreach ($customer in $customerList.value) {
    Write-Host "正在处理租户: $($customer.displayName) | ID: $($customer.customerId)"
    
    # 针对当前客户租户申请访问令牌,无需客户租户侧单独授权
    $customerToken = Get-MsalToken -ClientId $ClientId `
                                   -ClientSecret $ClientSecret `
                                   -TenantId $customer.customerId `
                                   -Scope $GraphScope
    $authHeader = @{Authorization = "Bearer $($customerToken.AccessToken)"}

    # 拉取用户数据(可自行调整需要返回的字段)
    $users = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users?`$select=id,displayName,userPrincipalName,accountEnabled,lastSignInDateTime" `
                               -Headers $authHeader `
                               -Method Get
    
    # 拉取设备数据(可自行调整需要返回的字段)
    $devices = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/devices?`$select=id,displayName,deviceId,operatingSystem,accountEnabled,lastLogonDateTime" `
                                 -Headers $authHeader `
                                 -Method Get

    $result += [PSCustomObject]@{
        TenantName = $customer.displayName
        TenantId = $customer.customerId
        DefaultDomain = $customer.defaultDomainName
        TotalUserCount = $users.value.Count
        TotalDeviceCount = $devices.value.Count
        UserList = $users.value | ConvertTo-Json -Compress
        DeviceList = $devices.value | ConvertTo-Json -Compress
    }
}

# 导出结果到CSV
$result | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
Write-Host "查询完成,结果已导出到: $OutputPath"

注意事项

  • 不建议使用Connect-MgGraph做跨租户切换,模块本身的上下文缓存容易出现权限错乱,直接携带对应租户的令牌调用Graph接口稳定性更高
  • 如果调用contracts接口返回403,优先检查应用是否已经关联到合作伙伴中心、是否授予了Directory.Read.All应用权限并完成管理员同意
  • 如果单个客户租户访问返回403,优先检查对应租户的GDAP关系是否处于活跃状态、应用是否在GDAP授权的安全组范围内
  • 客户租户数量较多时,可以在循环中加200-500ms的请求间隔,避免触发Graph接口限流

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:27:39