安全性、合规性和审核是 IT 管理员的首要任务。 Microsoft 365 具有多种内置功能,可帮助组织管理安全性、合规性和审核。 具体来说,统一审核日志记录可以帮助调查安全事件和合规性问题。 可以使用以下方法检索审核日志:
- Office 365 管理活动 API
- Microsoft Purview 门户中的审核日志搜索工具
- Exchange Online PowerShell 中的 Search-UnifiedAuditLog cmdle
如果需要定期检索审核日志,请考虑使用 Office 365 管理活动 API 的解决方案。 它为大型组织提供了可伸缩性和性能,可以持续检索数百万条审核记录。 使用 Microsoft Purview 门户中的审核日志搜索工具是快速查找在较短时间范围内发生的特定作的审核记录的好方法。 在审核日志搜索工具中使用较长的时间范围(尤其是对于大型组织),可能会返回过多记录,无法轻松管理或导出。
当需要手动检索特定调查或事件的审核数据时,尤其是对于较大组织中的较长日期范围,使用 Search-UnifiedAuditLog cmdlet 可能是最佳选择。 本文包含使用 cmdlet 的 PowerShell 脚本。 每次运行 cmdlet 时,脚本可以检索 50,000 条审核记录,然后将其导出到 CSV 文件。 可以使用 Excel 中的Power Query来设置文件的格式,以帮助审阅。 使用本文中的脚本还可以最大程度地减少服务中大型审核日志搜索超时的可能性。
运行此脚本之前
必须启用审核日志记录,组织才能成功使用该脚本返回审核记录。 Microsoft 365 和 Office 365 企业版组织默认已打开审核日志搜索。 若要验证是否为组织启用了审核日志搜索,请在 Exchange Online PowerShell 中运行以下命令:
Get-AdminAuditLogConfig | FL UnifiedAuditLogIngestionEnabledUnifiedAuditLogestionEnabled 属性的
True值表明已打开审核日志搜索。必须在 Exchange Online 中为用户分配“仅查看审核日志”或“审核日志”角色,才能成功运行脚本。 默认情况下,这些角色是在 Exchange 管理中心中的“权限”页上被分配给“合规性管理”和“组织管理”角色组。
脚本可能需要很长时间才能完成。 运行所需的时长取决于配置脚本以为其检索审核记录的日期范围和时间间隔大小。 日期范围越大,间隔越短,运行时间越长。 请参阅步骤 2 中的表格,了解有关日期范围和间隔的信息。
本文中提供的示例脚本在任何 Microsoft 标准支持程序或服务下都不受支持。 示例脚本按 原样 提供,不提供任何形式的保证。 Microsoft 进一步拒绝所有默示保证,包括但不限于针对特定用途的适销性或适用性的任何默示保证。 由于示例脚本及文档的使用或性能所引起的全部风险均由你承担。 在任何情况下,对于由于使用或者无法使用示例脚本或文档所引起的任何损失(包括但不限于商业利润损失、业务中断、商业信息丢失或者其他经济损失),Microsoft、其作者或者参与创建、制作或交付脚本的任何人概不负责,即使 Microsoft 已被告知可能会出现此类损失。
步骤 1:连接到 Exchange Online PowerShell
首先,连接到 Exchange Online PowerShell。 可以使用新式身份验证或多重身份验证 (MFA) 进行连接。 有关分步说明,请参阅连接 Exchange Online PowerShell。
步骤 2:修改并运行脚本以检索审核记录
连接到 Exchange Online PowerShell 后,请创建、修改并运行脚本以检索审核数据。 审核日志搜索脚本中的前七行包含以下变量,可以对其进行修改以配置搜索。 请参阅步骤 2 中的表格,了解这些变量的说明。
使用 ps1 文件名后缀将以下文本保存到 Windows PowerShell 脚本。 例如,SearchAuditLog.ps1。
#Modify the values for the following variables to configure the audit log search. $logFile = "d:\AuditLogSearch\AuditLogSearchLog.txt" $outputFile = "d:\AuditLogSearch\AuditLogRecords.csv" [DateTime]$start = [DateTime]::UtcNow.AddDays(-1) [DateTime]$end = [DateTime]::UtcNow $record = "AzureActiveDirectory" $resultSize = 5000 $intervalMinutes = 60 #Start script [DateTime]$currentStart = $start [DateTime]$currentEnd = $end Function Write-LogFile ([String]$Message) { $final = [DateTime]::Now.ToUniversalTime().ToString("s") + ":" + $Message $final | Out-File $logFile -Append } Write-LogFile "BEGIN: Retrieving audit records between $($start) and $($end), RecordType=$record, PageSize=$resultSize." Write-Host "Retrieving audit records for the date range between $($start) and $($end), RecordType=$record, ResultsSize=$resultSize" $totalCount = 0 while ($true) { $currentEnd = $currentStart.AddMinutes($intervalMinutes) if ($currentEnd -gt $end) { $currentEnd = $end } if ($currentStart -eq $currentEnd) { break } $sessionID = [Guid]::NewGuid().ToString() + "_" + "ExtractLogs" + (Get-Date).ToString("yyyyMMddHHmmssfff") Write-LogFile "INFO: Retrieving audit records for activities performed between $($currentStart) and $($currentEnd)" Write-Host "Retrieving audit records for activities performed between $($currentStart) and $($currentEnd)" $currentCount = 0 $sw = [Diagnostics.StopWatch]::StartNew() do { $results = Search-UnifiedAuditLog -StartDate $currentStart -EndDate $currentEnd -RecordType $record -SessionId $sessionID -SessionCommand ReturnLargeSet -ResultSize $resultSize if (($results | Measure-Object).Count -ne 0) { $results | export-csv -Path $outputFile -Append -NoTypeInformation $currentTotal = $results[0].ResultCount $totalCount += $results.Count $currentCount += $results.Count Write-LogFile "INFO: Retrieved $($currentCount) audit records out of the total $($currentTotal)" if ($currentTotal -eq $results[$results.Count - 1].ResultIndex) { $message = "INFO: Successfully retrieved $($currentTotal) audit records for the current time range. Moving on!" Write-LogFile $message Write-Host "Successfully retrieved $($currentTotal) audit records for the current time range. Moving on to the next interval." -foregroundColor Yellow "" break } } } while (($results | Measure-Object).Count -ne 0) $currentStart = $currentEnd } Write-LogFile "END: Retrieving audit records between $($start) and $($end), RecordType=$record, PageSize=$resultSize, total count: $totalCount." Write-Host "Script complete! Finished retrieving audit records for the date range between $($start) and $($end). Total count: $totalCount" -foregroundColor Green修改下表中列出的变量以配置搜索条件。 脚本包括这些变量的示例值,但除非另有说明,否则 (更改它们,) 以满足特定要求。
| 变量 | 示例值 | 说明 |
|---|---|---|
$logFile |
"d:\temp\AuditSearchLog.txt" | 指定日志文件的名称和位置,其中包含有关脚本执行的审核日志搜索的进度信息。 该脚本将 UTC 时间戳写入日志文件。 |
$outputFile |
"d:\temp\AuditRecords.csv" | 指定包含脚本所返回的审核记录的 CSV 文件的名称和位置。 |
[DateTime]$start 和 [DateTime]$end |
[DateTime]::UtcNow.AddDays(-1) [DateTime]::UtcNow |
指定审核日志搜索的日期范围。 该脚本返回在指定日期范围内发生的审核活动的记录。 例如,若要返回 2021 年 1 月执行的活动,可使用 "2021-01-01" 的开始日期和 "2021-01-31" 的结束日期(请确保用双引号括起值)脚本中的示例值将返回过去 24 小时内执行的活动的记录。 如果值中不包含时间戳,则指定日期的默认时间戳为凌晨 12:00(午夜)。 |
$record |
"AzureActiveDirectory" | 指定要搜索的审计活动(也称为操作)的记录类型。 此属性指示触发了活动的服务或功能。 有关可用于此变量的记录类型的列表,请参阅审核日志记录类型。 可以使用记录类型名称或 ENUM 值。 提示:若要返回所有记录类型的审核记录,请使用 $null 值(不带双引号)。 |
$resultSize |
5000 | 指定脚本每次调用 Search-UnifiedAuditLog cmdlet 时返回的结果数(称为结果集)。 cmdlet 支持的最大值是 5,000。 保留该值。 |
$intervalMinutes |
60 | 为了帮助克服返回的 5,000 条记录的限制,此变量采用指定的数据范围,并将其切成更小的时间间隔。 现在,每个间隔(并非整个日期范围)都受命令的 5000 条记录输出限制约束。 对于大多数组织来说,日期范围内的默认值为每 60 分钟间隔 5,000 条记录应足够。 但是,如果脚本返回 maximum results limitation reached 的错误,请缩短时间间隔(例如,减少到 30 分钟甚至 15 分钟),然后重新运行脚本。 |
上表中列出的大多数变量都对应于 Search-UnifiedAuditLog cmdlet 的参数。 有关这些参数的详细信息,请参阅 Search-UnifiedAuditLog。
在本地计算机上,打开 Windows PowerShell,然后转到保存修改后的脚本的文件夹。
在 Exchange Online PowerShell 中运行脚本;例如:
.\SearchAuditLog.ps1
该脚本在运行时显示进度消息。 脚本完成运行后,它会创建日志文件和包含审核记录的 .csv 文件,并将其保存到 由 $logFile 和 $outputFile 变量定义的文件夹中。
重要
每次在脚本中运行 cmdlet 时返回的最大审核记录数限制为 50,000。 如果运行此脚本并返回 50,000 个结果,则可能不包括在日期范围内发生的活动的审核记录。 如果发生这种情况,请将日期范围划分为较小的持续时间,然后针对每个日期范围重新运行脚本。 例如,如果 90 天的日期范围返回 50,000 条结果,则可以重新运行脚本两次,对日期范围中的前 45 天重新运行一次,然后针对接下来 45 天再运行一次。
步骤 3:设置审核记录格式并查看
运行脚本并将审核记录导出到 .csv 文件后,可能需要设置 .csv 的格式,以便更轻松地查看和分析审核记录。 执行此作的一种方法是使用 Excel 中的Power Query JSON 转换功能,将 AuditData 列中 JSON 对象中的每个属性拆分为其自己的列。 有关分步说明,请参阅导出、配置和查看审核日志记录中的“步骤 2:使用 Power Query 编辑器转换 JSON 对象”。