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

[玩转系统] Get-EventLog:使用 PowerShell 查询 Windows 事件日志

作者:精品下载站 日期:2024-12-14 12:36:14 浏览:17 分类:玩电脑

Get-EventLog:使用 PowerShell 查询 Windows 事件日志


每个 Windows 系统管理员可能都熟悉 Windows 事件日志。在 PowerShell 中使用此 cmdlet 允许系统管理员同时解析多台计算机上的大量事件。它使系统管理员无需在事件查看器中四处点击,试图找出要使用的正确过滤器并确定关键事件的准确存储位置。然而,Get-EventLog 确实有其缺点,您将会看到。

使用 Get-EventLog 列出事件日志

Get-EventLog cmdlet 可在所有现代版本的 Windows PowerShell 上使用。在最简单的使用中,此 cmdlet 需要一个事件日志来查询,然后它将显示该事件日志中的所有事件。

但是,如果您一开始就不知道事件日志名称怎么办?在这种情况下,我们需要找出本地计算机上可用的所有事件日志。我们通过使用命令 Get-EventLog -List 来完成此操作。

[玩转系统] Get-EventLog:使用 PowerShell 查询 Windows 事件日志

您可以看到我的本地系统上现在有一些事件日志,但您可能想知道其他日志在哪里?事件查看器中的应用程序和服务日志下显示了许多其他事件日志。他们为什么不在这里?

不幸的是,如果您需要这些事件,Get-EventLog 将不起作用。相反,您需要查看 Get-WinEvent。目前,Get-EventLog cmdlet 可以被视为旧版 cmdlet,但我仍然经常使用它,因为它非常易于使用。

使用 Get-EventLog 查询事件

现在我们知道所有可用的事件日志,我们现在可以读取该事件日志中的事件。也许我想查看应用程序事件日志中的所有事件。要获取这些事件,我需要使用 Get-EventLog 指定 LogName 参数,并且 cmdlet 将返回该事件日志中的所有事件。

[玩转系统] Get-EventLog:使用 PowerShell 查询 Windows 事件日志

默认情况下,您只会在输出中看到六个属性:

    Index
    Time
    EntryType
    Source
    InstanceId
    Message

    实际上,Get-EventLog 返回其中的 16 个。您只看到六个的原因是定义输出的 PowerShell 格式规则。下面是通过将 Get-EventLog 通过管道传输到 Select-Object 并选择所有属性找到的实际输出示例。

    [玩转系统] Get-EventLog:使用 PowerShell 查询 Windows 事件日志

    使用 Get-EventLog 进行过滤

    寻找事件时,我们很可能不需要所有事件。相反,我们只需要一些。在这种情况下,我们需要过滤特定事件。 Get-EventLog 有几种不同的方法可以做到这一点。 Get-EventLog cmdlet 可以根据时间戳、条目类型、事件 ID、消息、源和用户名进行过滤。这适用于大多数查找事件的方式。

    为了演示过滤,也许我经常查询事件,并且我想找到十个最新的事件。在这种情况下,我可以使用 Newest 参数并指定我想要查看的事件数量。 Get-EventLog -LogName Application -Newest 10 将仅返回最新的十个事件。

    也许我想查找特定时间点之后的所有事件。为此,我们有 After 参数。 After 参数采用日期/时间,因此如果我只想查找应用程序日志中 2019 年 1 月 26 日上午 10:17 之后发生的事件,我可以这样做Get-EventLog -LogName 应用程序 -“1/26/19 10:17”之后。我们也可以执行相同的过程,但使用 Before 参数选择在某个日期之前发生的事件,您可能已经猜到了。

    Get-EventLog 有很多不同的方法来过滤不包括基于时间戳的内容。我们还可以根据其他属性(例如事件 ID(实例 ID)和消息)来过滤事件,这些属性往往是搜索的常用属性。也许我知道我正在寻找 ID 为 916 的活动;我们将 916 传递给 InstanceId 参数。

    PS> Get-EventLog -LogName Application -InstanceId 916

    我们也可以组合过滤器。也许我收到很多 ID 为 916 的事件返回,但我希望这些事件在消息中带有字符串 svchost。在这种情况下,我们可以将 Message 参数添加到 Get-EventLog 中,并指定一个通配符,例如 svchost

    PS> Get-EventLog -LogName Application -InstanceId 916 -Message '*svchost*'

    奖励脚本!

    您是否需要在实际脚本中使用 Get-EventLog 的绝佳示例?如果是这样,那么你很幸运!以下是 Get-EventLog 的高级用例,您可以立即下载并使用!

    <#
    .SYNOPSIS
        This script searches a Windows computer for all event log or text log entries
        between a specified start and end time.
    .DESCRIPTION
        This script enumerates all event logs within a specified timeframe and all text logs 
     that have a last write time in the timeframe or contains a line that has a date/time
     reference within the timeframe.  It records this information to a set of files and copies
     any interesting log file off for further analysis.
    .EXAMPLE
        PS> .\Get-EventsFromTimeframe.ps1 -StartTimestamp '01-29-2014 13:25:00' -EndTimeStamp '01-29-2014 13:28:00' -ComputerName COMPUTERNAME
     
        This example finds all event log entries between StartTimestamp and EndTimestamp and any file
        with an extension inside the $FileExtension param that either was last written within the timeframe
        or contains a line with a date/time reference within the timeframe.
    .PARAMETER StartTimestamp
     The earliest date/time you'd like to begin searching for events.
    .PARAMETER EndTimestamp
     The latest date/time you'd like to begin searching for events.
    .PARAMETER Computername
     The name of the remote (or local) computer you'd like to search on.
    .PARAMETER OutputFolderPath
     The path of the folder that will contain the text files that will contain the events.
    .PARAMETER LogAuditFilPath
     The path to the text file that will document the log file, line number and match type
     to the logs that were matched.
    .PARAMETER EventLogsOnly
     Use this switch parameter if you only want to search in the event logs.
    .PARAMETER LogFilesOnly
     Use this parameter if you only want to search for logs on the file system.
    .PARAMETER ExcludeDirectory
     If searching on the file system, specify any folder paths you'd like to skip.
    .PARAMETER FileExtension
     Specify one or more comma-delimited set of file extensions you'd like to search for on the file system.
     This defaults to 'log,txt,wer' extensions.
    #>
    [CmdletBinding(DefaultParameterSetName = 'Neither')]
    param (
        [Parameter(Mandatory)]
        [datetime]$StartTimestamp,
        [Parameter(Mandatory)]
        [datetime]$EndTimestamp,
        [Parameter(ValueFromPipeline,
            ValueFromPipelineByPropertyName)]
        [string]$ComputerName = 'localhost',
        [Parameter()]
     [string]$OutputFolderPath = ".$Computername",
     [Parameter(ParameterSetName = 'LogFiles')]
     [string]$LogAuditFilePath = "$OutputFolderPath\LogActivity.csv",
     [Parameter(ParameterSetName = 'EventLogs')]
     [switch]$EventLogsOnly,
        [Parameter(ParameterSetName = 'LogFiles')]
        [switch]$LogFilesOnly,
        [Parameter(ParameterSetName = 'LogFiles')]
     [string[]]$ExcludeDirectory,
     [Parameter(ParameterSetName = 'LogFiles')]
     [string[]]$FileExtension = @('log', 'txt', 'wer')
    )
     
    begin {
     if (!$EventLogsOnly.IsPresent) {
     ## Create the local directory where to store any log files that matched the criteria
     $LogsFolderPath = "$OutputFolderPath\logs"
     if (!(Test-Path $LogsFolderPath)) {
     mkdir $LogsFolderPath | Out-Null
     }
     }
     
     function Add-ToLog($FilePath,$LineText,$LineNumber,$MatchType) {
     $Audit = @{
     'FilePath' = $FilePath;
     'LineText' = $LineText
     'LineNumber' = $LineNumber
     'MatchType' = $MatchType
     }
     [pscustomobject]$Audit | Export-Csv -Path $LogAuditFilePath -Append -NoTypeInformation
     }
    }
     
    process {
     
        ## Run only if the user wants to find event log entries
        if (!$LogFilesOnly.IsPresent) {
     ## Find all of the event log names that contain at least 1 event
     $Logs = (Get-WinEvent -ListLog * -ComputerName $ComputerName | where { $_.RecordCount }).LogName
     $FilterTable = @{
     'StartTime' = $StartTimestamp
     'EndTime' = $EndTimestamp
     'LogName' = $Logs
     }
     
     ## Find all of the events in all of the event logs that are between the start and ending timestamps
     $Events = Get-WinEvent -ComputerName $ComputerName -FilterHashtable $FilterTable -ea 'SilentlyContinue'
     Write-Verbose "Found $($Events.Count) total events"
     
     ## Convert the properties to something friendlier and append each event into the event log text file
     $LogProps = @{ }
     [System.Collections.ArrayList]$MyEvents = @()
     foreach ($Event in $Events) {
     $LogProps.Time = $Event.TimeCreated
     $LogProps.Source = $Event.ProviderName
     $LogProps.EventId = $Event.Id
     if ($Event.Message) {
     $LogProps.Message = $Event.Message.Replace("<code>n", '|').Replace("</code>r", '|')
     }
     $LogProps.EventLog = $Event.LogName
     $MyEvents.Add([pscustomobject]$LogProps) | Out-Null
     }
     $MyEvents | sort Time | Export-Csv -Path "$OutputFolderPath\eventlogs.txt" -Append -NoTypeInformation
     }
     
     ## Run only if the user wants to find log files
     if (!$EventLogsOnly.IsPresent) {
            ## Enumerate all remote admin shares on the remote computer.  I do this instead of enumerating all phyiscal drives because
            ## the drive may be there and the share may not which means I can't get to the drive anyway.
     $Shares = Get-WmiObject -ComputerName $ComputerName -Class Win32_Share | where { $_.Path -match '^\w{1}:\$' }
     [System.Collections.ArrayList]$AccessibleShares = @()
     ## Ensure I can get to all of the remote admin shares
     foreach ($Share in $Shares) {
     $Share = "\$ComputerName$($Share.Name)"
     if (!(Test-Path $Share)) {
     Write-Warning "Unable to access the '$Share' share on '$Computername'"
     } else {
     $AccessibleShares.Add($Share) | Out-Null 
     }
     }
     
     $AllFilesQueryParams = @{
     Path = $AccessibleShares
     Recurse = $true
     Force = $true
     ErrorAction = 'SilentlyContinue'
     File = $true
     }
     ## Add any directories specified in $ExcludeDirectory param to not search for log files in
     if ($ExcludeDirectory) {
     $AllFilesQueryParams.ExcludeDirectory = $ExcludeDirectory 
     }
     ## Create the crazy regex string that I use to search for a number of different date/time formats.
     ## This is used in an attempt to search for date/time strings in each text file found
     ##TODO: Add capability to match on Jan,Feb,Mar,etc
     $DateTimeRegex = "($($StartTimestamp.Month)[\.\-/]?$($StartTimestamp.Day)[\.\-/]?[\.\-/]$($StartTimestamp.Year))|($($StartTimestamp.Year)[\.\-/]?$($StartTimestamp.Month)[\.\-/]?[\.\-/]?$($StartTimestamp.Day))"
     ## Enumerate all files matching the query params that have content
     Get-ChildItem @AllFilesQueryParams | where { $_.Length -ne 0 } | foreach {
     try {
     Write-Verbose "Processing file '$($_.Name)'"
     ## Record the file if the last write time is within the timeframe.  This finds log files that may not record a 
     ## date/time timestamp but may still be involved in whatever event the user is trying to find.
     if (($_.LastWriteTime -ge $StartTimestamp) -and ($_.LastWriteTime -le $EndTimestamp)) {
     Write-Verbose "Last write time within timeframe for file '$($_.Name)'"
     Add-ToLog -FilePath $_.FullName -MatchType 'LastWriteTime'
     }
     ## If the file found matches the set of extensions I'm trying to find and it's actually a plain text file.
     ## I use the Get-Content to just double-check it's plain text before parsing through it.
     if ($FileExtension -contains $_.Extension.Replace('.','') -and !((Get-Content $_.FullName -Encoding Byte -TotalCount 1024) -contains 0)) {
     ## Check the contents of text file to references to dates in the timeframe
     Write-Verbose "Checking log file '$($_.Name)' for date/time match in contents"
     $LineMatches = Select-String -Path $_.FullName -Pattern $DateTimeRegex
     if ($LineMatches) {
     Write-Verbose "Date/time match found in file '$($_.FullName)'"
     ## Record all of the matching lines to the audit file.
     foreach ($Match in $LineMatches) {
     Add-ToLog -FilePath $_.FullName -LineNumber $Match.LineNumber -LineText $Match.Line -MatchType 'Contents'
     }
     ## Create the same path to the log file on the remote computer inside the output log directory and 
     ## copy the log file with an event inside the timeframe to that path.
     ## This will not work if an file path above 255 characters is met.
     $Trim = $_.FullName.Replace("\$Computername\", '')
     $Destination = "$OutputFolderPath$Trim"
     if (!(Test-Path $Destination)) {
     ##TODO: Remove the error action when long path support is implemented
     mkdir $Destination -ErrorAction SilentlyContinue | Out-Null
     }
     Copy-Item -Path $_.FullName -Destination $Destination -ErrorAction SilentlyContinue -Recurse
     }
     }
     } catch {
     Write-Warning $_.Exception.Message 
     }
     }
     }
    }

    概括

    如果您发现自己需要快速查询常见事件日志之一,则 Get-EventLog cmdlet 是一个非常有用的命令。它易于使用并提供一些基本的过滤功能。但是,如果您需要进行任何深入的事件日志调查,Get-WinEvent 命令可能会更好,但使用起来有点困难,有时需要了解 XPath 等语法。

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

    取消回复欢迎 发表评论:

    关灯