Exchange Online电子取证搜索迁移至Graph:预览及报告下载问题
我正在将eDiscovery搜索从Exchange Online模块迁移至Microsoft Graph,已实现以下Beta版Graph API调用:
1. 对应New-ComplianceCase的调用
body = { 'displayName': 'TestJob_{}'.format(testjob_id), 'description': 'Rest job {}'.format(testjob_id), 'externalId': externalid } case = graph_post('security/cases/ediscoveryCases', body=body)
2. 对应New-ComplianceSearch的调用
body = { 'displayName': 'Test search {}'.format(search_id), 'description': "Test search", "contentQuery": "from:{}".format(sender), 'dataSourceScopes': 'allTenantMailboxes' } search = graph_post('security/cases/ediscoveryCases/{}/searches'.format(case['id']), body=body)
3. 对应Start-ComplianceSearch的调用
startsearch = graph_post("security/cases/ediscoveryCases/{}/searches/{}/estimateStatistics".format( case['id'], search['id']), body=None)
4. 对应Get-ComplianceSearch查询状态的调用
stats = graph_get('security/cases/ediscoveryCases/{}/searches/{}/lastEstimateStatisticsOperation'.format( case['id'],search['id']))
当前存在两个待解决问题:
- 原Exchange Online模块的
New-ComplianceSearchAction -Preview预览功能,未找到对应Graph API端点,如何实现? lastEstimateStatisticsOperation接口返回的downloadUrl无法用Graph请求头下载,脚本仅支持应用凭证,如何解决?
一、实现预览功能
在Microsoft Graph Beta版中,对应New-ComplianceSearchAction -Preview的操作是调用eDiscovery搜索的preview端点,通过POST请求触发预览任务,无需请求体。
示例Python代码:
# 触发预览操作 preview_response = graph_post(f'security/cases/ediscoveryCases/{case["id"]}/searches/{search["id"]}/preview', body=None) # 查询预览状态及结果 preview_status = graph_get(f'security/cases/ediscoveryCases/{case["id"]}/searches/{search["id"]}/lastPreviewOperation')
预览任务完成后,lastPreviewOperation会返回预览结果的相关信息,包括可查看的内容条目。
二、使用应用凭证下载统计报告
lastEstimateStatisticsOperation返回的downloadUrl属于eDiscovery代理服务端点,而非标准Graph API,需直接使用应用权限获取的访问令牌发起请求,步骤如下:
确保应用权限配置正确:
为应用注册添加应用权限:Security.ReadWrite.All或SecurityEvents.Read.All,并完成管理员同意。获取应用访问令牌:
使用客户端凭证流(Client Credential Flow)获取令牌,确保令牌的受众(audience)覆盖eDiscovery服务(通用Graph令牌即可适配)。发起下载请求:
直接向downloadUrl发送GET请求,请求头携带Authorization: Bearer {access_token},示例Python代码:
import requests # 假设已通过应用凭证获取到access_token access_token = "YOUR_APP_ACCESS_TOKEN" download_url = stats["downloadUrl"] headers = { "Authorization": f"Bearer {access_token}" } response = requests.get(download_url, headers=headers) if response.status_code == 200: # 保存报告文件 with open("compliance_report.csv", "wb") as f: f.write(response.content) else: print(f"下载失败,状态码:{response.status_code}")
注意:部分区域的代理服务可能需要确保应用的IP在允许列表中,若遇到403错误,需检查IP权限或应用权限配置。
内容的提问来源于stack exchange,提问作者Haruka Shitou

