Exportar logs y eventos en PowerShell: guía completa

Última actualización: 16/10/2025
Autor: Isaac
  • PowerShell registra su actividad en el log Windows PowerShell y permite ajustar qué se escribe con variables de preferencia.
  • Get-EventLog sirve para registros clásicos; Get-WinEvent y filtros por hashtable son la opción moderna y más eficiente.
  • Para EVTX nativo usa wevtutil epl; para datos tabulares, Select-Object y Export-Csv evitan truncados.

Exportar logs y eventos en PowerShell

Si trabajas con sistemas Windows, tarde o temprano acabarás necesitando sacar informes del registro de eventos. PowerShell es la navaja suiza para consultar, filtrar y exportar logs sin depender de clics en el Visor de eventos, y además permite automatizarlo para varios equipos a la vez.

En las próximas líneas vas a encontrar una guía práctica y a la vez muy completa, reunida a partir de referencias fiables y casos reales, para entender cómo PowerShell registra su propia actividad, cómo ver esos datos y, sobre todo, cómo exportar eventos a CSV, XML y EVTX con técnicas robustas basadas en Get-EventLog, Get-WinEvent y la utilidad wevtutil.

Cómo registra eventos PowerShell y dónde consultarlos

Windows crea un registro específico llamado Windows PowerShell para anotar la actividad del intérprete y de sus proveedores. Ese registro se puede abrir desde el Visor de eventos o desde PowerShell con cmdlets que leen eventos, como Get-EventLog.

De fábrica, el sistema escribe eventos del motor y de los proveedores, aunque es posible ajustar qué se captura gracias a variables de preferencia. También es viable añadir detalles sobre la ejecución de comandos si necesitas más granularidad para diagnóstico.

Para echar un vistazo inmediato al contenido del registro Windows PowerShell desde consola, puedes ejecutar:
Get-EventLog -LogName 'Windows PowerShell'. Luego, usa Sort-Object, Group-Object y los cmdlets de formato para ordenar, agrupar o presentar la salida de forma más legible.

Por ejemplo, para agrupar por identificador de evento tienes varias opciones útiles:
Get-EventLog 'Windows PowerShell' | Format-Table -GroupBy EventID
Get-EventLog 'Windows PowerShell' | Sort-Object EventID | Group-Object EventID. Si necesitas ver todos los registros clásicos disponibles en el equipo, ejecuta Get-EventLog -List.

Además de los cmdlets del propio registro, puedes recurrir a WMI para inspeccionar detalles de los ficheros .evt y .evtx. Con Get-WmiObject puedes consultar clases Win32 relacionadas con eventos, por ejemplo:
Get-WmiObject Win32_NTEventlogFile | Where-Object LogFileName -EQ 'Windows PowerShell' | Format-List -Property *
Get-WmiObject -List | Where-Object Name -Like 'Win32*Event*'

Elegir qué se registra: variables de preferencia

PowerShell expone seis variables de preferencia para decidir qué eventos acaban en el registro Windows PowerShell. Hay dos variables por cada ámbito de registro: motor, proveedores y comandos. Las variables LifecycleEvent anotan eventos normales de inicio y fin; las variables Health registran errores.

Variable Qué registra
$LogEngineLifecycleEvent Arranque y parada del motor de PowerShell
$LogEngineHealthEvent Errores del programa de PowerShell
$LogProviderLifecycleEvent Inicio y fin de proveedores de PowerShell
$LogProviderHealthEvent Errores de proveedores de PowerShell
$LogCommandLifecycleEvent Inicio y finalización de comandos
$LogCommandHealthEvent Errores de comandos

Por defecto vienen activados los siguientes tipos: $LogEngineLifecycleEvent, $LogEngineHealthEvent, $LogProviderLifecycleEvent y $LogProviderHealthEvent. Para activar o desactivar cualquier tipo basta con asignar $true o $false a la variable correspondiente en la sesión actual:

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

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

Ojo: hay ciertos eventos que no se pueden desactivar, como los que indican que el motor de PowerShell o los proveedores principales han arrancado. Se generan antes de cargar perfiles y de que el host acepte comandos, de ahí que no dependan de tu configuración. Si quieres que estos ajustes apliquen siempre, añade las asignaciones a tu perfil de PowerShell.

  Repair: Webcam is Being Used By One other Software Error in Home windows 10

Registro de ejecución en módulos y complementos

Desde PowerShell 3.0, los módulos y complementos pueden registrar la ejecución de funciones y cmdlets estableciendo su propiedad LogPipelineExecutionDetails a $true. En PowerShell 2.0 esta característica solo está disponible para complementos, pero en versiones modernas se aplica también a módulos.

Cuando LogPipelineExecutionDetails vale $true, PowerShell escribe eventos de ejecución de la sesión en el registro Windows PowerShell del Visor de eventos. El cambio afecta únicamente a la sesión actual, salvo que lo fuerces por directiva.

# 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

También puedes activar o desactivar este registro por directiva de grupo usando la configuración Activar registro de módulos. La directiva permite listar nombres de módulos y complementos, con comodines. Cuando la directiva fuerza el registro para un módulo, su propiedad LogPipelineExecutionDetails queda en $true para todas las sesiones y no se puede cambiar a mano.

Rutas de directiva de grupo para esta configuración:
Computer Configuration\ Administrative Templates\ Windows Components\ Windows PowerShell
User Configuration\ Administrative Templates\ Windows Components\ Windows PowerShell. La política de usuario tiene prioridad sobre la de equipo, y ambas prevalecen sobre el valor de la propiedad en módulos y complementos.

Sobre seguridad y auditoría

El registro Windows PowerShell está pensado para dar visibilidad operativa y ayudar en el diagnóstico. No es un registro diseñado para ser seguro ni para albergar datos sensibles. Igual que otros registros de aplicaciones en Windows, su objetivo es ser legible y útil para usuarios.

En muchos entornos los usuarios pueden leer y escribir en los registros de eventos. Un usuario malintencionado podría leer eventos en equipos locales o remotos, inyectar entradas falsas e incluso interferir con la propia escritura. Para requisitos de auditoría estrictos hay que apoyarse en controles adicionales y canalizaciones seguras de eventos.

Get-EventLog: sintaxis, parámetros y ejemplos imprescindibles

El cmdlet Get-EventLog obtiene eventos y registros de equipos locales o remotos. Por defecto consulta el equipo local, pero con -ComputerName puedes apuntar a otros equipos sin necesidad de tener remoting de PowerShell habilitado. Importante: Get-EventLog opera solo sobre registros clásicos como Application, System o Security; para los canales modernos usa Get-WinEvent.

Un apunte de compatibilidad que conviene recordar: Get-EventLog y Get-WinEvent no se admiten en Windows PE. Si trabajas con entornos de preinstalación, tendrás que buscar alternativas.

Ejemplos prácticos para el día a día con Get-EventLog:
Listar registros disponibles
Get-EventLog -List

Últimos 5 eventos del registro System
Get-EventLog -LogName System -Newest 5

Top de orígenes entre los 1000 eventos más recientes
$events = Get-EventLog -LogName System -Newest 1000
$events | Group-Object -Property Source -NoElement | Sort-Object Count -Descending

Solo errores en System
Get-EventLog -LogName System -EntryType Error

Filtrar por InstanceId y Source
Get-EventLog -LogName System -InstanceId 10016 -Source DCOM

Consultar varios equipos a la vez
Get-EventLog -LogName System -ComputerName Server01,Server02,Server03. Recuerda que -ComputerName admite NetBIOS, IP o FQDN, y también un punto para el local.

Buscar por texto en el mensaje
Get-EventLog -LogName System -Message *description*

Ver todas las propiedades de un evento
$a = Get-EventLog -LogName System -Newest 1
$a | Select-Object -Property *

Filtrar por origen y EventID, y mostrar campos concretos
Get-EventLog -LogName Application -Source Outlook | Where-Object { $_.EventID -eq 63 } | Select-Object Source,EventID,InstanceId,Message

Agrupar por usuario
Get-EventLog -LogName System -UserName 'NT*' | Group-Object UserName -NoElement | Select-Object Count,Name

Filtrar por intervalo de tiempo
$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. Los parámetros -After y -Before acotan el rango temporal pero no aparecen en la salida.

  La cámara no puede establecer la conexión

Parámetros clave y detalles útiles que conviene retener:
-LogName (obligatorio) admite comodines; -List muestra los registros disponibles; -ComputerName acepta nombre NetBIOS, IP o FQDN; -Newest devuelve N eventos recientes; -EntryType filtra por Error, Information, FailureAudit, SuccessAudit o Warning; -UserName y -Source aceptan comodines; -Message filtra por texto; -InstanceId y -Index aceptan listas separadas por comas; -After y -Before reciben DateTime; -AsBaseObject devuelve objetos System.Diagnostics.EventLogEntry; -AsString devuelve cadenas en el conjunto de -List

Get-WinEvent frente a Get-EventLog

Get-WinEvent es el cmdlet moderno para tratar con los registros basados en la tecnología Windows Event Log introducida a partir de Windows Vista. Admite canales modernos, consultas XML XPath, filtros por hashtable y mejor rendimiento con volúmenes grandes.

Mientras Get-EventLog queda para los logs clásicos, Get-WinEvent se recomienda para escenarios actuales. Un filtro típico por rango de fechas y log podría ser:
Get-WinEvent -FilterHashtable @{ LogName = 'System'; StartTime = (Get-Date).AddDays(-30) }

La gran baza de Get-WinEvent está en las consultas avanzadas (XPath o FilterHashtable), además de la capacidad de leer suscripciones y logs personalizados. Si necesitas exportar a CSV o XML, puedes canalizar a Select-Object y a Export-Csv o Export-Clixml para tener estructuras limpias y consumibles.

Exportar eventos a CSV, XML y EVTX sin perder datos

Un problema habitual al volcar eventos a fichero es usar Format-Table seguido de Out-File: Format-Table da salida pensada para pantalla y puede truncar columnas o cortar mensajes. Si quieres exportar datos, utiliza Select-Object y Export-Csv para obtener columnas completas.

Ejemplo de exportación a CSV de los últimos 7 días del registro Security, con columnas elegidas y sin pérdidas:
$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. Si aun así quieres texto plano, mejor usa Out-String con un ancho amplio y luego Set-Content para evitar cortes.

# 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'

Si tu objetivo es un archivo .evtx nativo, no intentes crearlo con Out-File o redirecciones: los .evtx solo los genera el subsistema de eventos de Windows. La herramienta soportada para exportar a .evtx es wevtutil con la opción epl.

Exportar los últimos 30 días a .evtx para System, Security, Setup y Application con una carpeta por equipo, creando el directorio si no existe:
$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. La consulta XPath usa timediff para filtrar los últimos 30 días en milisegundos.

Otro patrón muy práctico es recorrer un conjunto de logs y construir el nombre del fichero con servidor y marca de tiempo. Con un pequeño temporizador visualizas el tiempo total de proceso si exportas grandes volúmenes:

$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))

Si trabajas con varios equipos a la vez y quieres generar CSV por máquina, lee una lista de activos y aplica un filtro temporal. Evita el patrón Format-Table | Out-File para exportar datos, utiliza Select-Object y Export-Csv con codificación UTF-8.

$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'

Solución de problemas al exportar logs

Ficheros .evtx corruptos: suele ocurrir cuando alguien intenta usar Out-File para crear un .evtx. Un .evtx no es texto plano, solo wevtutil epl genera archivos válidos. Repite la exportación con la utilidad correcta.

  ¿Cómo puedes bañarte en el mar con tu Aquatic Smartwatch sin dañarlo permanentemente?

Datos cortados en CSV o TXT: la causa es casi siempre Formatear antes de exportar, por ejemplo con Format-Table. La regla de oro es seleccionar propiedades con Select-Object y exportar con Export-Csv. Si necesitas una tabla legible, apóyate en -Wrap y controla el ancho con Out-String -Width 4096.

Permisos insuficientes en el registro Security: para leer eventos de seguridad en equipos remotos o locales hace falta pertenecer a grupos con privilegios (por ejemplo, Administradores del equipo). Si Get-EventLog o Get-WinEvent devuelven acceso denegado, revisa membresías y directivas.

Rendimiento: filtra siempre en origen con -FilterHashtable cuando uses Get-WinEvent. Evita traer todo y filtrar con Where-Object después, especialmente en logs ruidosos como Security. Para Get-EventLog, usa -Newest y parámetros de filtro nativos.

Entornos Windows PE: no están soportados por Get-EventLog ni Get-WinEvent. Si estás en preinstalación, considera herramientas específicas o recolecta tras el despliegue en el sistema completo.

Recetas rápidas de consulta

Listar todos los registros clásicos disponibles
Get-EventLog -List

Contar eventos por tipo en System
Get-EventLog -LogName System | Group-Object EntryType -NoElement | Sort-Object Count -Desc

Buscar eventos con una palabra clave en el mensaje
Get-EventLog -LogName Application -Message *timeout*

Eventos de varios equipos en paralelo
'Srv01','Srv02','Srv03' | ForEach-Object { Get-EventLog -LogName System -ComputerName $_ -Newest 100 }. Añade Select-Object para controlar columnas y Export-Csv para persistir los resultados en disco.

Con todo lo anterior ya tienes criterio para elegir herramienta y técnica: Get-EventLog para lo clásico, Get-WinEvent para lo moderno y wevtutil cuando quieras EVTX. Usando filtros en origen, seleccionando propiedades antes de exportar y evitando dar formato previo a la salida, conseguirás exportaciones fiables, completas y rápidas tanto en local como en remoto, y podrás programarlas con tareas para que no tengas que volver a preocuparte cada mes.

comando Get-WinEvent de powershell
Artículo relacionado:
Cómo usar el comando Get-WinEvent en PowerShell