使用 PowerShell 脚本搜索审核日志

安全性、合规性和审核成为当今 IT 管理员的首要任务。 Microsoft 365 具有多种内置功能,可帮助组织管理安全性、合规性和审核。 具体来说,统一审核日志记录可以帮助调查安全事件和合规性问题。 可以使用以下方法检索审核日志:

如果需要定期检索审核日志,应考虑使用Office 365管理活动 API 的解决方案,因为它可为大型组织提供可伸缩性和性能,以便持续检索数百万条审核记录。 使用 Microsoft Purview 门户或合规性门户中的审核日志搜索工具是快速查找在较短时间范围内发生的特定操作的审核记录的好方法。 在审核日志搜索工具中使用较长的时间范围(尤其是对于大型组织),可能会返回过多记录,无法轻松管理或导出。

在某些情况下,需要手动检索特定调查或事件的审核数据,特别是对于大型组织中较长的日期范围,最好使用 Search-UnifiedAuditLog cmdlet。 本文包含一个使用 cmdlet 的 PowerShell 脚本,可以检索多达 50,000 条审核记录(每次运行 cmdlet 时),然后将它们导出为 CSV 文件,并可以使用 Excel 中的 Power Query 对其进行格式设置以帮助审阅。 使用本文中的脚本还可以将大审核日志搜索在服务中超时的可能性降到最低。

提示

如果你不是 E5 客户,请使用为期 90 天的 Microsoft Purview 解决方案试用版来探索其他 Purview 功能如何帮助组织管理数据安全性和合规性需求。 立即从Microsoft Purview 合规门户试用中心开始。 了解有关 注册和试用条款的详细信息。

运行此脚本之前

  • 必须启用审核日志记录,以便组织成功使用该脚本返回审核记录。 Microsoft 365 和 Office 365 企业版组织默认已打开审核日志搜索。 若要验证组织是否已打开审核日志搜索,可以在 Exchange Online PowerShell 中运行以下命令:

    Get-AdminAuditLogConfig | FL UnifiedAuditLogIngestionEnabled
    

    UnifiedAuditLogestionEnabled 属性的 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 中的表格,了解这些变量的说明。

  1. 使用 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
    
  2. 修改下表中列出的变量以配置搜索条件。 脚本包括这些变量的示例值,但应对其进行更改(除非另有说明)以满足特定要求。



变量 示例值 说明
$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

  1. 在本地计算机上,打开 Windows PowerShell,然后转到保存修改后的脚本的文件夹。

  2. 在 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 对象”。