当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 使用图形 API 编写邮箱清理脚本

作者:精品下载站 日期:2024-12-14 04:06:34 浏览:13 分类:玩电脑

使用图形 API 编写邮箱清理脚本


用于从用户和共享邮箱中删除碎片的 PowerShell 脚本

有时,需要从用户邮箱中删除项目。也许有人在电子邮件中共享了他们不应该共享的信息,或者某些充满恶意软件的有害邮件已渗透到 Exchange Online Protection 并到达收件箱。您可以要求用户手动删除有问题的邮件,但如果管理员介入并删除问题,通常会更高效。

在本地环境中,Search-Mailbox cmdlet 可以完成这项工作。 Microsoft 热衷于采用跨多种工作负载的合规性功能,有时会带来不幸的后果,他们决定在 2020 年 7 月弃用 Search-Mailbox,从而删除了一个有价值的工具。在撰写本文时,搜索邮箱仍然有效,但由于其不受支持的性质,许多人推迟使用它。

Microsoft 建议的搜索邮箱替代方案是使用清除操作和合规性搜索来删除 Exchange Online 邮箱中的项目。此方法使用合规性搜索来查找匹配的项目,然后执行清除操作以删除这些项目。它可以工作,但处理速度很慢,并且随着时间的推移似乎会变得更慢。上周,我花了一些时间研究我在 2019 年编写的示例脚本,以展示如何循环遍历合规性搜索结果以清除项目,但性能非常糟糕。如果只是为了了解如何使用图形 API 请求解决问题,那么在不使用搜索邮箱或合规性搜索的情况下研究脚本来完成这项工作似乎是一件好事。

制定脚本

该脚本的基本轮廓是:

  • 收集搜索查询的参数。
  • 找到要搜索的邮箱。
  • 针对邮箱运行搜索查询。由于我们使用的是 Graph API 请求,因此需要一个注册的 Azure AD 应用程序并同意使用 Mail.ReadWrite 应用程序权限。读取消息数据需要读取访问权限。从邮箱中删除邮件需要写访问权限。
  • 将操作应用于查询找到的消息。我想要报告消息和删除消息的选项。

现在我们知道必须采取哪些步骤,让我们检查一些细节。

第一次尝试

脚本的原始版本非常简单。我使用图形消息资源类型从邮箱中检索消息,并使用过滤器来查找所需的消息。应用过滤器可查找完全匹配的消息。例如,此请求查找主题为“Project Ankara To Do Items”的所有消息:

https://graph.microsoft.com/v1.0/users/aff4cd58-1bb8-4899-94de-795f656b4a18/messages?$select=id,receivedDateTime,subject,from&$filter=subject eq 'Project Ankara To Do Items'

选择请求成功,但仅返回有限的一组(因为完全匹配),这与 Search-Mailbox 或合规性搜索检索到的内容不同。

在深入讨论之前,我要强调一下,在计算 Graph API 请求的详细信息时,Graph Explorer 是一个必不可少的工具。您可以将脚本计算出的 URI 输入到 Graph Explorer 中,看看会发生什么。一旦请求在 Graph Explorer 中起作用,您就知道它将在脚本中起作用。

过滤与搜索

然后我转向 Microsoft Search API,这可能是我应该开始的地方。搜索 API 使用关键字查询语言 (KQL) 查询来扫描邮箱,以根据其元数据(属性)或内容(邮件正文和附件)查找匹配的邮件。尽管客户端的实现有所不同,但 Outlook 客户端使用此 API 进行搜索。

最初的挑战是编写合适的 KQL 查询。如果您习惯于为合规性搜索(或搜索邮箱)编写搜索条件,那么您就会知道 KQL 支持一组特定属性来搜索电子邮件项目。该脚本接受一系列参数,包括消息主题、关键字、日期范围和发件人地址,它会处理这些参数来创建查询。

# Prepare search filter
$SearchFilter = "subject:$MessageSubject" 

If ($SenderAddress) {
  $SearchFilter = $SearchFilter + " AND from:$SenderAddress" }

If ($StartDate) {
   $StartDateFilter = (Get-Date $StartDate).toString('yyyy-MM-dd') }
 If (($StartDateFilter) -and (!($EndDate))) { # if we have a start date but no end date, set to today's date
   $EndDate = Get-Date }
 If ($EndDate) {
   $EndDateFilter = (Get-Date $EndDate).toString('yyyy-MM-dd') }

If (($StartDateFilter) -and ($EndDateFilter)) {
  $SearchFilter = $SearchFilter + " AND received>=$StartDateFilter AND received<=$EndDateFilter" }

If ($SearchQuery) {
  $SearchFilter = $SearchFilter + " AND '" + $SearchQuery + "'" }

以下是组装的 KQL 查询的样子。此查询查找 Kim Akers 在 2022 年 1 月 1 日至 2022 年 8 月 1 日期间发送的邮件主题中任意位置包含“更新到 Office 365 Book”的邮件:

subject:Update to Office 365 Book AND from:[email protected] AND received>=2022-01-01 AND received<=2022-08-01

另一个示例搜索每日 Viva Briefing 电子邮件

subject:Your daily briefing AND from:[email protected] AND received>=2021-01-01 AND received<=2022-08-02 AND 'Better with Microsoft Viva'

为了执行搜索,我们编写一个如下所示的 Graph API 请求。您可以看到 KQL 查询是如何传递的,以及我们告诉图表为每条消息返回一组属性。

https://graph.microsoft.com/v1.0/users/aff4cd58-1bb8-4899-94de-795f656b4a18/mailfolders//messages?$search="subject:Update to Office 365 Book AND from:[email protected] AND received>=2022-01-01 AND received<=2022-08-01"&$select=id,parentfolderid,receivedDateTime,subject,from

搜索目标文件夹

这将我带到目标文件夹。我的脚本允许用户搜索邮箱中的单个文件夹或所有文件夹。如果搜索处理所有文件夹,则结果就像在 Outlook 桌面中搜索生成的结果一样,只有一个问题。搜索不会扫描“已删除邮件”文件夹中的项目。这取决于不同客户端中搜索的实现。 Outlook 桌面版不会搜索“已删除邮件”文件夹,除非您明确搜索该文件夹,但 OWA 会搜索该文件夹。两个客户端都使用 Microsoft 搜索 API 功能,首先显示搜索找到的三个最相关的项目,而我想要一个简单的列表。 Search-Mailbox cmdlet 查找所有用户可见的文件夹以及“可恢复项目”结构中的文件夹中的项目。

解决方案很简单:对“已删除邮件”文件夹进行一次搜索,对所有其他文件夹进行另一次搜索,然后合并结果。也许有一种更好的方法来搜索所有用户可见的文件夹,但我找不到,而且我的解决方法很有效。

目前,Graph API 无法访问存档邮箱。如果需要此功能,您需要使用 Exchange Web 服务编写它。

文件夹名称

搜索找到的消息返回的信息如下所示:

@odata.etag      : W/"FgAAAA=="
id               : AAMkADAzNzBmMzU0LTI3NTItNDQzNy04NzhkLWNmMGU1MzEwYThkNABGAAAAAAB_7ILpFNx8TrktaK8VYWerBwBe9CuwLc2fTK7W46L1SAp9AAAA2lHKAAA3tTkMTDKYRI6zB9VW59QNAASRem3ZAAA=
receivedDateTime : 2022-01-08T00:21:02Z
subject          : Office 365 Roadmap Updated: 2022-01-08
parentFolderId   : AAMkADAzNzBmMzU0LTI3NTItNDQzNy04NzhkLWNmMGU1MzEwYThkNAAuAAAAAAB_7ILpFNx8TrktaK8VYWerAQBe9CuwLc2fTK7W46L1SAp9AAAA2lHKAAA=

消息所在的文件夹存储在 parentFolderId 中。该值对于计算机来说非常有意义,但对于人类来说却没有多大好处。我需要一种方法将这些值解析为有意义的内容,例如收件箱。已删除的项目或已发送的项目。为了解释标识符,我使用 List mailFolders API 来获取邮箱内的文件夹集。返回的数据包括文件夹标识符和显示名称,因此我可以构建一个以文件夹标识符为键的哈希表以用作查找。

处理子文件夹

许多邮箱都有简单的一级文件夹结构,因此从邮箱根目录获取文件夹列表就足够了。其他邮箱具有嵌套文件夹,如图 1 所示。

[玩转系统] 使用图形 API 编写邮箱清理脚本

List mailFolders API 返回的信息包括子文件夹的计数,因此很容易知道哪些文件夹包含文件夹。为了构建哈希表以包含文件夹标识符和嵌套文件夹的显示名称,该脚本会向下迭代四层以查找并处理它可以找到的任何子文件夹。奇怪的是,List mailFolders API 没有限定符来指示 Graph 获取邮箱中的所有文件夹,但这就是事情的工作方式。

举报或删除

希望当脚本运行时,它能在目标邮箱中找到一些邮件(图 2)。

[玩转系统] 使用图形 API 编写邮箱清理脚本

参数确定脚本随后是报告消息还是删除(并报告)消息。要删除消息,脚本会构建一个包含消息标识符的 URI,然后发出删除请求以删除该消息。 URI 和 API 请求如下所示:

https://graph.microsoft.com/v1.0/users/aff4cd58-1bb8-4899-94de-795f656b4a18/messages/AAMkADAzNzBmMzU0LTI3NTItNDQzNy04NzhkLWNmMGU1MzEwYThkNABGAAAAAAB_7ILpFNx8TrktaK8VYWerBwBe9CuwLc2fTK7W46L1SAp9AAAA2lHKAAA3tTkMTDKYRI6zB9VW59QNAASRem3ZAAA=
$Status = Invoke-RestMethod $Uri -Method 'Delete' -Headers $Headers

已删除的邮件将进入可恢复项目的“删除”子文件夹。用户可以从此文件夹恢复项目。如果您希望它们无法恢复项目,您可以将邮件移至隐藏文件夹(如可恢复项目中的清除子文件夹)。

一切准备好删除(测试后)

您可以从 GitHub 下载该脚本的最新版本。在造成任何实际损坏之前,请对其进行彻底测试。不要陷入过去许多人在不知道自己在做什么的情况下运行删除电子邮件的实用程序的陷阱。特别要注意 KQL 查询中使用的关键字,因为它们可能会找到您不期望的项目。

我通常在报告模式下运行该脚本,以查看发现了哪些消息(图 3),然后再让它删除任何内容。尽管用户可以恢复已删除的项目,但管理员最好不要删除他们不需要的项目。随意生活在边缘并删除消息而不检查这是否是你喜欢做的事情。

[玩转系统] 使用图形 API 编写邮箱清理脚本

如果您发现错误,请在 GitHub 中提交问题。更好的是,修复错误并告诉我你做了什么。我感谢您能提供的任何帮助!

Microsoft 365 杀伤链和攻击路径管理

有效的网络安全策略需要对攻击如何展开有清晰、全面的了解。阅读本白皮书,获取保卫您的组织所需的专家见解!

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯