如何使用PowerShell在Azure AD中通过用户名密码生成委派令牌?
解决Azure AD应用生成委派令牌的问题
核心修改点说明
你的原脚本创建的是应用级权限(客户端凭据令牌),要生成代表用户的委派令牌,需要从权限类型、应用配置、令牌请求三个部分调整:
1. 替换应用权限为委派类型
原脚本中Add-AzADAppPermission用了-Type Role,这是添加应用级权限。要改成委派权限,需将-Type设为Scope,同时注意委派权限的ID和应用权限不同:
- Mail.Send的委派权限ID:
e1fe6dd8-ba31-4d61-89e7-88639da4683d - 原脚本里的
b633e1c5-b582-4048-a93e-9f11b44c7e96是应用级权限ID,不能混用
2. 配置应用支持用户名密码登录
要通过用户名密码流(ROPC)获取委派令牌,需开启应用的公共客户端访问:
Set-AzADApplication -ObjectId $app.Id -AllowPublicClient $true
3. 完成管理员同意(可选但必要)
如果要让所有用户无需手动授权就能使用,需执行管理员同意委派权限的操作,替换原脚本里的New-AzADServicePrincipalAppRoleAssignment:
New-AzADServicePrincipalOAuth2PermissionGrant -ClientId $sp.Id -ResourceId $graphSp.Id -Scope "Mail.Send" -ConsentType "AllPrincipals"
完整修改后的脚本
Connect-AzAccount $appName = "MyTestingApp" $app = New-AzADApplication -DisplayName $appName # 开启应用支持公共客户端(适配ROPC流) Set-AzADApplication -ObjectId $app.Id -AllowPublicClient $true $secret = New-AzADAppCredential -ApplicationId $app.AppId -EndDate (Get-Date).AddYears(1) Start-Sleep -Seconds 30 $graphApiId = '00000003-0000-0000-c000-000000000000' # 使用Mail.Send的委派权限ID $mailSendDelegatedId = 'e1fe6dd8-ba31-4d61-89e7-88639da4683d' $graphSp = Get-AzADServicePrincipal -Filter "appId eq '$graphApiId'" # 添加委派权限(Type设为Scope) Add-AzADAppPermission -ObjectId $app.Id -ApiId $graphApiId -PermissionId $mailSendDelegatedId -Type Scope Start-Sleep -Seconds 30 $sp = New-AzADServicePrincipal -ApplicationId $app.AppId # 管理员同意该委派权限,允许所有用户使用 New-AzADServicePrincipalOAuth2PermissionGrant -ClientId $sp.Id -ResourceId $graphSp.Id -Scope "Mail.Send" -ConsentType "AllPrincipals" Start-Sleep -Seconds 30 # 替换为目标用户的凭据 $username = "user@yourtenant.onmicrosoft.com" $password = ConvertTo-SecureString "用户密码" -AsPlainText -Force $tenantId = (Get-AzContext).Tenant.Id $clientId = $app.AppId $clientSecret = $secret.SecretText $tokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" # 使用ROPC授权类型生成委派令牌 $body = @{ client_id = $clientId client_secret = $clientSecret scope = "https://graph.microsoft.com/Mail.Send offline_access" grant_type = "password" username = $username password = $password.GetNetworkCredential().Password } $response = Invoke-RestMethod -Method Post -Uri $tokenUrl -ContentType "application/x-www-form-urlencoded" -Body $body $token = $response.access_token $token
注意事项
- ROPC流不支持开启MFA的用户,仅适合测试场景,生产环境建议用授权码流
- 若不需要管理员全局同意,可省略
New-AzADServicePrincipalOAuth2PermissionGrant,但首次使用需要用户手动授权(ROPC流下可能报错,建议还是做管理员同意)
内容的提问来源于stack exchange,提问作者user12072310




