- 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.
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.
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.
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.
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.
Redactor apasionado del mundo de los bytes y la tecnología en general. Me encanta compartir mis conocimientos a través de la escritura, y eso es lo que haré en este blog, mostrarte todo lo más interesante sobre gadgets, software, hardware, tendencias tecnológicas, y más. Mi objetivo es ayudarte a navegar por el mundo digital de forma sencilla y entretenida.