通过 PowerShell 访问 MS Graph API 的权限

Permissions to access to MS Graph API via PowerShell

问题

我正在尝试编写 PowerShell 脚本以通过 MS Graph API /reports/credentialUserRegistrationDetails 获取报告数据。 当我使用 Graph Explorer 它工作得很好,只要我在修改权限(预览)选项卡上启用 Reports.Read.All

但是,当我尝试使用我的脚本执行此操作时,我收到错误 "Calling principal does not have required MSGraph permissions Reports.Read.All"

在我所有的搜索中,我只能找到如何为应用分配权限。 有什么方法可以让我从我的脚本中做到这一点吗?


我的脚本

$azContext = Get-AzContext
$token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate(
    $azContext.Account,
    $azContext.Environment,
    $azContext.Tenant.Id,
    $null,
    [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never,
    $null,
    "https://graph.microsoft.com"
)

$params = @{
    Method  = "GET"
    Uri     = "https://graph.microsoft.com/beta/reports/credentialUserRegistrationDetails"
    Headers = @{
        Authorization  = "Bearer $($token.AccessToken)"
        "Content-Type" = "application/json"
    }
}
Invoke-RestMethod @params

回应

{
  "error": {
    "code":"Authentication_MSGraphPermissionMissing",
    "message":"Calling principal does not have required MSGraph permissions Reports.Read.All",
    "innerError": {
      "date":"2021-10-19T01:18:36",
       "request-id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
       "client-request-id":"6b8cc3a3-b93b-44bb-b1d4-190c618aa52a"
    }
  }
}

When I use Graph Explorer it works just fine, as long as I enable Reports.Read.All on the Modify permissions (Preview) tab.

这是因为 Microsoft Graph Explorer 是 Microsoft 的企业应用程序,它存在于每个 Azure AD 租户上,您只需要通过提供所需的权限来登录和使用它。

但是当您编写 运行 您的 Powershell 脚本时,它使用 Microsoft Azure Powershell 。您可以通过检查 JWT Token 中收到的 access_token 来验证它。因此,您需要向您的租户中具有 appid 的同一应用程序提供 Reports.Read.All API 权限:1950a258-227b-4e31-a9cf-717495945fc2 在 Enterprise Application >> Permissions 中授予管理员同意。提供所需的权限后,它才会起作用。


另一种方法是创建应用程序注册,为其创建客户端密码,然后提供 Reports.Read.All API 权限并使用以下脚本:

$TenantName = "tenantname.onmicrosoft.com"
$clientID = "d344e3xxx-xxx-xxxx-xxxx-9c861d363244" # app registration clientId
$clientSecret = "fNc7Q~UNHBgv_xxxxxxxxxxxxxxxxxxxxxx-PD"
$Scope = "https://graph.microsoft.com/.default"
 
$Body = @{
    Grant_Type = "client_credentials"
    Scope = $Scope
    client_Id = $clientID
    Client_Secret = $clientSecret
}
$authUri = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
  
$TokenResponse = Invoke-RestMethod -Uri $authUri -Method POST -Body $Body

$Headers = @{
        "Authorization" = "Bearer $($TokenResponse.access_token)"
        "Content-type"  = "application/json"
    }
$apiUri = "https://graph.microsoft.com/beta/reports/credentialUserRegistrationDetails"
$response = Invoke-RestMethod -Headers $Headers -Uri $apiUri -Method GET
 
$response.value

输出:

注意:在某些租户中,Microsoft Azure PowerShell 可能无法从门户中看到,因此在这种情况下,请使用上述解决方案,它会更容易。

对于授权代码流程,尝试这样的事情-

#region Auth1
#With User Interaction for Delegated Permission
Add-Type -AssemblyName System.Web

Function Get-AuthCode {
    Add-Type -AssemblyName System.Windows.Forms

    $form = New-Object -TypeName System.Windows.Forms.Form -Property @{Width = 440; Height = 640 }
    $web = New-Object -TypeName System.Windows.Forms.WebBrowser -Property @{Width = 420; Height = 600; Url = ($url -f ($Scope -join "%20")) }

    $DocComp = {
        $Global:uri = $web.Url.AbsoluteUri        
        if ($Global:uri -match "error=[^&]*|code=[^&]*") { $form.Close() }
    }
    $web.ScriptErrorsSuppressed = $true
    $web.Add_DocumentCompleted($DocComp)
    $form.Controls.Add($web)
    $form.Add_Shown( { $form.Activate() })
    $form.ShowDialog() | Out-Null

    $queryOutput = [System.Web.HttpUtility]::ParseQueryString($web.Url.Query)
    $output = @{}
    foreach ($key in $queryOutput.Keys) {
        $output["$key"] = $queryOutput[$key]
    }

    #$output
}

Get-AuthCode
#Extract Access token from the returned URI
$regex = '(?<=code=)(.*)(?=&)'
$authCode = ($uri | Select-string -pattern $regex).Matches[0].Value

Write-output "Received an authCode, $authCode"

$tokenBody = @{  
    Grant_Type    = "authorization_code"  
    Scope         = "https://graph.microsoft.com/.default"  
    Client_Id     = $clientId  
    Client_Secret = $clientSecret
    redirect_uri  = $redirectUri
    code          = $authCode
    ressource     = $resource
}   

$tokenResponse = Invoke-RestMethod https://login.microsoftonline.com/common/oauth2/token -Method Post -ContentType "application/x-www-form-urlencoded" -Body $tokenBody -ErrorAction STOP

#endregion Auth1

对于委派权限,使用类似下面的内容 -

$tokenBody = @{  
    Grant_Type = "password"  
    Scope      = "user.read%20openid%20profile%20offline_access"  
    Client_Id  = $clientId  
    username   =  $User
    password   = $pw
    resource  = $resource
}   

$tokenResponse = Invoke-RestMethod https://login.microsoftonline.com/common/oauth2/token -Method Post -ContentType "application/x-www-form-urlencoded" -Body $tokenBody -ErrorAction STOP

#endregion Auth2

对于应用程序权限(使用客户端凭证流)使用类似这样的东西

$tokenBody = @{  
    Grant_Type    = "client_credentials"  
    Scope         = "https://graph.microsoft.com/.default"  
    Client_Id     = $clientId  
    Client_Secret = $clientSecret  
}   

$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$Tenantid/oauth2/v2.0/token" -Method POST -Body $tokenBody  


#endregion Auth3

无论您选择何种方法,tokenRepsonse 变量都保存着我们针对 Microsoft GRAPH API.

进行查询的密钥

我们想要租户中所有团队的列表,因此这需要适当的应用程序许可。因此,例如 - 我们的 Powershell 获取所有团队的完整列​​表如下所示 -

$headers = @{
        "Authorization" = "Bearer $($tokenResponse.access_token)"
        "Content-type"  = "application/json"
    }

$URL = "https://graph.microsoft.com/beta/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')"  
$AllTeams = (Invoke-RestMethod -Headers $headers -Uri $URL -Method GET).value 

谢谢。

我终于放弃了使用 REST API,开始使用 Microsoft.Graph PowerShell 模块。我发现文档非常稀疏,但至少它可以满足我的需要。 :)

Import-Module "Microsoft.Graph.Identity.Signins"
Import-Module "Microsoft.Graph.Users"
Import-Module "Microsoft.Graph.Groups"
Connect-MgGraph -TenantId $TenantId  -Scopes "Directory.Read.All", "UserAuthenticationMethod.Read.All" -ForceRefresh
Select-MgProfile -Name "beta"

$report = Get-MgReportCredentialUserRegistrationDetail