Querying the Windows Event Log with PowerShell | Ranjan.info

The Windows event log is an important tool for administrators to track errors, warnings, and other information reports that are logged by the operating system, its components, or programs. You can use the Event Viewer graphical MMC snap-in (eventvwr.msc) to view the Windows Event Log. In some cases, it is more convenient to use PowerShell to parse and analyze information from the event log. In this article, you will learn how to use Get-WinEvent cmdlet to retrieve information from the Windows event log.

Two cmdlets are currently available in Windows to access event log entries: get-eventlog And Get-WinEvent. We recommend that you use Get-WinEvent in most cases, as it is more productive, especially in scenarios where you need to process a large number of events from a remote computer. The Get-EventLog cmdlet is deprecated and was used to get the log in earlier versions of Windows. Also, Get-EventLog is not supported in the latest versions of PowerShell Core 7.x.

Get-WinEvent: Search the Event Log Using PowerShell

To use the Get-WinEvent command, you must be running PowerShell as an administrator. If you try to run Get-WinEvent as a non-administrator user, you will not be able to access some logs, including the Security log.

To get a list of events from a specific log, you must specify its name. For example, the following command lists the last 20 events from the System log:

Get-WinEvent -LogName Application -MaxEvents 20

The most common logs to query are the System, Application, Security, or Setup logs. You can also specify other log names. You can get a complete list of event logs in Windows with the command:

Get-WinEvent -ListLog *

Search the event log with Get-WinEvent

For example, to view the RDP connection history on a computer, you would specify Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational log:

Get-WinEvent -LogName Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational

Or you can get the SSH connection log from OpenSSH/Operational Log in Windows:

Get-WinEvent -LogName OpenSSH/Operational

You can also select events from multiple logs at once. For example, if you want to retrieve information about errors and warnings from the System and Application logs for the last 24 hours, use the following code:

$StartDate = (Get-Date) - (New-TimeSpan -Day 1)
Get-WinEvent Application,System | Where-Object {($_.LevelDisplayName -eq "Error" -or $_.LevelDisplayName -eq "Warning") -and ($_.TimeCreated -ge $StartDate )}

Filtering the event log with a specific date range

you can use select-object or Format-Table cmdlets to display only specific event fields:

Get-WinEvent -LogName System | Format-Table Machinename, TimeCreated, Id, UserID
Get-WinEvent Format-Table

You can further process the data obtained from the event log. In this example, we’ll quickly convert the username to a SID:

Get-WinEvent -filterhash @{Logname="system"} |
Select-Object @{Name="Computername";Expression = {$_.machinename}},@{Name="UserName";Expression = {$_.UserId.translate([System.Security.Principal.NTAccount]).value}}, TimeCreated

Faster event search with filter hashtable option

The above method of filtering specific events from the Event Viewer log with the Where-Object may be easier to understand, but it is extremely slow, especially if you want to search through a large number of events. In most cases, it is better to use the Event Viewer server-side filtering by using filter hashtable Option.

Now, let’s try to generate a list of errors and warnings over a 30-day period using a warehousing object and a FilterHashtable. we will then use Measure-Command To compare the execution time of these two PowerShell commands:

$StartDate = (Get-Date).AddDays(-30)

First, we check the execution time of the command with the where-object filter:

(Measure-Command {Get-WinEvent Application,System | Where-Object {($_.LevelDisplayName -eq "Error" -or $_.LevelDisplayName -eq "Warning") -and ($_.TimeCreated -ge $StartDate )}}).TotalMilliseconds

Same command with filtered hashtable:

(Measure-Command {Get-WinEvent -FilterHashtable @{LogName="System",'Application'; Level =2,3; StartTime=$StartDate }}).TotalMilliseconds

This example shows filter hashtable event filtering command 30 times faster ware-object filter over normal ( 2.5 sec vs 76 seconds).

Faster Event Log Search with FilterHashtable in PowerShell

If you need to find events by EventID, use the following command with the filterHashtable parameter:

Get-WinEvent -FilterHashtable @{logname="System";id=1074}|ft TimeCreated,Id,Message

The Filter Hashtable argument allows you to filter by the following event attributes:

  • logname
  • provider name
  • path
  • keyword (use 9007199254740992 to discover successful events and 4503599627370496 for losers)
  • Identification
  • level (1=fatal, 2=error, 3=warning, 4=info, 5=debug, 6=trace, 0=info)
  • start time
  • end time
  • UserID (SID of the user)
  • statistics

Here’s an example of finding an event in a given time period:

Get-WinEvent -FilterHashTable @{LogName="System"; StartTime=(get-date).AddDays(-7); EndTime=(get-date).AddHours(-1); ID=1234}

If you want to find specific text in event description then below command can be used:

Get-WinEvent -FilterHashtable @{logname="System"}|Where {$_.Message -like "*USB*"}

    Get-WinEvent Queries with FilterHashtable

Advanced Get-WinEvent Filtering with FilterXML

The FilterHashtable option has some limitations with the Get-WinEvent filter. If you need to use complex queries with multiple criteria to select events, you need to use FilterXML Flag, which allows you to select using an XML query. Similar to FilterHashtable, FilterXML filters are server-side. This means that you get the result very quickly.

For example, another way to get the latest errors from the system log for the last 30 days is:

$xmlQuery = @'
<QueryList>
<Query Id="0" Path="System">
<Select Path="System">*[System[(Level=2 or Level=3) and TimeCreated[timediff(@SystemTime) &lt;= 2592000000]]]</Select>
</Query>
</QueryList>
'@
Get-WinEvent -FilterXML $xmlQuery

Using the FilterXml option with Get-WinEvent

To generate a complex XML query code, you can use the Event Viewer graphical console:

  1. run command eventvwr.msc ,
  2. Find the log for which you want to create a query and click Filter Current Log, Filter the current log in Event Viewer
  3. Select the required query parameters in the Filter form. In this example, I want to find events with a specific event ID for the last 7 days for a specific user; Filter event log by event ID and username
  4. To get the XML query code, go to the XML tab, and copy the XPath code (CTRL+A, CTRL+C,Copy XPath for Occurrence Search Query
  5. You can manually edit this query if necessary.

To export the list of events to a CSV file, use the Export-CSV cmdlet:

$Events= Get-WinEvent -FilterXML $xmlQuery
$events| Export-CSV "C:\ps\FilterSYSEvents.csv" -NoTypeInformation -Encoding UTF8

Receive event logs from remote computers

To receive events from a remote computer, just specify its name -computer name Parameters:

$computer="mun-dc01"
Get-WinEvent -ComputerName $computer -FilterHashtable @{LogName="System"; StartTime=(get-date).AddHours(-24)} |   select Message,Id,TimeCreated

You can query multiple remote hosts at once to search for specific events. You can get list of remote computers from text file:

$servers = Get-Content -Path C:\ps\servers.txt

or from Active Directory:

$servers = (Get-ADComputer -Filter 'operatingsystem -like "*Windows Server*" -and enabled -eq "true"').Name
foreach ($server in $servers) {
Get-WinEvent -ComputerName $server -MaxEvents 5 -FilterHashtable @{
LogName="System"; ID= 1234
} | Select-Object -Property ID, MachineName
}

Here’s another example of searching for user account lockout events on all domain controllers:

$Username="a.muller"
Get-ADDomainController -fi * | select -exp hostname | % {
$GweParams = @{
'Computername' = $_
'LogName' = 'Security'
'FilterXPath' = "*[System[EventID=4740] and EventData[Data[@Name="TargetUserName"]='$Username']]"
}
$Events = Get-WinEvent @GweParams
$Events | foreach {$_.Computer + " " +$_.Properties[1].value + ' ' + $_.TimeCreated}
}

Leave a Comment