Advanced use of Get-WinEvent and WEF for auditing and security

Last update: 17/12/2025
Author Isaac
  • Get-WinEvent allows you to query, filter, and combine local, remote, and archived records with great flexibility.
  • FilterHashtable, XPath, and XML queries optimize filtering and drastically reduce the volume of irrelevant events.
  • Event forwarding Windows (WEF/WEC) centralizes logs on a large scale through baseline and suspect subscriptions.
  • A good audit policy and the correct channel configuration are key to obtaining useful and scalable traces.

event logging and device disconnection

In many organizations, the use of devices USBRDP connections, interactive logins, and other system access has become a real headache for security teams. Control who connects, from where, with what device, and at what time It is vital for detecting intrusions, filtering out anomalous behavior, and complying with increasingly strict regulations.

The good news is that, if you work with Windows, you have several very powerful tools to centralize all that data tracking: Get-WinEvent, Windows event forwarding (WEF/WEC), advanced XPath/XML queries, and SIEM or MapReduce-type solutionsBy combining these tools you can set up anything from a lightweight system to audit single-user logins, to a massive architecture capable of ingesting tens of thousands of events per second and storing them for years.

Get-WinEvent: the basis for querying the event log in Windows

The cmdlet Get-WinEvent is the modern replacement for Get-EventLog on Windows Vista or later systems. Unlike its predecessor, it allows access to both the "classic" registries (Application, System, Security…) and the new registries based on the technology of Windows Event Log and ETW (Event Tracing for Windows)as well as .evtx and .etl files archived or copied from other computers.

One of its great advantages is that It supports various query and filtering modesAccess can be gained by: record name, provider, specific files, hash tables, XPath, or full XML queries. It also supports remote access using the parameter computer name even without PowerShell Remoting, and can be authenticated with alternative credentials through -Credential.

By default, when you request events, It returns them in order from newest to oldest, although with the switch -Oldest You can reverse that order, which is mandatory when working with ETW traces (.etl) or certain debug logs.

Main syntax of Get-WinEvent

The cmdlet is organized into several “parameter setsEach one designed for a different scenario. Broadly speaking, the most common forms are:

  • Get-WinEvent -LogName: retrieve events from one or more specific records.
  • Get-WinEvent -ListLog: list the configuration of the available records.
  • Get-WinEvent -ListProvider: obtain the list of event providers and in which records they write.
  • Get-WinEvent -ProviderName: read events issued by one or more specific providers.
  • Get-WinEvent -Path: work directly with archived .evtx, .evt or .etl files.
  • Get-WinEvent -FilterHashtable: build powerful filters with key-value pairs (LogName, Id, Level, StartTime, Data, etc.).
  • Get-WinEvent -FilterXml: execute complex XML queries generated, for example, from the Event Viewer.

All these sets can be combined with common parameters such as -MaxEvents (results limit), -ComputerName (remote equipment), -Credential (another account), -Strength (include debugging/analysis logs) or -Oldest (ascending chronological order).

Practical examples of Get-WinEvent for auditing and security

The quickest way to familiarize yourself with Get-WinEvent is to see real-world use cases that fit with everyday tasksespecially if you are in charge of security, compliance, or first-level support.

For example, you can start by listing all the existing records on a server to see what's available, and then refine your search to focus on the events that interest you, such as logins (Id 4624), RDP disconnections, application errors, service changes, or suspicious USB activity.

List all records from the computer (local or remote)

To get a quick inventory For records present on a host, including maximum size, rotation mode, and entry count, you can use:

Get-WinEvent -ListLog *

If you also want to limit yourself only to records that have content, it's very useful to combine it with Where-Object filtering the property RecordCountboth locally and remotely with -ComputerName:

Get-WinEvent -ListLog * -ComputerName localhost | Where-Object { $_.RecordCount }

Thus You focus on the "live" recordings where things are really happening., ideal as a starting point before building more specific queries.

Working with the configuration of a specific register

When you have space or evidence retention issues, it's useful to know and modify the configuration of a log. You can obtain an object using Get-WinEvent. EventLogConfiguration For example, the Security registry:

$log = Get-WinEvent -ListLog Security
$log.MaximumSizeInBytes = 1GB
$log.SaveChanges()

After changing properties such as MaximumSizeInBytes, LogMode or LogFilePathIt's advisable to check the registry again with Format-List -Property * to verify that the modification has been applied correctly. However, you will need administrator permissionsOtherwise, you will see access denied exceptions.

  How to fix error 0xC1900223 in Windows Update

Query records from multiple servers in parallel

In environments with dozens of domain controllers or critical servers, it is common to need a homogeneous photo of the state of the same record (for example, Application or Security). Since the ComputerName parameter only accepts one computer per invocation, a foreach loop is usually used:

$servers = 'Server01','Server02','Server03'
foreach ($s in $servers) {
    Get-WinEvent -ListLog Application -ComputerName $s |
    Select-Object LogMode,MaximumSizeInBytes,RecordCount,LogName,
        @{Name='ComputerName';Expression={$s}} |
    Format-Table -AutoSize
}

With this pattern, In a single run you have comparable data from all members of the group and you can immediately detect differences in size, rotation mode, or abnormal growth.

Explore available providers and event types

In addition to logs, Get-WinEvent lets you list event providers (programs/services that write to the log) using the parameter -ListProviderThis is key when you want to see what is generated by, for example, “Group Policy” or “Windows Defender”:

Get-WinEvent -ListProvider *

The output shows properties such as Name, LogLinks, Opcodes, Tasks and, within Events, the list of Ids and their descriptionsWith something as simple as:

(Get-WinEvent -ListProvider Microsoft-Windows-GroupPolicy).Events |
    Format-Table Id, Description

you get it all at once which event identifiers does a specific provider generate?, with a short summary of each, ideal for knowing what you should collect via WEF or SIEM when investigating an intrusion or want to create correlation rules.

Summarize the content of a record by event ID or level

You don't always need to see every single event; often it's more useful to know Which IDs are repeated most often and at what level (Error, Warning, Information…)You can do that by first loading the events into memory and then grouping them:

$events = Get-WinEvent -LogName 'Windows PowerShell'
$events.Count
$events | Group-Object -Property Id -NoElement | Sort-Object Count -Descending
$events | Group-Object -Property LevelDisplayName -NoElement

This gives you a very convenient summary where you can see, for example, that ID 600 has 147 occurrences and that Most of the entries are at the Information levelIt's a quick way to detect if there are spikes in errors or warnings over a specific period.

Advanced filtering: FilterHashtable, XPath, and XML queries

When you start refining your search, Get-WinEvent shines thanks to three very powerful filtering mechanismsHash tables, XPath queries, and full XML queries. Using them correctly makes the difference between retrieving millions of events or only the ones you need.

FilterHashtable: the most convenient and efficient filter

Parameter -FilterHashtable It accepts one or more hash tables with key-value pairs such as LogName, Id, Level, StartTime, EndTime, ProviderName, UserID, Data, or even SuppressHashFilter to exclude certain events. The good thing is that The filtering is performed in the event engine itself.not in the PowerShell pipeline, so it's much faster than using Where-Object afterward.

For example, to locate application events with Id 1003 of the last two days:

$start = (Get-Date).AddDays(-2)
Get-WinEvent -FilterHashtable @{ LogName='Application'; StartTime=$start; Id=1003 }

And if what interests you is Hunt down “Application Error” errors related to iexplore.exe in the last week:

$start = (Get-Date).AddDays(-7)
Get-WinEvent -FilterHashtable @{
    LogName='Application'
    ProviderName='Application Error'
    Data='iexplore.exe'
    StartTime=$start
}

The variant SuppressHashFilter It adds an interesting layer: you can tell it to retrieve everything except what fits another mini hash table. For example, all Application events from the last two days except those at level 4 (Information):

$start = (Get-Date).AddDays(-2)
$filter = @{
    LogName='Application'
    StartTime=$start
    SuppressHashFilter=@{ Level=4 }
}
Get-WinEvent -FilterHashtable $filter

This type of composite filter is ideal for Focus on what's relevant (errors, warnings) without letting the noise of information obscure the signals..

XPath and FilterXPath: when you need surgical precision

If you come from the XML world or have tinkered with the Event Viewer, this will sound familiar. XPathGet-WinEvent allows you to apply an XPath expression directly to the registry using -FilterXPath combined with LogName or ProviderName.

A classic example is filter by level and by relative time window, without having to calculate dates in PowerShell, but in the query itself:

$xpath = '*]]'
Get-WinEvent -LogName 'Windows PowerShell' -FilterXPath $xpath

Here you are asking Warning level events in the last 24 hours (86.400.000 ms), using the SystemTime information of the event itself, which is very convenient when you automate WEF rules.

FilterXml: complex queries generated from the Event Viewer

When the query becomes complex (multiple records, combinations of Select/Suppress, nested conditions…), the practical thing to do is to go to Events viewerCreate a custom view with the graphical interface and then copy the XML tab of the query.

  How to set up a home network attack simulator geared towards SMEs

Esa XML string You can reuse it directly in PowerShell:

$xmlQuery = @'
<QueryList>
  <Query Path="Windows PowerShell">
    <Select Path="System">
      *]]
    </Select>
  </Query>
</QueryList>
'@

Get-WinEvent -FilterXml $xmlQuery

In addition, the XML format supports elements Suppress similar to SuppressHashFilter, which They help you eliminate noise without affecting the rest of the consultation., very useful in complex WEF subscriptions.

Archived log files and ETW traces (.evtx, .evt, .etl)

Another huge advantage of Get-WinEvent is that It is not limited to the active records of the equipmentYou can also work with files saved on disk, whether they are backups, exports from other systems, or diagnostic traces.

Read .evtx logs saved on disk

If you have, for example, a "Windows PowerShell" registry export (see reliability history in PowerShell) On C:\Test\Windows PowerShell.evtxSimply point to that file:

Get-WinEvent -Path 'C:\Test\Windows PowerShell.evtx'

The exit will include ProviderName, TimeCreated, Id, LevelDisplayName and MessageExactly the same as if you were reading the live recording. From there you can apply filters by ID, time range, etc., as always.

Limit the number of events in archived files

When the file is very large, it is advisable to use -MaxEvents To avoid retrieving thousands of entries at once. For example, the last 100 events from an archived PowerShellCore log:

Get-WinEvent -Path 'C:\Test\PowerShellCore Operational.evtx' -MaxEvents 100

This technique is perfect for Open old logs "cold" without saturating the session and then refine the analysis with more filters if necessary.

Analyze ETW traces (.etl) and combine them with .evtx logs

The traces of Event Tracing for Windows (ETW) They are saved as .etl and write the events in order from oldest to newestTherefore, when querying with Get-WinEvent, you should always force it. -OldestOtherwise, you won't get the expected results.

Get-WinEvent -Path 'C:\Tracing\TraceLog.etl' -Oldest |
  Sort-Object TimeCreated -Descending |
  Select-Object -First 100

Here reorder in memory by TimeCreated in descending order and you keep the 100 most recent events, even if they were in the opposite direction on the disk.

You can even combine them into a single call. several files of different typesFor example, an .etl trace with an archived .evtx file, and then filtering them together by Id or any other property:

Get-WinEvent -Path 'C:\Tracing\TraceLog.etl','C:\Test\Windows PowerShell.evtx' -Oldest |
  Where-Object { $_.Id -eq 403 }

This allows you to do rapid correlation between low-level events and high-level records without having to upload each file separately to different tools.

Auditing RDP logins and connections with Get-WinEvent

One of the most typical scenarios with Get-WinEvent in security is track successful (Id 4624) and failed (Id 4625) logins in the Security registry, cross-referencing information such as user, source device, IP address and logon type (interactive, network, service, RDP…).

If you want, for example, locate all successful logins for a given user For domain controllers in the last 24 hours, a typical approach would be:

$DCs = Get-ADDomainController -Filter *
$startDate = (Get-Date).AddDays(-1)

foreach ($dc in $DCs) {
    Get-WinEvent -ComputerName $dc.HostName -FilterHashtable @{
        LogName   = 'Security'
        StartTime = $startDate
        Id        = 4624
        Data      = 'USERNAME'
    } |
    Select-Object TimeCreated, MachineName, Id, Message
}

The trick is that the data you're looking for (source IP address, remote hostname, login type, etc.) doesn't appear as direct properties, but in the EventData/XMLEvent section of the eventTo extract them cleanly and without parsing the Message text, you can convert each EventLogRecord to XML:

Get-WinEvent -FilterHashtable @{ LogName='Security'; Id=4624; StartTime=$startDate } |
ForEach-Object {
    $xml = $_.ToXml()
    @{
        TimeCreated    = $_.TimeCreated
        TargetUser     = $xml.Event.EventData.Data.'#text'   # Depende del esquema
        SourceIp       = $xml.Event.EventData.Data.'#text'  # Ejemplo típico
        SourceHostname = $xml.Event.EventData.Data.'#text'
        LogonType      = $xml.Event.EventData.Data.'#text'
        Computer       = $_.MachineName
    }
}

The specific indexes for each field in Data[] depend on the event template (Security Id 4624 in this case), but with a couple of tests in the Event Viewer or by inspecting the XML you can easily locate them. which position corresponds to IpAddress, WorkstationName, TargetUserName, LogonType, etc.

Windows Event Forwarding (WEF) and WEC Collector

When you move from one or two servers to hundreds or thousands of devices, simply running Get-WinEvent on demand is no longer enough. You need a system. centralized and scalable continuous event collectionThat role is fulfilled by Windows Event Forwarding (WEF) and the Windows Event Collector (WEC).

The idea is simple: Clients (sources) send events to the collector server based on subscriptions that you define. You can have, for example, a "baseline" subscription that applies to the entire organization and another "suspect" or target subscription that you only activate on devices that you want to monitor closely (due to incidents, forensic investigations, etc.).

  How to Manage Network Interfaces in PowerShell: A Complete, Practical, and Up-to-Date Guide

Baseline subscription vs. suspicious subscription

In practice, one usually works with two large XML queries (which you can import into the WEC):

  • Baseline subscription: the one that applies to all hosts and collects low-volume but high-value events, such as Boot and system shutdown, process creation (4688), administrative group changes, creation or modification of scheduled tasks, AppLocker usage, time changes, SMB client activity, creation/deletion of shared resources, events of malware and key events from the Security log.
  • Suspicious or targeted subscription: applies only to a subset of "marked" computers and adds high-volume or very detailed events, such as all network sessions, DNS Client/Operational, local credential validation, detailed auditing of registry changes, PowerShell events (classic and modern), 802.1xo wireless authentication load drivers in user mode.

with this model You don't overload your SEM with noise from all endpointsBut when a team "smells fishy," you can upgrade it simply by adding it to the suspicious subscription, without touching the rest of the fleet.

Scalability and data warehouse selection

Depending on the volume of events per second, you will have to choose where to store that data and what tool to use to analyze them:

  • Up to some 5.000 events/sec: a sql database or an "all-in-one" type SEM is usually sufficient.
  • Between 5.000 and 50.000 events/secThe usual approach is to use a SIEM or security event management platform (Splunk, Elastic Stack, etc.).
  • Above 50.000 events/secThe best approach is to think in terms of MapReduce / Data Lake architectures such as Hadoop, HDInsight, or equivalent platforms for long retention periods (years) and advanced analysis.

The beauty of WEF is that It does not modify event generationIt only reads and forwards them. That's why it's recommended that, as part of your baseline GPO, you already have the minimum audit directive, the appropriate log sizes and channel permissions, so that the system has been accumulating useful traces from the very first minute.

Push vs Pull, VPN and event channel security

WEF subscriptions can operate in mode push (origin-initiated) o pull (initiated by the collector)Although in practice most environments opt for push, which is simpler, scalable and easier to maintainThe client is configured via GPO, WinRM is activated, and it starts sending events to the WEC according to the subscription parameters.

The system works well with VPNRAS and DirectAccessIf a client loses connection, it accumulates events in the local log and resends them when it reconnects to the collector. The local log acts as a buffer; if the log becomes corrupted and entries are lost before being resent, the collector doesn't receive explicit notification of the loss, so it's worthwhile. expand the size of important channels.

In a domain environment, The connection between the WEF and WEC clients is encrypted using Kerberos. (with a possible fallback to NTLM if you don't disable it via GPO), regardless of whether you use HTTP or HTTPS. Only if you want pure certificate authentication (without Kerberos) will you resort to HTTPS with SSL and client certificates.

Shipping frequency and optimization options

Each subscription defines how and when are the events deliveredYou have three pre-configured options and a fourth "Custom" option that can only be adjusted with wecutil.exe:

  • Normal: prioritizes the reliability versus bandwidth savings, with batches of 5 elements and a 15-minute timeout (pull mode).
  • Minimize bandwidth: Use push mode, heartbeat every 6 hours and large batches, ideal for tight links.
  • Minimize latency: also push, but with very frequent batches (30 seconds), perfect for near real-time alerts.
  • Custom: allows you to adjust DeliveryMaxItems, DeliveryMaxLatencyTime, etc., for example by setting a batch event with a maximum latency of 10 ms.

With commands , the wecutil ss «SubscriptionName» /cm:Custom /dmi:1 /dmlt:10 You can fine-tune these options to to ensure that certain critical subscriptions deliver events almost instantly at the cost of increased traffic.

Security audit with auditpol, wevtutil
Related article:
Windows security audit using auditpol and wevtutil