Skip to main content

Querying Event Logs

I noticed that there is a huge speed difference between using an XML Query and PowerShell Get-EventLog piped through Where-Object to filter event logs. Thanks to this article, I learned how to use the XML Query via PowerShell, so you get the best of both worlds.

Know your version

Here's different commands that will show you which version PowerShell you're running.

$PSVersionTable.PSVersion

Get-Host

$host

$host.version

 

General concepts

There are two different cmdlets for accessing Windows Event Logs. Get-WinEvent is a newer version of Get-EventLog.

Get-WinEvent

    You have access to more information Because you have more information, it might take more effort to filter the data

    Get-EventLog

      One clear advantage: you can use the -After and -Before attributes to easily filter results by date

      Filtering results

      If you want to know how to filter the results, simply pipe the cmdlet to Get-Member:

      Get-EventLog system -newest 1 | Get-Member

      The output of the command clearly shows you the methods and properties returned:

      PS C:\> Get-EventLog system -newest 1 | Get-Member
      
      
         TypeName: System.Diagnostics.EventLogEntry#system/nhi/1074012975
      
      Name                      MemberType     Definition
      ----                      ----------     ----------
      Disposed                  Event          System.EventHandler Disposed(System.Object, System.EventArgs)
      CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
      Dispose                   Method         void Dispose(), void IDisposable.Dispose()
      Equals                    Method         bool Equals(System.Diagnostics.EventLogEntry otherEntry), bool Equals(System.Object obj)
      GetHashCode               Method         int GetHashCode()
      GetLifetimeService        Method         System.Object GetLifetimeService()
      GetObjectData             Method         void ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
      GetType                   Method         type GetType()
      InitializeLifetimeService Method         System.Object InitializeLifetimeService()
      ToString                  Method         string ToString()
      Category                  Property       string Category {get;}
      CategoryNumber            Property       int16 CategoryNumber {get;}
      Container                 Property       System.ComponentModel.IContainer Container {get;}
      Data                      Property       byte[] Data {get;}
      EntryType                 Property       System.Diagnostics.EventLogEntryType EntryType {get;}
      Index                     Property       int Index {get;}
      InstanceId                Property       long InstanceId {get;}
      MachineName               Property       string MachineName {get;}
      Message                   Property       string Message {get;}
      ReplacementStrings        Property       string[] ReplacementStrings {get;}
      Site                      Property       System.ComponentModel.ISite Site {get;set;}
      Source                    Property       string Source {get;}
      TimeGenerated             Property       datetime TimeGenerated {get;}
      TimeWritten               Property       datetime TimeWritten {get;}
      UserName                  Property       string UserName {get;}
      EventID                   ScriptProperty System.Object EventID {get=$this.get_EventID() -band 0xFFFF;}

       

      Get-EventLog Examples

      # Show available event logs and stats
      Get-EventLog -List
      # get the most recent 10 system log entries
      Get-EventLog# -just change the LogName Applicationfrom -NewestSystem 10to Get-EventLogApplication, -LogNameSecurity, Securityetc. -Newestto 10access other logs
      Get-EventLog -LogName System -Newest 10
      # get all system logs from the last 4 hours
      Get-EventLog -LogName System -After (Get-Date).AddHours(-4)
      # get all system logs from the last 24 hours
      Get-EventLog -LogName systemSystem -afterAfter (Get-Date).AddDays(-1)
      # View specific event using the event Index
      Get-EventLog -LogName System -Index [Event_Index_Number] | Format-List
      # get the most recent 10 entries from a specific source
      Get-EventLog -LogName System -Source Kerberos -Newest 10
      Get-EventLog -LogName System -Source Microsoft-Windows-WLAN-AutoConfig -Newest 10
      # Get system logs from the last 24 hours from Source WLAN-AutoConfig 
      Get-EventLog -LogName system -afterAfter (Get-Date).AddDays(-1) -Source Microsoft-Windows-WLAN-AutoConfig
      # get the most recent 10 Error entries
      Get-EventLog -LogName Application -EventType Error -Newest 10
      Get-EventLog -LogName Security -EventType Error -Newest 10
      Get-EventLog -LogName System -EventType Error -Newest 10

      # Get list of Event Log Sources from the System log from the last 8 hours sorted by log count
      Get-EventLog -LogName System -after (Get-Date).AddHours(-8) | Group-Object -Property Source -NoElement | Select-Object -Property Count, Name | Sort-Object -Descending Count
      # GetFind listlogins of Event Log Sources fromin the last 24 hours
      Get-EventLog -LogName Systemsystem -after (get-date).AddDays(-1) | where {$_.InstanceId -eq 7001}
      
      # Find last computer start
      $today = get-date -Hour 0 -Minute 0;
      Get-EventLog system -after $today | sort -Descending | select -First 1
      # Find logins and logoffs in the last 7 days
      $logs = get-eventlog system -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-1)7);
      |$res Group-= @(); ForEach ($log in $logs) {if($log.instanceid -eq 7001) {$type = "Logon"} Elseif ($log.instanceid -eq 7002){$type="Logoff"} Else {Continue} $res += New-Object PSObject -Property Source@{Time -NoElement= |$log.TimeWritten; Select-"Event" = $type; User = (New-Object -PropertySystem.Security.Principal.SecurityIdentifier Count,$Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
      Name | Sort-Object -Descending Count
      $res

       

      Get-WinEvent Examples

      # Get user Logon / Logoff events
      Get-WinEvent -FilterHashtable @{
         LogName='System'
         ProviderName='Microsoft-Windows-Winlogon'
         ID=7001,7002
      }
      Get-WinEvent -FilterHashtable @{
         LogName='Application'
         ProviderName='.NET Runtime'
         Keywords=36028797018963968
         ID=1023
         Level=2
      }

       

      Formatting output

      Source

      You can see what formatters are available on any system using the following command

      Get-Command -Verb Format -Module Microsoft.PowerShell.Utility

      Below is the output on Windows 11 as of 10/31/2023

      PS C:\> Get-Command -Verb Format -Module Microsoft.PowerShell.Utility
      
      CommandType     Name                                               Version    Source
      -----------     ----                                               -------    ------
      Function        Format-Hex                                         3.1.0.0    Microsoft.PowerShell.Utility
      Cmdlet          Format-Custom                                      3.1.0.0    Microsoft.PowerShell.Utility
      Cmdlet          Format-List                                        3.1.0.0    Microsoft.PowerShell.Utility
      Cmdlet          Format-Table                                       3.1.0.0    Microsoft.PowerShell.Utility
      Cmdlet          Format-Wide                                        3.1.0.0    Microsoft.PowerShell.Utility

      You also have access to the following cmdlets for other output formats

      Viewing a specific eventExport-CliXml

      # Export-Clixml exports an XML representation of an object or objects and stores it in a file
      Get-EventLogAcl C:\Windows | Export-CliXml -LogNamePath Application.\c-windows-acl.xml
      # You can use Import-CliXml to save the stored object or objects back to a variable
      $WindowsFolderACL = Import-CliXml -IndexPath [Event_Index_Number].\c-windows-acl.xml

      Export-Csv

      # Export-Csv - Add an example later

       

      Redirecting data with Out-* cmdlets

      Source

      Out-Host -Paging
      
      Get-Process | Out-Host -Paging | Format-List
      
      Get-Process | Format-List | Out-Host -Paging
      
      Get-Command | Out-Null
      
      Get-Command Get-Command | Out-Printer -Name 'Microsoft Office Document Image Writer'
      
      Get-Process | Out-File -FilePath C:\temp\processlist.txt
      
      Get-Command | Out-File -FilePath c:\temp\output.txt -Width 2147483647

       

      Grouping output

      Remember to use the Get-Member cmdlet to see what properties you can use with Sort-Object and -GroupBy

      Get-Service -Name win* | Sort-Object StartType | Format-Table -GroupBy StartType -AutoSize
      PS C:\> Get-Service -Name win* | Sort-Object StartType | Format-Table -GroupBy StartType -AutoSize
      
      
         StartType: Automatic
      
      Status  Name      DisplayName
      ------  ----      -----------
      Running Winmgmt   Windows Management Instrumentation
      Running WinDefend Microsoft Defender Antivirus Service
      
      
         StartType: Manual
      
      Status  Name                DisplayName
      ------  ----                -----------
      Stopped WinRM               Windows Remote Management (WS-Management)
      Running WinHttpAutoProxySvc WinHTTP Web Proxy Auto-Discovery Service


      Querying for specific logs

      System uptime related logs

      For the actual current system uptime via PowerShell, look here.

      Use this XML Filter in the Windows Event Viewer to create a custom filtered view of Kernel-General "The operating system started at system time..." events.

      <QueryList>
        <Query Id="0" Path="System">
          <Select Path="System">*[System[(EventID='12')]]</Select>
          <Select Path="System">*[System[(EventID='13')]]</Select>
        </Query>
      </QueryList>

      Actual log message

      Log Name:      System
      Source:        Microsoft-Windows-Kernel-General
      Date:          5/30/2023 7:48:33 PM
      Event ID:      12
      Task Category: (1)
      Level:         Information
      Keywords:      (128)
      User:          SYSTEM
      Computer:      [REDACTED]
      Description:
      The operating system started at system time ‎2023‎-‎05‎-‎31T02:48:32.500000000Z.
      Event Xml:
      <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
        <System>
          <Provider Name="Microsoft-Windows-Kernel-General" Guid="{a68ca8b7-004f-d7b6-a698-07e2de0f1f5d}" />
          <EventID>12</EventID>
          <Version>0</Version>
          <Level>4</Level>
          <Task>1</Task>
          <Opcode>0</Opcode>
          <Keywords>0x8000000000000080</Keywords>
          <TimeCreated SystemTime="2023-05-31T02:48:33.1346923Z" />
          <EventRecordID>74715</EventRecordID>
          <Correlation />
          <Execution ProcessID="4" ThreadID="8" />
          <Channel>System</Channel>
          <Computer>[REDACTED]</Computer>
          <Security UserID="S-1-5-18" />
        </System>
        <EventData>
          <Data Name="MajorVersion">10</Data>
          <Data Name="MinorVersion">0</Data>
          <Data Name="BuildVersion">19041</Data>
          <Data Name="QfeVersion">2075</Data>
          <Data Name="ServiceVersion">0</Data>
          <Data Name="BootMode">0</Data>
          <Data Name="StartTime">2023-05-31T02:48:32.5000000Z</Data>
        </EventData>
      </Event>

      Finding account lockouts.

      XML Query

      Use this XML Filter in the Windows Event Viewer to create a custom filtered view displaying account lockouts.

      <QueryList>
        <Query Id="0" Path="Security">
          <Select Path="Security">
            *[
              System[(EventID='4740')]
            ] 
          </Select>
        </Query>
      </QueryList>

      PowerShell Script - Slow method

      Get-EventLog -LogName Security | Where-Object {$_.EventID -eq 4740} |
         Select-Object -Property TimeGenerated, Source, EventID, InstanceId, Message

      PowerShell Script - Fast method

      $query = @"
      <QueryList>
        <Query Id="0" Path="Security">
          <Select Path="Security">
            *[
              System[(EventID='4740')]
            ] 
          </Select>
        </Query>
      </QueryList>
      "@
      
      Get-WinEvent -FilterXml $query | Format-List

      Finding account lockouts for a particular user.

      XML Query

      Use this XML Filter in the Windows Event Viewer to create a custom filtered view displaying account lockouts for the administrator user.

      <QueryList>
        <Query Id="0" Path="Security">
          <Select Path="Security">
            *[
              EventData[Data[@Name='TargetUserName']='administrator']
              and
              System[(EventID='4740')]
            ] 
          </Select>
        </Query>
      </QueryList>

      PowerShell Script - Fast method

      $query = @"
      <QueryList>
        <Query Id="0" Path="Security">
          <Select Path="Security">
            *[
              EventData[Data[@Name='TargetUserName']='administrator']
              and
              System[(EventID='4740')]
            ] 
          </Select>
        </Query>
      </QueryList>
      "@
      
      Get-WinEvent -FilterXml $query | Format-List

      NPS + Azure MFA Logs - XML Query

      XML Filter for custom filtered view that suppresses accounting event logs.

      <QueryXML>
      	<QueryList>
      	  <Query Id="0" Path="System">
      		<Select Path="System">*[System[Provider[@Name='NPS']]]</Select>
      		<Select Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and Task = 12552]]</Select>
      		<Suppress Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and Task = 12552 and (Data='Network Policy Server discarded the accounting request for a user.')]]</Suppress>
      		<Select Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing']]] and *[EventData[Data[@Name='LogonProcessName'] and (Data='IAS')]]</Select>
      		<Select Path="AuthNOptCh">*</Select>
      		<Select Path="AuthZAdminCh">*</Select>
      		<Select Path="AuthZOptCh">*</Select>
      	  </Query>
      	</QueryList>
      </QueryXML>

      NPS Logs - XML Query

      XML Filter for custom filtered view that suppresses accounting event logs.

      <QueryXML>
      	<QueryList>
      	  <Query Id="0" Path="System">
      		<Select Path="System">*[System[Provider[@Name='NPS']]]</Select>
      		<Select Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and Task = 12552]]</Select>
      		<Suppress Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and Task = 12552 and (Data='Network Policy Server discarded the accounting request for a user.')]]</Suppress>
      		<Select Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing']]] and *[EventData[Data[@Name='LogonProcessName'] and (Data='IAS')]]</Select>
      	  </Query>
      	</QueryList>
      </QueryXML>

      Disk logs

      XML Query

      XML Filter for custom filtered view for disk events.

      <QueryList>
        <Query Id="0" Path="System">
          <Select Path="System">*[System[Provider[@Name='disk']]]</Select>
        </Query>
      </QueryList>

      VPN Client Logs

      PowerShell Query

      $query = @"
      <QueryList>
        <Query Id="0" Path="Application">
          <Select Path="Application">*[System[Provider[@Name='RasAuto' or @Name='RasCfg' or @Name='RasClient' or @Name='Rasman' or @Name='Microsoft-Windows-RasServer' or @Name='Microsoft-Windows-RasSstp' or @Name='Microsoft-Windows-EapMethods-RasChap' or @Name='Microsoft-Windows-NcdAutoSetup' or @Name='Microsoft-Windows-NCSI' or @Name='Microsoft-Windows-NetworkProfile']]]</Select>
          <Select Path="System">*[System[Provider[@Name='RasAuto' or @Name='RasCfg' or @Name='RasClient' or @Name='Rasman' or @Name='Microsoft-Windows-RasServer' or @Name='Microsoft-Windows-RasSstp' or @Name='Microsoft-Windows-EapMethods-RasChap' or @Name='Microsoft-Windows-NcdAutoSetup' or @Name='Microsoft-Windows-NCSI' or @Name='Microsoft-Windows-NetworkProfile']]]</Select>
        </Query>
      </QueryList>
      "@
      
      $vpnEvents = Get-WinEvent -FilterXml $query -Oldest
      
      # Displays events from the last 24 hours grouped by ProviderName
      # This is the best view for easily browsing
      $vpnEvents | ?{$_.TimeCreated -ge (Get-Date).Addhours(-24)}

      # Displays events from the last 24 hours as a time sorted list
      $vpnEvents | ?{$_.TimeCreated -ge (Get-Date).Addhours(-24)} | Format-List

      XML Query

      <QueryList>
        <Query Id="0" Path="Application">
          <Select Path="Application">*[System[Provider[@Name='RasAuto' or @Name='RasCfg' or @Name='RasClient' or @Name='Rasman' or @Name='Microsoft-Windows-RasServer' or @Name='Microsoft-Windows-RasSstp' or @Name='Microsoft-Windows-EapMethods-RasChap' or @Name='Microsoft-Windows-NcdAutoSetup' or @Name='Microsoft-Windows-NCSI' or @Name='Microsoft-Windows-NetworkProfile']]]</Select>
          <Select Path="System">*[System[Provider[@Name='RasAuto' or @Name='RasCfg' or @Name='RasClient' or @Name='Rasman' or @Name='Microsoft-Windows-RasServer' or @Name='Microsoft-Windows-RasSstp' or @Name='Microsoft-Windows-EapMethods-RasChap' or @Name='Microsoft-Windows-NcdAutoSetup' or @Name='Microsoft-Windows-NCSI' or @Name='Microsoft-Windows-NetworkProfile']]]</Select>
        </Query>
      </QueryList>

      Searching for Wired/WLAN-AutoConfig related errors

      Original source

      Wired-AutoConfig

      #Powershell
      $addhours = 12;
      
      # Setup filter for error only logs
      $filter = @{ LogName = "Microsoft-Windows-Wired-AutoConfig/Operational"
      StartTime = [DateTime]::Now.AddHours($addhours*-1)
      EndTime = [DateTime]::Now
      Level = 2
      }
      
      Write-Host ([DateTime]::Now.AddHours($addhours*-1))
      
      Write-Host ([DateTime]::Now)
      
      $Events = Get-Winevent -FilterHashtable $filter
      
      
      
      # Parse out the event message data            
      ForEach ($Event in $Events) {            
      	# Convert the event to XML            
      	$eventXML = [xml]$Event.ToXml()            
      	# Iterate through each one of the XML message properties            
      	For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++) {            
      		# Append these as object properties            
      		Add-Member -InputObject $Event -MemberType NoteProperty -Force -Name $eventXML.Event.EventData.Data[$i].name -Value $eventXML.Event.EventData.Data[$i].'#text'            
      	}            
      }       
      

      # Show results stored in variable
      $Events | Format-List

      WLAN-AutoConfig

      #Powershell
      $addhours = 12;
      
      # Setup filter for error only logs
      $filter = @{ LogName = "Microsoft-Windows-WLAN-AutoConfig/Operational"
      StartTime = [DateTime]::Now.AddHours($addhours*-1)
      EndTime = [DateTime]::Now
      Level = 2
      }
      
      Write-Host ([DateTime]::Now.AddHours($addhours*-1))
      
      Write-Host ([DateTime]::Now)
      
      $Events = Get-Winevent -FilterHashtable $filter
      
      
      
      # Parse out the event message data            
      ForEach ($Event in $Events) {            
      	# Convert the event to XML            
      	$eventXML = [xml]$Event.ToXml()            
      	# Iterate through each one of the XML message properties            
      	For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++) {            
      		# Append these as object properties            
      		Add-Member -InputObject $Event -MemberType NoteProperty -Force -Name $eventXML.Event.EventData.Data[$i].name -Value $eventXML.Event.EventData.Data[$i].'#text'            
      	}            
      }       
      
      $Events | Select-Object id, MachineName, ProcessId,TimeCreated, Adapter, LocalMac, SSID, Cipher, Auth, PeerMac | Format-List
      

      # Show results stored in variable
      $Events | Select-Object id, MachineName, ProcessId,TimeCreated, Adapter, LocalMac, SSID, Cipher, Auth, PeerMac | Format-List

      Show available wireless profiles and available wireless networks
      # show profiles
      netsh wlan show profiles
      
      # show available networks
      netsh wlan show networks

      Sources: 1