Investigar el registro de eventos con Get-WinEvent de forma práctica — la velocidad del filtrado determina el tiempo de investigación
· Actualizado el: · Go Komura · PowerShell, Windows, Registro de eventos, Investigación de fallos, Mejora operativa, Sistemas de información, Auditoría, Resolución de problemas
«Parece que el servidor se reinició solo la madrugada del viernes pasado» o «solo en un equipo concreto, la aplicación de negocio se cierra varias veces al mes» — casi siempre el punto de partida de este tipo de investigaciones es el registro de eventos de Windows. Sin embargo, si se recorre con el Visor de eventos (Event Viewer) un registro de cientos de miles de entradas desplazándose por la interfaz gráfica, solo eso se lleva toda una mañana.
Con el cmdlet Get-WinEvent de PowerShell, este trabajo se resuelve en cuestión de segundos. Pero hay una condición: hay que filtrar en el lugar correcto. Si se escribe Get-WinEvent | Where-Object { ... }, se termina cargando todos los eventos antes de descartarlos, lo que puede resultar incluso más lento que la interfaz gráfica.
En este artículo se explica cómo usar correctamente el filtrado de Get-WinEvent, se presentan recetas para las investigaciones más habituales en el día a día (reinicios inesperados, inicios de sesión, cierres anómalos de aplicaciones, detención de servicios) y se cubre también la recolección desde varios equipos.
Entorno de referencia
| Elemento | Contenido |
|---|---|
| Sistema operativo objetivo | Windows 10/11, Windows Server. Get-WinEvent lee sobre la infraestructura de registro de eventos de Windows Vista en adelante, y puede manejar tanto los registros clásicos como los registros de ETW1 |
| Versión de PowerShell | Se puede usar tanto con Windows PowerShell 5.1 como con PowerShell 7 (Get-WinEvent es un cmdlet exclusivo de Windows, no disponible en PowerShell 7 sobre Linux o macOS). El código de este artículo está escrito para funcionar tanto en 5.1 como en 71 |
| Permisos | Muchos registros, como System o Application, se pueden leer con una cuenta de usuario normal, pero la lectura del registro Security requiere permisos de administrador o un permiso equivalente concedido de forma explícita. Hay registros de los que no se puede obtener información si no se ejecuta como administrador (el capítulo 4 (2) detalla el procedimiento para conceder permisos)12 |
| Recolección remota | El método 1 del capítulo 5 (-ComputerName) no depende de PowerShell Remoting (WinRM). En su lugar, es necesario permitir en el firewall del equipo de destino el acceso remoto al servicio de registro de eventos. El método 2 (Invoke-Command) sí requiere WinRM1 |
1. La conclusión primero
- Use
Get-WinEvent, noGet-EventLog. El primero es exclusivo de Windows PowerShell y solo cubre los registros clásicos; no está disponible en PowerShell 7.1 - El filtrado se hace con
-FilterHashtable. Como el filtrado ocurre en el propio registro de eventos, resulta órdenes de magnitud más rápido que filtrar después conWhere-Object.3 - Las claves de
-FilterHashtableestán predefinidas.LogName,ProviderName,ID,Level,StartTime,EndTime,Keywords,Path,UserID, entre otras.3 - Para condiciones complejas o filtrado por datos del evento, use XPath (
-FilterXPath). El XPath se puede copiar desde las «Vistas personalizadas» del Visor de eventos.1 Leveles un valor numérico. 1 = crítico, 2 = error, 3 = advertencia, 4 = información, 5 = detallado.4- La lectura del registro de seguridad exige permisos especiales. Ejecutar como administrador es lo más sencillo, pero para el personal de investigación resulta más acorde al mínimo privilegio conceder solo lectura mediante el grupo «Event Log Readers» o la ACL del canal.12
- Consulte los datos del evento, no la cadena del mensaje. Al obtener los datos estructurados con
ToXml(), el script deja de depender de la configuración de idioma del sistema operativo.1 - También se pueden analizar archivos
.evtx. Indicando-Pathes posible examinar localmente registros recogidos en sitio.1 - Para una recopilación permanente, use el reenvío de eventos de Windows (WEF). Para una investigación puntual, basta con la ejecución en paralelo mediante
Invoke-Command.5
2. Dos tipos de registro y la elección del cmdlet
Los registros de eventos de Windows se dividen a grandes rasgos en dos familias.
| Tipo | Ejemplo | Cmdlet que puede leerlo |
|---|---|---|
| Registro clásico | System / Application / Security | Get-EventLog (solo 5.1) · Get-WinEvent |
| Registro de aplicaciones y servicios | Microsoft-Windows-TaskScheduler/Operational, entre otros |
Solo Get-WinEvent |
Precisamente en el segundo grupo es donde se encuentra la información más útil para investigar. El historial de ejecución del Programador de tareas (Task Scheduler), el registro de bloques de script de PowerShell, el historial de aplicación de Windows Update: buena parte de los registros que resultan decisivos para determinar la causa de un problema están en este lado. Por lo tanto, lo correcto es unificar a partir de ahora todos los scripts en torno a Get-WinEvent.1
Primero comprobamos qué registros existen.
# Listado de registros (ordenado por número de eventos). Los registros con RecordCount 0 no tienen entradas
Get-WinEvent -ListLog * -ErrorAction SilentlyContinue |
Where-Object RecordCount -gt 0 |
Sort-Object RecordCount -Descending |
Select-Object LogName, RecordCount, MaximumSizeInBytes, IsEnabled -First 20
# Buscar el registro de un producto concreto
Get-WinEvent -ListLog *TaskScheduler* | Format-Table LogName, IsEnabled, RecordCount
Get-WinEvent -ListProvider *PowerShell* | Select-Object Name
3. El filtrado depende por completo de «dónde» se realice
Comparemos tres formas de escribir que obtienen el mismo resultado.
# 【Lo peor】Se cargan todos los eventos y se descartan luego en PowerShell
Get-WinEvent -LogName System | Where-Object { $_.Id -eq 41 }
# 【Recomendado】Se filtra en el propio registro de eventos (FilterHashtable)
Get-WinEvent -FilterHashtable @{ LogName = 'System'; ID = 41 }
# 【Condiciones complejas】Se filtra con XPath
Get-WinEvent -LogName System -FilterXPath "*[System[EventID=41]]"
La primera opción convierte en objetos cientos de miles de eventos para luego descartarlos, de modo que la mayor parte del tiempo de espera se desperdicia. La segunda y la tercera filtran en el lado de la API del registro de eventos, así que solo se devuelve lo necesario.3
Las claves que admite -FilterHashtable están predefinidas.3
| Clave | Qué se indica | Ejemplo |
|---|---|---|
LogName |
Nombre del registro | 'System', 'Microsoft-Windows-TaskScheduler/Operational' |
ProviderName |
Origen del evento | 'Application Error', 'Service Control Manager' |
ID |
ID de evento (admite un arreglo) | 41, @(1000, 1001) |
Level |
Gravedad (numérica) | 2 (error), @(1,2) |
StartTime / EndTime |
Período | (Get-Date).AddDays(-7) |
Keywords |
Palabra clave (éxito/fallo de auditoría, etc.) | 9007199254740992 (auditoría con éxito) |
Path |
Archivo .evtx |
'D:\collect\srv01_System.evtx' |
UserID |
SID de usuario | 'S-1-5-21-...' |
Los valores numéricos de Level son los siguientes.4
Valor (Level) |
Texto mostrado en español | Texto mostrado en inglés |
|---|---|---|
| 1 | Crítico | Critical |
| 2 | Error | Error |
| 3 | Advertencia | Warning |
| 4 | Información | Information |
| 5 | Detallado | Verbose |
Las dos columnas de la derecha son el texto que aparece en la columna «Nivel» del Visor de eventos y en la propiedad LevelDisplayName del resultado de Get-WinEvent. LevelDisplayName cambia según el idioma de visualización del sistema operativo. Use esta tabla de equivalencias cuando compare la salida a simple vista, y al filtrar mediante script, indique siempre el Level numérico (si se filtra por el nombre mostrado, el script dejará de funcionar en un entorno en inglés).
En una forma práctica, queda así.
# Agrupa por origen los eventos de error y críticos de los últimos 7 días (primer paso para tomar una foto de la situación)
$filter = @{
LogName = 'System', 'Application'
Level = 1, 2
StartTime = (Get-Date).AddDays(-7)
}
try {
Get-WinEvent -FilterHashtable $filter -ErrorAction Stop |
Group-Object ProviderName, Id |
Sort-Object Count -Descending |
Select-Object Count, Name -First 15
}
catch {
# Deja pasar en silencio solo el caso de "ningún evento coincidente". No depende de la configuración regional
# Se decide por FullyQualifiedErrorId (la cadena del mensaje no coincide en un entorno en español)
if ($_.FullyQualifiedErrorId -notlike 'NoMatchingEventsFound*') { throw }
}
Cómo leer el resultado. La salida de Group-Object tiene dos columnas, Count y Name. Como se agrupa por varias propiedades a la vez (ProviderName, Id), en Name aparecen «origen, ID de evento» separados por comas (por ejemplo, Service Control Manager, 7034). Como están ordenados de mayor a menor cantidad, lo primero que conviene revisar es si en las primeras filas aparece algún origen que no reconoce y si hay un pico de cantidad que coincida con la franja horaria en la que ocurrió el problema. Una vez que tiene una pista aquí, puede profundizar en eventos concretos con las recetas del siguiente capítulo.
Cuando no hay ningún evento que coincida, Get-WinEvent genera un error. No agregue a la ligera -ErrorAction SilentlyContinue en este punto. «No hay coincidencias», «no tengo permiso para leer ese registro» y «no puedo llegar al destino» terminan produciendo el mismo “resultado vacío”. En el contexto de una investigación, este es el peor tipo de fallo silencioso.
Lo correcto, como en el ejemplo anterior, es capturar el error con -ErrorAction Stop y descartarlo únicamente cuando FullyQualifiedErrorId sea NoMatchingEventsFound. Si se evalúa por la cadena del mensaje, en un entorno en español no coincidirá y el filtro no funcionará (para el enfoque general del manejo de errores, véase «Manejo de errores y diseño de reintentos en PowerShell»).
4. Recetas de investigación habituales en el día a día
(1) Reinicios y apagados inesperados
# 41: reinicio sin apagado limpio previo (Kernel-Power)
# 6008: apagado inesperado (EventLog)
# 1074: solicitud de apagado por un proceso o usuario (quién o qué lo apagó)
# 6005/6006: inicio/detención del servicio de registro de eventos (= marca de arranque/parada)
Get-WinEvent -FilterHashtable @{
LogName = 'System'
ID = 41, 1074, 6005, 6006, 6008
StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, ProviderName,
@{ n = 'Message'; e = { ($_.Message -split "`r?`n")[0] } } |
Sort-Object TimeCreated -Descending | Format-Table -AutoSize
Cómo leer el resultado. La salida tiene cuatro columnas: TimeCreated, Id, ProviderName y Message (solo la primera línea, porque es larga), ordenadas de más reciente a más antigua. Lo que hay que observar no es tanto el contenido de cada fila, sino en qué orden aparecen los distintos ID por cada reinicio. En un reinicio planificado suele aparecer el trío 1074 (alguien lo solicitó) → 6006 (detención del servicio de registro de eventos, es decir, apagado normal) → 6005 (inicio, es decir, arranque completado).
El 1074 es el evento clave para saber quién solicitó el reinicio. Si en este evento aparece WindowsUpdate o el nombre de un proceso concreto, la causa queda prácticamente confirmada. Si solo aparecen 41 y 6008 sin ningún 1074, sospeche de un corte de energía o un bloqueo del sistema (hang) que provocó una detención anómala.
(2) Seguimiento de inicios y cierres de sesión (registro de seguridad)
# 4624: inicio de sesión correcto / 4625: inicio de sesión fallido / 4634: cierre de sesión
# Requiere permiso de lectura del registro de seguridad (ejecute como administrador,
# o añada previamente la cuenta de ejecución al grupo Event Log Readers)
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 4624, 4625, 4634
StartTime = (Get-Date).AddDays(-1)
} | ForEach-Object {
$xml = [xml]$_.ToXml()
$d = @{}
foreach ($n in $xml.Event.EventData.Data) { $d[$n.Name] = $n.'#text' }
[pscustomobject]@{
Hora = $_.TimeCreated
Tipo = switch ($_.Id) { 4624 { 'Inicio de sesión correcto' } 4625 { 'Inicio de sesión fallido' } 4634 { 'Cierre de sesión' } }
Usuario = $d['TargetUserName']
TipoDeSesion = $d['LogonType'] # 2=interactivo 3=red 10=RDP
OrigenConexion = $d['IpAddress']
}
} | Where-Object Usuario -notlike '*$' | Format-Table -AutoSize
Aquí tenemos un ejemplo típico de uso de los datos del evento. Recortar Message con una expresión regular depende de la configuración de idioma del sistema operativo, pero el EventData de ToXml() se puede referenciar por nombre, de modo que el mismo script funciona tanto en un entorno en español como en uno en inglés.6
Cómo leer el resultado. La salida tiene cinco columnas: Hora, Tipo, Usuario, TipoDeSesion y OrigenConexion (como se construye a mano con [pscustomobject], tanto los nombres como el orden de las columnas los decide usted mismo). Al final se añade Where-Object Usuario -notlike '*$' para descartar las cuentas de equipo (cuyo nombre termina en $), de modo que solo quedan las cuentas de personas. Conviene revisar si en las filas con TipoDeSesion igual a 3 (red) o 10 (RDP) aparece alguna dirección IP en OrigenConexion que no reconozca, y si hay varios 4625 (fallidos) del mismo usuario en un intervalo corto de tiempo.
Tenga en cuenta también que, si la auditoría no está habilitada, el evento simplemente no se registra. Que «no aparezca ni un solo evento» no significa necesariamente que «no haya ocurrido nada»: puede que simplemente no se haya registrado.
Conceder al personal de investigación solo permiso de lectura. Conviene evitar repartir permisos de administrador solo para que alguien pueda leer el registro de seguridad. Si añade la cuenta al grupo integrado Event Log Readers (SID S-1-5-32-573), podrá leer el registro de eventos sin necesidad de permisos de administrador.2
# Se ejecuta en el equipo de destino (requiere permisos de administrador).
# El nombre visible del grupo integrado puede variar según el idioma del sistema operativo,
# así que es más fiable indicarlo por SID
Add-LocalGroupMember -SID 'S-1-5-32-573' -Member 'EXAMPLE\監査担当'
# Comprobar que se añadió correctamente
Get-LocalGroupMember -SID 'S-1-5-32-573'
Si necesita distribuir esto a varios equipos, use la directiva de grupo mediante «Configuración del equipo > Directivas > Configuración de Windows > Configuración de seguridad > Grupos restringidos», o bien la preferencia de directiva de grupo «Configuración del equipo > Preferencias > Configuración del Panel de control > Usuarios y grupos locales», para distribuir la configuración que añade un grupo del dominio al grupo local Event Log Readers de cada servidor.
Si quiere restringirlo aún más a nivel de canal, puede consultar y modificar con wevtutil los permisos de acceso (SDDL) de cada registro.2
wevtutil gl Security # Muestra la configuración actual (channelAccess es el SDDL)
# wevtutil sl Security /ca:<SDDL> # La modifica. /ca "reemplaza" el SDDL existente
/ca reemplaza el valor, no lo añade. Asegúrese siempre de guardar antes la salida de wevtutil gl antes de hacer el cambio.
(3) Cierres anómalos de aplicaciones
# 1000: Application Error (bloqueo de la aplicación)
# 1026: .NET Runtime (finalización por una excepción administrada)
# 1001: Windows Error Reporting (información del bucket de fallo)
Get-WinEvent -FilterHashtable @{
LogName = 'Application'
ID = 1000, 1001, 1026
StartTime = (Get-Date).AddDays(-14)
} | Select-Object TimeCreated, Id, ProviderName, Message |
Sort-Object TimeCreated -Descending | Format-List
El evento 1000 contiene el nombre del módulo que falló y el desplazamiento (offset), y el 1026 contiene la pila de la excepción de .NET. Conviene tomar una pista aquí antes de pasar al análisis de volcados (dumps) («Introducción a la recolección de volcados de fallos de Windows», «Leer volcados de fallos con WinDbg + SOS»).
(4) Detención y reinicio de servicios
# 7034: el servicio finalizó de forma inesperada / 7031: acción de recuperación tras la finalización / 7045: se instaló un servicio nuevo
Get-WinEvent -FilterHashtable @{
LogName = 'System'
ProviderName = 'Service Control Manager'
ID = 7031, 7034, 7045
StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, Message | Format-List
El evento 7045 (instalación de un servicio nuevo) también resulta útil para detectar la instalación de software no deseado. Para el diseño operativo de servicios de Windows, consulte «Cómo crear y operar servicios de Windows».
(5) Historial de ejecución del Programador de tareas
En esta sección se usa XPath, así que antes conviene fijar el esqueleto básico. Para el registro de eventos, en la práctica solo hay dos formas de escribir XPath que memorizar.1
| Forma de escribirlo | A qué apunta | Ejemplo |
|---|---|---|
*[System[ ... ]] |
Elementos comunes a cualquier evento (ID de evento, hora, nivel, proveedor) | *[System[EventID=41]] |
*[EventData[Data[@Name='nombreDelElemento']='valor']] |
Elementos propios de ese evento en concreto (datos de evento con nombre) | *[EventData[Data[@Name='TaskName']='\夜間集計']] |
Basta con combinar estas dos formas mediante and / or. Como la comparación de valores usa comillas simples, conviene meter la expresión en un here-string de PowerShell (@" … "@), así se evitan los problemas de anidar comillas (el código de más abajo tiene exactamente esa forma).
En lugar de armarla usted mismo, es más rápido y fiable dejar que el Visor de eventos la escriba y copiarla de ahí. En «Visor de eventos > (clic derecho sobre el registro correspondiente) > Filtrar el registro actual», indique las condiciones desde la interfaz gráfica y, al cambiar a la pestaña «XML» del cuadro de diálogo, se muestra la misma consulta en formato XML. El fragmento que queda entre <Select Path="..."> y </Select> es exactamente la cadena que se puede pasar tal cual a -FilterXPath.1
# 【Mal】Se traen todos los eventos y se filtra por el mensaje visible (depende del idioma)
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-TaskScheduler/Operational'
StartTime = (Get-Date).AddDays(-3)
} -ErrorAction SilentlyContinue |
Where-Object { $_.Message -like '*夜間集計*' }
# 【Bien】Se filtra en el servidor por el nombre de la tarea (dato del evento). Rápido y no depende del idioma
$xpath = @"
*[System[TimeCreated[timediff(@SystemTime) <= 259200000]]]
and
*[EventData[Data[@Name='TaskName']='\夜間集計']]
"@
Get-WinEvent -LogName 'Microsoft-Windows-TaskScheduler/Operational' `
-FilterXPath $xpath -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, LevelDisplayName, Message | Format-List
timediff es una función de XPath que indica el «tiempo transcurrido desde ahora» en milisegundos, y 259200000 equivale a 3 días. El nombre de la tarea se indica con la ruta completa que tenía al registrarse (si está justo bajo la raíz, sería \nombreDeTarea). El Message que se muestra depende de la configuración de idioma y, además, implica filtrar del lado del cliente, así que, siguiendo el criterio de este artículo, filtre siempre por los datos del evento.
Este registro puede estar deshabilitado de forma predeterminada. El procedimiento para habilitarlo y cómo diagnosticar el caso en que la tarea no se ejecuta están resumidos en «La tarea del Programador de tareas no se ejecuta o termina con 0x1».
5. Consultar registros de varios equipos o máquinas distintas
Método 1: leer directamente en remoto
Get-WinEvent -ComputerName 'srv01' -FilterHashtable @{ LogName='System'; ID=41 } -MaxEvents 10
Método 2: consultar en paralelo con Invoke-Command (preferible cuando son muchos equipos)
$servers = 'srv01', 'srv02', 'srv03'
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-WinEvent -FilterHashtable @{
LogName = 'System'; Level = 1, 2; StartTime = (Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, ProviderName, LevelDisplayName
} | Sort-Object PSComputerName, TimeCreated
Invoke-Command se ejecuta en paralelo contra varios equipos («Introducción a PowerShell Remoting (WinRM)», «Procesamiento en paralelo en PowerShell»).
Método 3: recoger el .evtx y analizarlo localmente
Se puede leer directamente el archivo que alguien exportó en sitio. Es más rápido que consultar repetidamente a través de la red y, además, queda como evidencia.
# En sitio: wevtutil epl System D:\collect\srv01_System.evtx
Get-WinEvent -Path 'D:\collect\srv01_System.evtx' -FilterXPath "*[System[(Level=1 or Level=2)]]" |
Select-Object TimeCreated, Id, ProviderName, Message
Método 4: reenvío de eventos de Windows (WEF) — esta es la opción para una recopilación permanente. Es una función estándar que reenvía los eventos de cada equipo a un servidor de recolección, sin necesidad de instalar ningún agente adicional.5
6. Tamaño del registro y período de retención
«Cuando fui a investigar, el registro de esa franja horaria ya se había sobrescrito» es un fallo muy habitual. El tamaño máximo predeterminado es reducido, y en entornos con mucha actividad el registro puede dar una vuelta completa en pocos días.
# Comprobar la configuración de tamaño actual y el estado de retención
Get-WinEvent -ListLog 'System', 'Application', 'Security' |
Select-Object LogName, IsEnabled, LogMode,
@{ n='MaxMB'; e={ [math]::Round($_.MaximumSizeInBytes / 1MB, 1) } },
RecordCount, OldestRecordNumber
# Cambiar el tamaño máximo (requiere permisos de administrador; ejemplo: el registro System a 256 MB)
wevtutil sl System /ms:268435456
En servidores destinados a investigación, o en equipos donde ya se ha producido un fallo, la práctica habitual es ampliar primero el tamaño del registro y después esperar a que el problema se reproduzca. Para la gestión de generaciones del registro y el archivado automático, consulte también «PowerShell aplicado — investigación de registros, archivado y generación de informes».
7. Criterios prácticos (tabla de decisión)
| Situación | Elección | Nota |
|---|---|---|
| Script nuevo que va a escribir | Get-WinEvent |
Get-EventLog está limitado a 5.1 y solo cubre registros clásicos1 |
| Filtrar por nombre de registro, ID o período | -FilterHashtable |
Es lo más rápido y lo más legible3 |
| Filtrar por el contenido de los datos del evento | -FilterXPath / -FilterXml |
Se puede copiar desde las vistas personalizadas del Visor de eventos1 |
| Muchos resultados y tarda demasiado | Acotar el período · -MaxEvents |
No delegue el filtrado en el lado de PowerShell |
| Quiere extraer un valor del mensaje | EventData de ToXml() |
El script deja de depender de la configuración de idioma1 |
| Investigación puntual en varios equipos | Invoke-Command |
Se ejecuta en paralelo5 |
| Recopilación permanente | Reenvío de eventos de Windows (WEF) | Función estándar que no requiere agente adicional5 |
| El registro antiguo ya no está | Ampliar el tamaño del registro | Hágalo antes de esperar a que se reproduzca el problema |
8. Resumen
- Unifique en torno a
Get-WinEvent.Get-EventLogno funciona en PowerShell 7 y además cubre menos registros. - El filtrado se hace con
-FilterHashtableo-FilterXPath. Filtrar después conWhere-Objectempeora el tiempo de investigación en órdenes de magnitud. - Para investigar un reinicio, revise el 41 y el 6008, y además el 1074 (quién lo solicitó). Para los cierres anómalos de aplicaciones, el punto de partida son el 1000, el 1026 y el 1001.
- Si usa los datos del evento de
ToXml()en lugar de la cadena del mensaje, el script deja de depender de la configuración de idioma. - Para una investigación puntual en varios equipos, use
Invoke-Command; para una recopilación permanente, el reenvío de eventos de Windows; y si necesita evidencia, recoja y analice localmente el.evtx. - Si no queda registro de la franja horaria que quiere investigar, no hay nada que hacer. Revisar el tamaño del registro debe ser la máxima prioridad al preparar la respuesta a incidentes.
Descarga del código de ejemplo
El código tratado en este artículo se distribuye ya organizado y listo para ejecutarse. Incluye el historial de reinicios, el historial de inicios de sesión, los fallos de tareas y la recolección en varios equipos.
Descargar el código de ejemplo (zip)
Como los ejemplos de este artículo dependen de Windows y del inquilino (tenant), no se ha realizado una verificación de ejecución. Se ha hecho un análisis de sintaxis y un análisis estático con PSScriptAnalyzer sobre todos los archivos, pero el funcionamiento debe comprobarse siempre en su propio equipo de pruebas.
# Análisis de sintaxis + análisis estático (se puede ejecutar incluso fuera de Windows)
./Invoke-SampleTests.ps1
Si no dispone de un entorno donde probar, no hace falta practicar contra los registros de producción de un equipo de trabajo. Con el entorno aislado de Windows (Windows Sandbox) puede levantar un Windows limpio en cuestión de minutos, y desaparece al cerrarlo («Cómo agilizar la validación de aplicaciones con Windows Sandbox»). Sin embargo, como el entorno aislado acaba de arrancar, apenas tiene registro acumulado, así que si quiere probar registros que “se acumulan con el tiempo”, como el historial de reinicios o de inicios de sesión, es más adecuada una máquina virtual de evaluación. Para empezar, basta con ejecutar los comandos del capítulo 3 en su propio equipo y comprobar en carne propia la diferencia de velocidad del filtrado.
Los valores de configuración (rutas, nombres de servidor, ID de inquilino, etc.) son solo ejemplos. No los ejecute tal cual en un entorno de producción; adáptelos a su propio entorno.
Artículos relacionados
- La tarea del Programador de tareas no se ejecuta o termina con 0x1 — cómo delimitar la causa y un diseño operativo seguro
- Registro de eventos, ETW y logging estructurado en Windows
- Introducción a la recolección de volcados de fallos de Windows - WER/ProcDump/WinDbg
- Introducción a PowerShell Remoting (WinRM) — administrar varios equipos Windows a la vez
- Cómo crear y operar servicios de Windows
- PowerShell aplicado — automatizar de forma segura la investigación de registros, el archivado y la generación de informes
Áreas de consultoría relacionadas
En KomuraSoft LLC nos ocupamos de la investigación de fallos en entornos Windows, del análisis de causas de reinicios y cierres anómalos de aplicaciones intermitentes, y de la construcción de mecanismos de recolección de registros y monitorización.
- Investigación de fallos y análisis de causas
- Consultoría técnica y revisión de diseño
- Modernización y mantenimiento de software Windows existente
- Contacto
Referencias
-
Microsoft Learn, Get-WinEvent. Sobre la posibilidad de obtener tanto registros clásicos como registros de eventos posteriores a Windows Vista; la obtención de listados mediante -ListLog / -ListProvider; el filtrado mediante -FilterHashtable / -FilterXPath / -FilterXml; la lectura de registros archivados (.evtx) mediante -Path; la obtención remota mediante -ComputerName; la limitación de cantidad mediante -MaxEvents; la necesidad de permisos de administrador para leer el registro de seguridad; y la obtención de la representación XML de cada evento mediante el método ToXml(). ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15
-
Microsoft Learn, Active Directory security groups — Event Log Readers. Sobre el hecho de que los miembros del grupo integrado «Event Log Readers» pueden leer el registro de eventos del equipo local (sin que ello implique conceder permisos de administrador). Como método para modificar los permisos de acceso de un canal individual, véase también sl /ca (acceso al canal) de wevtutil. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Creating Get-WinEvent queries with FilterHashtable. Sobre las claves que se pueden indicar en -FilterHashtable (LogName, ProviderName, Path, Keywords, ID, Level, StartTime, EndTime, UserID, Data, entre otras), el hecho de que el filtrado se realiza del lado del servidor y por ello resulta más eficiente que filtrar con Where-Object, y la forma de indicar los valores de palabra clave y gravedad. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Event Levels. Sobre los valores estándar de nivel de gravedad de un evento (1 = Critical, 2 = Error, 3 = Warning, 4 = Informational, 5 = Verbose). ↩ ↩2
-
Microsoft Learn, Windows Event Forwarding. Sobre la posibilidad de reenviar eventos desde varios equipos Windows a un servidor de recolección sin instalar un agente adicional, y la indicación de los objetivos de recolección mediante suscripciones. Véase también, sobre la ejecución en paralelo contra varios equipos, Invoke-Command. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, 4624(S): An account was successfully logged on. Sobre los elementos incluidos en los datos del evento de inicio de sesión correcto (TargetUserName, LogonType, IpAddress, entre otros), el significado de los valores del tipo de inicio de sesión, y el hecho de que la existencia del registro depende de la configuración de la directiva de auditoría. ↩
Artículos relacionados
Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.
Endurecimiento de la seguridad de PowerShell — registro, AMSI, modo de lenguaje y JEA
Resumen práctico para usar PowerShell con seguridad sin prohibirlo: registro de bloques de script y transcripción, deshabilitar AMSI y ve...
Auditoría de seguridad en Windows e investigación práctica del registro de eventos — cómo convertirse en un responsable de sistemas capaz de leer el 4625
Guía práctica para investigar fallos de inicio de sesión: directiva de auditoría básica y detallada, subcategorías mínimas, cómo leer 462...
Automatizar el kitting de PC con winget + PowerShell ── Convertir el manual de procedimientos en algo ejecutable
Resumimos cómo hacer reproducible la configuración de PC para nuevos empleados: instalación de aplicaciones con winget, export/import, co...
OneDrive «Archivos bajo demanda» y las aplicaciones empresariales — las suposiciones que rompen los marcadores de posición, y cómo abordarlas
¿Un CSV del escritorio no se puede leer, o el proceso de importación falla con «Archivo no encontrado»? La causa puede ser el KFM y los A...
Cómo funciona la Instantánea de volúmenes (VSS) en la práctica — por qué es posible respaldar archivos en uso
¿Por qué el software de backup sí puede copiar un archivo en uso pese a la violación de uso compartido? Explicamos los roles de VSS, el c...
Temas relacionados
Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.
Temas técnicos de Windows
Portal sobre desarrollo de Windows, investigación de fallos y aprovechamiento de activos existentes.
Investigación de fallos y problemas prolongados
Fallos intermitentes, diagnóstico de comunicaciones, bloqueos prolongados y pruebas de rutas de error.
Servicios relacionados con este tema
El artículo está directamente relacionado con los siguientes servicios.
Desarrollo de aplicaciones para Windows
Aplicaciones empresariales, integración de dispositivos y herramientas de comunicación, de los requisitos al desarrollo.
Preguntas frecuentes
Preguntas habituales en las consultas sobre el tema del artículo.
- ¿Debo usar Get-EventLog o Get-WinEvent?
- Use Get-WinEvent. Get-EventLog solo funciona en Windows PowerShell 5.1 y únicamente puede acceder a los registros clásicos, como System, Application y Security. Los registros que se encuentran bajo «Registros de aplicaciones y servicios», añadidos a partir de Windows Vista, como el detallado Microsoft-Windows-TaskScheduler/Operational, solo se pueden leer con Get-WinEvent. Además, en PowerShell 7 el propio Get-EventLog no está disponible, así que a partir de ahora conviene unificar todos los scripts nuevos en torno a Get-WinEvent.
- Get-WinEvent es demasiado lento y no me sirve para investigar.
- Es muy probable que esté filtrando con Where-Object después del pipe. Con esa forma de escribirlo, primero se convierten en objetos todos los eventos del registro y se cargan en PowerShell, y solo después se descartan los que no interesan. Con registros de cientos de miles de eventos, eso resulta poco práctico. Si utiliza -FilterHashtable o -FilterXPath, el filtrado se realiza en el propio registro de eventos y solo se devuelven los eventos necesarios, lo que lo hace órdenes de magnitud más rápido. Adquiera la costumbre de indicar primero el nombre del registro, el período y el ID de evento mediante FilterHashtable.
- Al intentar leer el registro de seguridad, obtengo acceso denegado.
- La lectura del registro de seguridad requiere de forma predeterminada permisos especiales. Si solo quiere comprobarlo en su propio equipo, basta con ejecutar PowerShell «como administrador», pero si no quiere entregar permisos de administrador al responsable de la investigación, existen dos alternativas: añadirlo al grupo integrado «Event Log Readers» (lectores del registro de eventos) o conceder únicamente el permiso de lectura mediante los permisos de acceso del canal (ACL). Desde el punto de vista del mínimo privilegio, se recomienda esta segunda opción. Además, cabe la posibilidad de que el propio registro de auditoría no se esté generando: la auditoría de inicios de sesión, por ejemplo, depende de la configuración de la directiva de auditoría, así que si no aparece ningún evento, conviene comprobar también si la propia directiva está habilitada.
- Quiero extraer del mensaje del evento solo un valor concreto (un nombre de usuario o de proceso).
- En lugar de recortar la propiedad Message con expresiones regulares, es más fiable usar Properties o los datos del evento. Cada evento permite obtener su representación XML mediante el método ToXml(), y dentro de esta, bajo EventData, aparecen elementos con nombre. La cadena de mensaje que se muestra en pantalla varía según el idioma configurado en el sistema operativo, pero la estructura de los datos del evento no cambia, de modo que puede escribir un script que funcione tanto en un entorno en español como en uno en inglés.
- Quiero revisar en conjunto los registros de eventos de varios servidores.
- Si son pocos equipos, basta con el parámetro -ComputerName de Get-WinEvent o con la ejecución remota mediante Invoke-Command. Invoke-Command se ejecuta en paralelo contra los equipos indicados, por lo que resulta práctico incluso para varias decenas de servidores. Si desea una recopilación permanente, considere el reenvío de eventos de Windows (WEF, Windows Event Forwarding) para centralizarlos en un servidor de recolección. Para una investigación puntual, también es útil exportar el archivo evtx en cada servidor y analizarlo localmente con Get-WinEvent -Path.
Perfil del autor
Página de presentación del autor del artículo.
Go Komura
Representante de KomuraSoft LLC
Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.