Exporting logs and events in PowerShell: a complete guide

Last update: 16/10/2025
Author Isaac
  • PowerShell records your activity in the log Windows PowerShell and allows you to adjust what is written with preference variables.
  • Get-EventLog is good for classic logs; Get-WinEvent and hashtable filters are the modern, more efficient option.
  • For native EVTX, use wevtutil epl; for tabular data, Select-Object and Export-Csv prevent truncation.

Export logs and events in PowerShell

If you work with Windows systems, sooner or later you will end up needing to retrieve reports from the event log. PowerShell is the Swiss Army knife for querying, filtering, and exporting logs. without relying on clicks in the Event Viewer, and also allows you to automate it for multiple computers at once.

In the following lines you will find a practical and very complete guide, compiled from reliable references and real cases, to understand how PowerShell records its own activity, how to view that data and, above all, How to export events to CSV, XML, and EVTX with robust techniques based on Get-EventLog, Get-WinEvent and the wevtutil utility.

How PowerShell logs events and where to view them

Windows creates a specific log called Windows PowerShell to record the activity of the interpreter and its providers. This log can be opened from Event Viewer or from PowerShell. with cmdlets that read events, such as Get-EventLog.

By default, the system writes engine and vendor events, although you can adjust what is captured using preference variables. It is also feasible to add details about the execution of commands if you need more granularity for diagnosis.

To take an immediate look at the contents of the Windows PowerShell registry from the console, you can run:
Get-EventLog -LogName 'Windows PowerShell'. Then, use Sort-Object, Group-Object, and the formatting cmdlets to sort, group, or present the output in a more readable manner.

For example, to group by event ID you have several useful options:
Get-EventLog 'Windows PowerShell' | Format-Table -GroupBy EventID
Get-EventLog 'Windows PowerShell' | Sort-Object EventID | Group-Object EventID. If you need to see all available classic records on the team, run Get-EventLog -List.

In addition to the registry cmdlets, you can use WMI to inspect details of .evt and .evtx files. With Get-WmiObject you can query Win32 classes related to events, For example:
Get-WmiObject Win32_NTEventlogFile | Where-Object LogFileName -EQ 'Windows PowerShell' | Format-List -Property *
Get-WmiObject -List | Where-Object Name -Like 'Win32*Event*'

Choosing what to record: preference variables

PowerShell exposes six preference variables to decide which events end up in the Windows PowerShell log. There are two variables per record scope: engine, providers, and commands. LifecycleEvent variables record normal start and end events; Health variables record errors.

Variable What it records
$LogEngineLifecycleEvent start and stop the PowerShell engine
$LogEngineHealthEvent PowerShell Program Errors
$LogProviderLifecycleEvent Starting and ending PowerShell providers
$LogProviderHealthEvent PowerShell Provider Errors
$LogCommandLifecycleEvent Starting and ending commands
$LogCommandHealthEvent Command errors

The following types are activated by default: $LogEngineLifecycleEvent, $LogEngineHealthEvent, $LogProviderLifecycleEvent y $LogProviderHealthEvent. To activate or deactivate any type just assign $true o $false to the corresponding variable in the current session:

# Activar eventos de ciclo de vida de comandos
$LogCommandLifecycleEvent = $true

# Desactivar eventos de ciclo de vida de proveedores
$LogProviderLifecycleEvent = $false

Note: There are certain events that cannot be disabled, such as those indicating that the PowerShell engine or core providers have started. They are generated before profiles are loaded and the host accepts commands., so they don't depend on your configuration. If you want these settings to always apply, add the mappings to your PowerShell profile.

  How to improve system security with secpol.msc

Execution logging in modules and plugins

Since PowerShell 3.0, modules and snap-ins can log the execution of functions and cmdlets by setting their LogPipelineExecutionDetails property to $true. In PowerShell 2.0 this feature is only available for snap-ins., but in modern versions it also applies to modules.

When LogPipelineExecutionDetails is valid $true, PowerShell writes session execution events to the Windows PowerShell log in Event Viewer. The change affects only the current session., unless you force it by directive.

# Módulos
Import-Module Microsoft.PowerShell.Archive
$m = Get-Module Microsoft.PowerShell.Archive
$m.LogPipelineExecutionDetails = $true

# Complementos (PSSnapin)
$m = Get-PSSnapin Microsoft.PowerShell.Core
$m.LogPipelineExecutionDetails = $true

You can also enable or disable this logging by group policy using the Enable Module Logging setting. The directive allows you to list module and plugin names, with wildcards. When the directive forces logging for a module, its LogPipelineExecutionDetails property is set to $true for all sessions and cannot be changed manually.

Group Policy paths for this configuration:
Computer Configuration\ Administrative Templates\ Windows Components\ Windows PowerShell
User Configuration\ Administrative Templates\ Windows Components\ Windows PowerShell. User policy takes precedence over computer policy, and both override the property value in modules and plugins.

On security and auditing

Windows PowerShell logging is intended to provide operational visibility and aid in diagnostics. It is not a record designed to be secure nor to store sensitive data. Like other application logs in Windows, its purpose is to be readable and useful to users.

In many environments, users can read and write to event logs. A malicious user could read events on local or remote computers, inject fake input, and even interfere with the writing itself.. For strict audit requirements, additional controls must be used and secure event channels.

Get-EventLog: Syntax, Parameters, and Essential Examples

The Get-EventLog cmdlet retrieves events and logs from local or remote computers. By default it queries the local computer, but with -ComputerName you can target other computers. without having PowerShell remoting enabled. Important: Get-EventLog only works on classic logs like Application, System, or Security; for modern channels, use Get-WinEvent.

A compatibility note to remember: Get-EventLog and Get-WinEvent are not supported in Windows PEIf you're working with pre-installation environments, you'll need to look for alternatives.

Practical examples for everyday use with Get-EventLog:
List available records
Get-EventLog -List

Last 5 events from the System log
Get-EventLog -LogName System -Newest 5

Top origins among the 1000 most recent events
$events = Get-EventLog -LogName System -Newest 1000
$events | Group-Object -Property Source -NoElement | Sort-Object Count -Descending

Only errors in System
Get-EventLog -LogName System -EntryType Error

Filter by InstanceId and Source
Get-EventLog -LogName System -InstanceId 10016 -Source DCOM

Consult multiple devices at once
Get-EventLog -LogName System -ComputerName Server01,Server02,Server03. Remember that -ComputerName supports NetBIOS, IP or FQDN, and also a point for the home team.

Search by text in the message
Get-EventLog -LogName System -Message *description*

View all properties of an event
$a = Get-EventLog -LogName System -Newest 1
$a | Select-Object -Property *

Filter by source and EventID, and display specific fields
Get-EventLog -LogName Application -Source Outlook | Where-Object { $_.EventID -eq 63 } | Select-Object Source,EventID,InstanceId,Message

Group by user
Get-EventLog -LogName System -UserName 'NT*' | Group-Object UserName -NoElement | Select-Object Count,Name

Filter by time range
$begin = Get-Date -Date '01/17/2019 08:00:00'
$end = Get-Date -Date '01/17/2019 17:00:00'
Get-EventLog -LogName System -EntryType Error -After $begin -Before $end. The -After and -Before parameters limit the time range but they do not appear in the output.

  The right way to Cease Apps From Working in Background in Home windows 10

Key parameters and useful details to remember:
-LogName (required) supports wildcards; -List displays available records; -ComputerName accepts NetBIOS name, IP or FQDN; -Newest returns N recent events; -EntryType filter by Error, Information, FailureAudit, SuccessAudit or Warning; -UserName y -Source accept wild cards; -Message filter by text; -InstanceId y -Index accept comma-separated lists; -After y -Before receive DateTime; -AsBaseObject returns System.Diagnostics.EventLogEntry objects; -AsString returns strings in the set of -List

Get-WinEvent vs. Get-EventLog

Get-WinEvent is the modern cmdlet for dealing with logs based on the Windows Event Log technology introduced since Windows Vista. Supports modern channels, XML XPath queries, hashtable filters and better performance with large volumes.

While Get-EventLog is left to the logs classics, Get-WinEvent is recommended for current scenarios. A typical filter by date range and log could be:
Get-WinEvent -FilterHashtable @{ LogName = 'System'; StartTime = (Get-Date).AddDays(-30) }

The great advantage of Get-WinEvent is its advanced queries (XPath or FilterHashtable), as well as the ability to read custom subscriptions and logs. If you need to export to CSV or XML, you can pipe to Select-Object and Export-Csv or Export-Clixml to have clean and consumable structures.

Export events to CSV, XML, and EVTX without losing data

A common problem when outputting events to a file is using Format-Table followed by Out-File: Format-Table gives output intended for screen and can truncate columns or cut messagesIf you want to export data, use Select-Object and Export-Csv to get complete columns.

Example of CSV export of the last 7 days of the Security log, with columns selected and no loss:
$desde = (Get-Date).AddDays(-7)
Get-WinEvent -FilterHashtable @{ LogName = 'Security'; StartTime = $desde } |
Select-Object TimeCreated,Id,LevelDisplayName,ProviderName,Message,UserId,MachineName |
Export-Csv -Path 'C:\temp\security-ultimos7dias.csv' -NoTypeInformation -Encoding UTF8. If you still want plain text, better use Out-String with a wide width and then Set-Content to avoid cuts.

# Alternativa a TXT sin truncado
a) Salida de tabla legible en archivo
Get-EventLog -LogName System -Newest 200 |
  Format-Table TimeGenerated,EntryType,Source,EventID,Message -Wrap |
  Out-String -Width 4096 |
  Set-Content -Path 'C:\temp\system-200.txt' -Encoding UTF8

b) Exportación a XML de objetos (no .evtx)
Get-WinEvent -LogName Application -MaxEvents 500 |
  Export-Clixml -Path 'C:\temp\application-500.xml'

If your goal is a native .evtx file, do not try to create it with Out-File or redirects: .evtx files are only generated by the Windows event subsystemThe supported tool for exporting to .evtx is wevtutil with the epl option.

Export the last 30 days to .evtx for System, Security, Setup, and Application with one folder per computer, creating the directory if it doesn't exist:
$computer = $env:COMPUTERNAME
$exportDir = ::Combine($env:PUBLIC, 'Desktop\AuditLogs-' + $computer)
if (-not (Test-Path $exportDir)) { New-Item -ItemType Directory -Path $exportDir | Out-Null }
$stamp = Get-Date -Format 'MM-dd-yyyy_HHmm'
wevtutil.exe epl System "$exportDir\$stamp`_SystemLog30days.evtx" '/q:*]]' /ow:true
wevtutil.exe epl Security "$exportDir\$stamp`_SecurityLog30days.evtx" '/q:*]]' /ow:true
wevtutil.exe epl Setup "$exportDir\$stamp`_SetupLog30days.evtx" '/q:*]]' /ow:true
wevtutil.exe epl Application "$exportDir\$stamp`_ApplicationLog30days.evtx" '/q:*]]' /ow:true. The XPath query uses timediff to filter the last 30 days in milliseconds.

Another very practical pattern is to iterate through a set of logs and construct the file name with the server and timestamp. With a small timer you visualize There total process If you export large volumes:

$logArray = @('System','Security','Application','Setup')
$server   = $env:COMPUTERNAME
$path     = 'C:\WindowsEventLogs\'
if ($path -notmatch '.+?\\$') { $path += '\' }
if (-not (Test-Path -Path $path)) { New-Item -ItemType Directory -Path $path | Out-Null }
$tag      = Get-Date -Format 'yyyyMMddHHmm'
$sw       = ::StartNew()
foreach ($log in $logArray) {
  $dest = $path + $server + '-' + $log + '-' + $tag + '.evtx'
  Write-Host ('Extrayendo el log {0}' -f $log)
  wevtutil epl $log $dest
  # Para limpiar tras exportar: wevtutil cl $log
}
$sw.Stop(); '{0} segundos' -f (::Round($sw.Elapsed.TotalSeconds,2))

If you're working with multiple machines at once and want to generate CSVs per machine, read a list of assets and apply a time filter. Avoid the Format-Table | Out-File pattern when exporting data, use Select-Object and Export-Csv with UTF-8 encoding.

$assetList = Get-Content -Path 'C:\temp\assetlist.txt'
$desde     = (Get-Date).AddDays(-7)
foreach ($pc in $assetList) {
  $dest = "C:\\temp\\$pc-security-7dias.csv"
  Get-WinEvent -ComputerName $pc -FilterHashtable @{ LogName='Security'; StartTime=$desde } |
    Select-Object TimeCreated,Id,LevelDisplayName,ProviderName,Message,UserId,MachineName |
    Export-Csv -Path $dest -NoTypeInformation -Encoding UTF8
}
Write-Host 'Exportación completada'

Troubleshooting log exports

Corrupt .evtx files: This usually occurs when someone tries to use Out-File to create a .evtx. A .evtx is not plain text, only wevtutil epl generates valid files. Repeat the export with the correct utility.

  Differences between .cmd and .bat files in Windows

Data cut off in CSV or TXT: the cause is almost always Format before exporting, for example with Format-Table. The golden rule is to select properties with Select-Object and export with Export-CsvIf you need a legible table, rely on -Wrap and control the width with Out-String -Width 4096.

Insufficient permissions in the Security log: Reading security events on remote or local computers requires membership in privileged groups (for example, Computer Administrators). If Get-EventLog or Get-WinEvent returns access denied, review memberships and directives.

Performance: Always filter at the source with -FilterHashtable when using Get-WinEvent. Avoid fetching everything and filtering with Where-Object afterwards, especially for noisy logs like Security. For Get-EventLog, use -Newest and native filter parameters.

Windows PE environments: Not supported by Get-EventLog and Get-WinEvent. If you are in pre-deployment, consider specific tools or collect after deployment in the entire system.

Quick reference recipes

List all available classic records
Get-EventLog -List

Count events by type in System
Get-EventLog -LogName System | Group-Object EntryType -NoElement | Sort-Object Count -Desc

Search for events with a keyword in the message
Get-EventLog -LogName Application -Message *timeout*

Multi-team events in parallel
'Srv01','Srv02','Srv03' | ForEach-Object { Get-EventLog -LogName System -ComputerName $_ -Newest 100 }. Add Select-Object to control columns and Export-Csv to persist the results on disk.

With all of the above you now have the criteria to choose the tool and technique: Get-EventLog for classic, Get-WinEvent for modern, and wevtutil when you want EVTX. By using filters at source, selecting properties before exporting, and avoiding pre-formatting before output, you will achieve reliable, complete, and fast exports both locally and remotely, and you will be able to schedule them with tasks so you don't have to worry about it every month.

powershell Get-WinEvent command
Related article:
How to use the Get-WinEvent command in PowerShell