- Get-WinEvent permite consultar, filtrar y combinar registros locales, remotos y archivados con gran flexibilidad.
- FilterHashtable, XPath y consultas XML optimizan el filtrado y reducen drásticamente el volumen de eventos irrelevantes.
- El reenvío de eventos de Windows (WEF/WEC) centraliza logs a gran escala mediante suscripciones de línea base y sospechosas.
- Una buena directiva de auditoría y la correcta configuración de canales son clave para obtener trazas útiles y escalables.
En muchas organizaciones, el uso de dispositivos USB, conexiones RDP, inicios de sesión interactivos y otros accesos al sistema se ha convertido en un auténtico quebradero de cabeza para los equipos de seguridad. Controlar quién se conecta, desde dónde, con qué dispositivo y en qué momento es vital para detectar intrusiones, filtrar comportamientos anómalos y cumplir con normativas cada vez más estrictas.
La buena noticia es que, si trabajas con Windows, dispones de varias piezas muy potentes para centralizar todo ese rastro: Get-WinEvent, el reenvío de eventos de Windows (WEF/WEC), consultas avanzadas XPath/XML y soluciones tipo SIEM o MapReduce. Combinando estas herramientas puedes montar desde un sistema ligero para auditar inicios de sesión de un solo usuario, hasta una arquitectura masiva capaz de ingerir decenas de miles de eventos por segundo y guardarlos durante años.
Get-WinEvent: la base para consultar el registro de eventos en Windows
El cmdlet Get-WinEvent es el sustituto moderno de Get-EventLog en sistemas Windows Vista o posteriores. A diferencia de su predecesor, permite acceder tanto a los registros “clásicos” (Application, System, Security…) como a los nuevos registros basados en la tecnología de Windows Event Log y ETW (Event Tracing for Windows), así como a archivos .evtx y .etl archivados o copiados de otros equipos.
Una de sus grandes ventajas es que admite varios modos de consulta y filtrado: por nombre de registro, por proveedor, contra archivos específicos, mediante tablas hash, usando XPath o con consultas XML completas. Además, soporta acceso remoto usando el parámetro ComputerName incluso sin PowerShell Remoting, y puede autenticarse con credenciales alternativas a través de -Credential.
Por defecto, cuando le pides eventos, los devuelve en orden de más reciente a más antiguo, aunque con el interruptor -Oldest puedes invertir ese orden, algo obligatorio cuando trabajas con trazas ETW (.etl) o determinados registros de depuración.
Sintaxis principales de Get-WinEvent
El cmdlet se organiza en varios “conjuntos de parámetros”, cada uno pensado para un escenario distinto. A grandes rasgos, las formas más habituales son:
- Get-WinEvent -LogName <String[]>: recuperar eventos desde uno o varios registros concretos.
- Get-WinEvent -ListLog <String[]>: listar la configuración de los registros disponibles.
- Get-WinEvent -ListProvider <String[]>: obtener la lista de proveedores de eventos y en qué registros escriben.
- Get-WinEvent -ProviderName <String[]>: leer eventos emitidos por uno o varios proveedores específicos.
- Get-WinEvent -Path <String[]>: trabajar directamente con archivos .evtx, .evt o .etl archivados.
- Get-WinEvent -FilterHashtable <Hashtable[]>: construir filtros potentes con pares clave-valor (LogName, Id, Level, StartTime, Data, etc.).
- Get-WinEvent -FilterXml <XmlDocument>: ejecutar consultas XML complejas generadas, por ejemplo, desde el Visor de eventos.
Todos estos conjuntos pueden combinarse con parámetros comunes como -MaxEvents (límite de resultados), -ComputerName (equipo remoto), -Credential (otra cuenta), -Force (incluir registros de depuración/análisis) o -Oldest (orden cronológico ascendente).
Ejemplos prácticos de Get-WinEvent para auditoría y seguridad
La forma más rápida de familiarizarse con Get-WinEvent es ver casos de uso reales que encajan con tareas del día a día, especialmente si te encargas de seguridad, cumplimiento o soporte de primer nivel.
Por ejemplo, puedes empezar por enumerar todos los registros existentes en un servidor para saber qué tienes disponible, y de ahí ir afinando hacia los eventos que te interesan, como inicios de sesión (Id 4624), desconexiones RDP, errores de aplicación, cambios de servicios o actividad sospechosa en USB.
Listar todos los registros del equipo (local o remoto)
Para obtener un inventario rápido de registros presentes en un host, incluyendo tamaño máximo, modo de rotación y recuento de entradas, puedes usar:
Get-WinEvent -ListLog *
Si además quieres limitarte únicamente a los registros que tienen contenido, resulta muy útil combinarlo con Where-Object filtrando la propiedad RecordCount, tanto local como remotamente con -ComputerName:
Get-WinEvent -ListLog * -ComputerName localhost | Where-Object { $_.RecordCount }
De esta forma te centras en los registros “vivos” donde realmente suceden cosas, ideal como punto de partida antes de construir consultas más específicas.
Trabajar con la configuración de un registro concreto
Cuando tienes problemas de espacio o retención de evidencias, interesa conocer y modificar la configuración de un log. Con Get-WinEvent puedes obtener un objeto EventLogConfiguration para, por ejemplo, el registro de Security:
$log = Get-WinEvent -ListLog Security
$log.MaximumSizeInBytes = 1GB
$log.SaveChanges()
Tras cambiar propiedades como MaximumSizeInBytes, LogMode o LogFilePath, conviene volver a consultar el registro con Format-List -Property * para verificar que la modificación se ha aplicado correctamente. Eso sí, necesitarás permisos de administrador, de lo contrario verás excepciones de acceso denegado.
Consultar registros desde varios servidores en paralelo
En entornos con decenas de controladores de dominio o servidores críticos, es habitual necesitar una foto homogénea del estado de un mismo registro (por ejemplo Application o Security). Como el parámetro ComputerName solo acepta un equipo por invocación, se suele tirar de un bucle foreach:
$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
}
Con este patrón, en una sola ejecución tienes datos comparables de todos los miembros del grupo y puedes detectar enseguida diferencias de tamaño, modo de rotación o crecimiento anómalo.
Explorar proveedores y tipos de eventos disponibles
Además de los registros, Get-WinEvent te permite enumerar proveedores de eventos (programas/servicios que escriben en el log) usando el parámetro -ListProvider. Esto es clave cuando quieres ver qué genera, por ejemplo, “Group Policy” o “Windows Defender”:
Get-WinEvent -ListProvider *
La salida muestra propiedades como Name, LogLinks, Opcodes, Tasks y, dentro de Events, el listado de Id y su descripción. Con algo tan sencillo como:
(Get-WinEvent -ListProvider Microsoft-Windows-GroupPolicy).Events |
Format-Table Id, Description
obtienes de golpe qué identificadores de evento genera un proveedor concreto, con un pequeño resumen de cada uno, ideal para saber qué debes recolectar vía WEF o SIEM cuando investigas una intrusión o quieres crear reglas de correlación.
Resumir el contenido de un registro por Id de evento o nivel
No siempre necesitas ver cada evento individual; muchas veces resulta más útil saber qué Id se repiten más y en qué nivel (Error, Warning, Information…). Eso puedes hacerlo cargando primero los eventos en memoria y luego agrupando:
$events = Get-WinEvent -LogName 'Windows PowerShell'
$events.Count
$events | Group-Object -Property Id -NoElement | Sort-Object Count -Descending
$events | Group-Object -Property LevelDisplayName -NoElement
Con esto obtienes un resumen muy cómodo donde ves, por ejemplo, que el Id 600 tiene 147 apariciones y que la mayoría de las entradas son de nivel Information. Es una manera rápida de detectar si hay picos de errores o avisos en un periodo determinado.
Filtrado avanzado: FilterHashtable, XPath y consultas XML
Cuando empiezas a afinar la búsqueda, Get-WinEvent brilla gracias a tres mecanismos de filtrado muy potentes: tablas hash, consultas XPath y consultas XML completas. Usarlos bien marca la diferencia entre traer millones de eventos o solo los que necesitas.
FilterHashtable: el filtro más cómodo y eficiente
El parámetro -FilterHashtable acepta una o varias tablas hash con pares clave-valor como LogName, Id, Level, StartTime, EndTime, ProviderName, UserID, Data o incluso SuppressHashFilter para excluir ciertos eventos. Lo bueno es que el filtrado se ejecuta en el propio motor de eventos, no en la tubería de PowerShell, por lo que es mucho más rápido que usar Where-Object después.
Por ejemplo, para localizar eventos de aplicación con Id 1003 de los últimos dos días:
$start = (Get-Date).AddDays(-2)
Get-WinEvent -FilterHashtable @{ LogName='Application'; StartTime=$start; Id=1003 }
Y si lo que te interesa es cazar errores de “Application Error” relacionados con iexplore.exe en la última semana:
$start = (Get-Date).AddDays(-7)
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='Application Error'
Data='iexplore.exe'
StartTime=$start
}
La variante SuppressHashFilter añade una capa interesante: puedes decirle que traiga todo menos lo que encaje con otra mini tabla hash. Por ejemplo, todos los eventos de Application de los últimos dos días excepto los de nivel 4 (Information):
$start = (Get-Date).AddDays(-2)
$filter = @{
LogName='Application'
StartTime=$start
SuppressHashFilter=@{ Level=4 }
}
Get-WinEvent -FilterHashtable $filter
Este tipo de filtro compuesto es ideal para quedarte con lo relevante (errores, avisos) sin que el ruido de la información te tape las señales.
XPath y FilterXPath: cuando necesitas precisión quirúrgica
Si vienes del mundo XML o has trasteado con el Visor de eventos, te sonará XPath. Get-WinEvent permite aplicar una expresión XPath directamente sobre el registro usando -FilterXPath combinado con LogName o ProviderName.
Un ejemplo clásico es filtrar por nivel y por ventana temporal relativa, sin tener que calcular fechas en PowerShell, sino en la propia consulta:
$xpath = '*]]'
Get-WinEvent -LogName 'Windows PowerShell' -FilterXPath $xpath
Aquí estás pidiendo eventos de nivel Warning de las últimas 24 horas (86.400.000 ms), usando la información de SystemTime del propio evento, algo muy cómodo cuando automatizas reglas de WEF.
FilterXml: consultas complejas generadas desde el Visor de eventos
Cuando la consulta se complica (varios registros, combinaciones de Select/Suppress, condiciones anidadas…), lo práctico es ir al Visor de eventos, crear una Vista personalizada con la interfaz gráfica y después copiar la pestaña XML de la consulta.
Esa cadena XML puedes reutilizarla directamente en PowerShell:
$xmlQuery = @'
<QueryList>
<Query Path="Windows PowerShell">
<Select Path="System">
*]]
</Select>
</Query>
</QueryList>
'@
Get-WinEvent -FilterXml $xmlQuery
Además, el formato XML admite elementos Suppress similares a SuppressHashFilter, que te ayudan a excluir ruido sin tocar el resto de la consulta, muy útil en suscripciones WEF complejas.
Archivos de registro archivados y trazas ETW (.evtx, .evt, .etl)
Otra baza enorme de Get-WinEvent es que no se limita a los registros activos del equipo. También puedes trabajar con archivos guardados en disco, ya sean copias de seguridad, exportaciones de otros sistemas o trazas de diagnóstico.
Leer registros .evtx guardados en disco
Si tienes, por ejemplo, una exportación del registro “Windows PowerShell” (ver historial de fiabilidad en PowerShell) en C:\Test\Windows PowerShell.evtx, basta con apuntar a ese archivo:
Get-WinEvent -Path 'C:\Test\Windows PowerShell.evtx'
La salida incluirá ProviderName, TimeCreated, Id, LevelDisplayName y Message, exactamente igual que si leyeses el registro en vivo. Desde ahí puedes aplicar filtros por Id, rango de tiempo, etc., como siempre.
Limitar el número de eventos en archivos archivados
Cuando el archivo es muy grande, conviene usar -MaxEvents para evitar traerte miles de entradas de golpe. Por ejemplo, los últimos 100 eventos de un log de PowerShellCore archivado:
Get-WinEvent -Path 'C:\Test\PowerShellCore Operational.evtx' -MaxEvents 100
Esta técnica viene de perlas para abrir “en frío” logs antiguos sin saturar la sesión y luego ir afinando el análisis con más filtros si hace falta.
Analizar trazas ETW (.etl) y combinarlas con logs .evtx
Las trazas de Event Tracing for Windows (ETW) se guardan como .etl y escriben los eventos en orden de más antiguo a más reciente. Por eso, cuando las consultas con Get-WinEvent debes forzar siempre -Oldest, o de lo contrario no obtendrás los resultados esperados.
Get-WinEvent -Path 'C:\Tracing\TraceLog.etl' -Oldest |
Sort-Object TimeCreated -Descending |
Select-Object -First 100
Aquí reordenas en memoria por TimeCreated en orden descendente y te quedas con los 100 eventos más recientes, aunque en disco estuviesen en el sentido contrario.
Incluso puedes combinar en una sola llamada varios archivos de distinto tipo, por ejemplo una traza .etl con un .evtx archivado, y luego filtrarlos juntos por Id o cualquier otra propiedad:
Get-WinEvent -Path 'C:\Tracing\TraceLog.etl','C:\Test\Windows PowerShell.evtx' -Oldest |
Where-Object { $_.Id -eq 403 }
Esto te permite hacer correlación rápida entre eventos de bajo nivel y registros de alto nivel sin tener que cargar cada archivo por separado en herramientas distintas.
Auditoría de inicios de sesión y conexiones RDP con Get-WinEvent
Uno de los escenarios más típicos con Get-WinEvent en seguridad es rastrear inicios de sesión correctos (Id 4624) y fallidos (Id 4625) en el registro de Security, cruzando información como usuario, equipo origen, IP y tipo de logon (interactivo, red, servicio, RDP…).
Si quieres, por ejemplo, localizar todos los inicios de sesión exitosos de un determinado usuario en los controladores de dominio de las últimas 24 horas, una aproximación habitual sería:
$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
}
El truco está en que los datos que buscas (dirección IP origen, nombre de host remoto, tipo de inicio de sesión…) no aparecen como propiedades directas, sino en la sección de EventData/XMLEvent del evento. Para extraerlos de forma limpia y sin parsear el texto de Message, puedes convertir cada EventLogRecord a 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
}
}
Los índices concretos de cada campo en Data[] dependen de la plantilla del evento (Security Id 4624 en este caso), pero con un par de pruebas en el Visor de eventos o inspeccionando el XML puedes localizar fácilmente qué posición corresponde a IpAddress, WorkstationName, TargetUserName, LogonType, etc.
Reenvío de eventos de Windows (WEF) y recopilador WEC
Cuando pasas de uno o dos servidores a cientos o miles de dispositivos, ya no basta con lanzar Get-WinEvent bajo demanda. Necesitas un sistema centralizado y escalable de recolección continua de eventos. Ese papel lo cumplen el reenvío de eventos de Windows (WEF) y el Windows Event Collector (WEC).
La idea es sencilla: los clientes (orígenes) envían eventos al servidor recopilador según unas suscripciones que tú defines. Puedes tener, por ejemplo, una suscripción “de línea base” que aplica a toda la organización y otra “sospechosa” o de destino que solo activas en equipos que quieres vigilar con lupa (por incidentes, investigación forense, etc.).
Suscripción de línea base vs. suscripción sospechosa
En la práctica se suele trabajar con dos grandes consultas XML (que puedes importar en el WEC):
- Suscripción de línea base: la que se aplica a todos los hosts y recoge eventos de bajo volumen pero alto valor, como arranque y apagado del sistema, creación de procesos (4688), cambios de grupos administrativos, creación o modificación de tareas programadas, uso de AppLocker, cambios de hora, actividad de cliente SMB, creación/eliminación de recursos compartidos, eventos de malware y eventos clave del registro de Security.
- Suscripción sospechosa o de destino: se aplica solo a un subconjunto de equipos “marcados” y añade eventos de alto volumen o muy detallados, como todas las sesiones de red, DNS Client/Operational, validación de credenciales locales, auditoría detallada de cambios de registro, eventos de PowerShell (clásico y moderno), autenticación inalámbrica 802.1x o carga de drivers en modo usuario.
Con este modelo no saturas tu SEM con ruido procedente de todos los endpoints, pero cuando un equipo “huele raro” puedes subirle de nivel simplemente añadiéndolo a la suscripción sospechosa, sin tocar el resto de la flota.
Escalabilidad y elección del almacén de datos
Según el volumen de eventos por segundo, tendrás que elegir dónde almacenar esos datos y qué herramienta usar para analizarlos:
- Hasta unos 5.000 eventos/seg: una base de datos SQL o un SEM tipo “todo en uno” suele bastar.
- Entre 5.000 y 50.000 eventos/seg: lo normal es tirar de un SIEM o plataforma de gestión de eventos de seguridad (Splunk, Elastic Stack, etc.).
- Por encima de 50.000 eventos/seg: lo suyo es pensar en arquitecturas MapReduce / Data Lake como Hadoop, HDInsight o plataformas equivalentes para retenciones largas (años) y análisis avanzados.
La gracia de WEF es que no modifica la generación de eventos: solo los lee y los reenvía. Por eso es recomendable que, como parte de tu GPO de línea base, tengas ya configurada la directiva de auditoría mínima, los tamaños de los logs y los permisos de canal adecuados, de forma que el sistema lleve acumulando trazas útiles desde el primer minuto.
Push vs Pull, VPN y seguridad del canal de eventos
Las suscripciones de WEF pueden funcionar en modo push (iniciadas por el origen) o pull (iniciadas por el recopilador), aunque en la práctica la mayoría de entornos optan por push, que es más simple, escalable y fácil de mantener. El cliente se configura vía GPO, se activa WinRM y empieza a enviar eventos al WEC según los parámetros de suscripción.
El sistema se lleva bien con VPN, RAS y DirectAccess: si un cliente pierde conexión, acumula eventos en el registro local y los reenvía cuando vuelve a ver al recopilador. El log local hace de “buffer”; si el registro rota y se pierden entradas antes de reenviarlas, el recopilador no recibe un aviso explícito de la pérdida, así que merece la pena ampliar el tamaño de los canales importantes.
En un entorno de dominio, la conexión entre cliente WEF y WEC va cifrada por Kerberos (con posible fallback a NTLM si no lo deshabilitas por GPO), independientemente de si usas HTTP o HTTPS. Solo si quieres autenticación por certificado puro (sin Kerberos) recurrirás a HTTPS con certificados SSL y de cliente.
Frecuencia de envío y opciones de optimización
Cada suscripción define cómo y cuándo se entregan los eventos. Tienes tres opciones preconfiguradas y una cuarta “Custom” que solo se ajusta con wecutil.exe:
- Normal: prioriza la fiabilidad frente al ahorro de ancho de banda, con lotes de 5 elementos y timeout de 15 minutos (modo pull).
- Minimizar ancho de banda: usa modo push, heartbeat cada 6 horas y lotes grandes, ideal para enlaces estrechos.
- Minimizar latencia: también push, pero con lotes muy frecuentes (30 segundos), perfecto para alertas casi en tiempo real.
- Custom: te permite ajustar DeliveryMaxItems, DeliveryMaxLatencyTime, etc., por ejemplo estableciendo un evento por lote con 10 ms de latencia máxima.
Con comandos como wecutil ss «NombreSuscripcion» /cm:Custom /dmi:1 /dmlt:10 puedes ajustar fino estas opciones para asegurar que determinadas suscripciones críticas entregan eventos casi instantáneamente a costa de un mayor tráfico.
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.
