PowerShell中如何设置GraphAPI令牌以标记Office365邮件为已读?
问题描述
我用PowerShell从Office 365获取邮件,当前令牌获取代码能正常读取邮件,但调用自定义函数MarkSingleEmailAsRead标记特定邮件为已读时,返回错误:
Error Message: The remote server returned an error: (401) Unauthorized.
令牌获取代码
if ($token -ne $null) { $body = @{ client_id = $clientID scope = "https://graph.microsoft.com/.default" client_secret = $clientSecret grant_type = "client_credentials" } $URL = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" try { $tokenRequest = Invoke-WebRequest -Method Post -Uri $URL -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing -ErrorAction Stop } catch { Write-Host "Unable to obtain access token, aborting..." Write-Host "Error Message: $($Error[0])" return } $token = ($tokenRequest.Content | ConvertFrom-Json).access_token #Write-Host("Got Token=$token") } $authHeader1 = @{ 'Content-Type'='application\json' 'Authorization'="Bearer $token" }
标记邮件为已读的函数代码
function MarkSingleEmailAsRead ($emailId, $headers) { <# This is what we need to post as an example POST https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/messages/markRead Content-Type: application/json { "messageIds": ["MC172851", "MC167983"] } #> $graphApiPostUrl = "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/messages/markRead" $body = @{ "messageIds" = @($emailId) } Write-Host "Headers=" $headers | ConvertTo-Json | Write-Host Write-Host "Body=" $body | ConvertTo-Json | Write-Host try { $results = Invoke-WebRequest -Method Post -Uri $graphApiPostUrl -ContentType "application/x-www-form-urlencoded" -Body $body -Headers $headers -UseBasicParsing -ErrorAction Stop } catch { Write-Host "Error Message: $($Error[0])" return } }
我想用同一令牌同时实现邮件读取和更新(标记为已读),想知道如何修改scope参数(当前为scope = "https://graph.microsoft.com/.default"),之前尝试两种配置都无效,同时不确定是否需要在Azure端配置更新权限。
解决方案
1. Azure AD应用权限配置(核心)
你用的是客户端凭证模式(client_credentials),这种模式下令牌的权限完全依赖于Azure AD应用注册中配置的应用权限(而非委派权限):
- 登录Azure门户,找到你的应用注册,进入「API权限」页面
- 点击「添加权限」→ 选择「Microsoft Graph」→ 「应用权限」
- 添加以下权限(必须由租户管理员授予同意):
ServiceAnnouncementMessage.ReadWrite.All:对应标记服务公告邮件为已读的权限- 保留原有的读取权限(比如
ServiceAnnouncementMessage.Read.All)
- 添加完成后,点击「授予管理员同意」,确保权限生效
2. Scope参数无需修改
客户端凭证模式下,scope = "https://graph.microsoft.com/.default"是正确写法,它会自动包含所有已配置并授予同意的应用权限,不需要手动指定单个scope。
3. 修复函数中的请求错误
你的MarkSingleEmailAsRead函数存在两个关键错误,会导致请求失败:
- Content-Type错误:Graph API要求该接口的Content-Type为
application/json,而非application/x-www-form-urlencoded - Body未转成JSON字符串:直接传入PowerShell哈希表作为Body,需要先转换为JSON格式
修改后的函数代码:
function MarkSingleEmailAsRead ($emailId, $headers) { $graphApiPostUrl = "https://graph.microsoft.com/v1.0/admin/serviceAnnouncement/messages/markRead" $body = @{ "messageIds" = @($emailId) } | ConvertTo-Json Write-Host "Headers=" $headers | ConvertTo-Json | Write-Host Write-Host "Body=" $body | Write-Host try { $results = Invoke-WebRequest -Method Post -Uri $graphApiPostUrl -ContentType "application/json" -Body $body -Headers $headers -UseBasicParsing -ErrorAction Stop } catch { Write-Host "Error Message: $($Error[0])" return } }
4. 验证步骤
- 重新获取令牌(确保权限更新已同步)
- 调用修改后的函数,检查是否能成功标记邮件为已读
内容的提问来源于stack exchange,提问作者NealWalters
相关产品推荐
相关产品推荐

