En los últimos meses tuvimos un caso en el que un dato cacheado en el perfil de una máquina bloqueaba recurrentemente a un usuario. Revisamos auditorías y herramientas de red sin éxito hasta que dimos con el enfoque correcto: leer el evento 4740 (A user account was locked out) en los Controladores de Dominio y extraer el CallerComputerName (equipo origen).
A continuación dejo comandos listos para: (1) localizar el equipo que bloqueó al usuario y (2) ver cuándo caduca la contraseña de los usuarios.
Requisitos rápidos
- Módulo de ActiveDirectory disponible (en servidor:
Install-WindowsFeature RSAT-AD-PowerShell
; en Windows 10/11:Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
). - Permisos para leer el Log de Seguridad en los DCs.
- La auditoría de bloqueo (evento 4740) suele venir habilitada por defecto en DCs.
Opción 1 (rápida): consultar solo el PDC Emulator
Suele bastar con consultar el PDC Emulator (centraliza información de bloqueos). Sustituye usuario.bloqueado
por el sAMAccountName
o UPN del usuario.
$User = "usuario.bloqueado"
$PDC = (Get-ADDomain).PDCEmulator
# 7 días hacia atrás; ajusta si lo necesitas
$Start = (Get-Date).AddDays(-7)
$Filter = @{
LogName = "Security"
Id = 4740
StartTime = $Start
}
$events = Get-WinEvent -ComputerName $PDC -FilterHashtable $Filter
# Convertir EventData a hashtable para acceder por nombre (CallerComputerName, TargetUserName, etc.)
$parsed = foreach($e in $events){
$xml = [xml]$e.ToXml()
$data = @{}
foreach($d in $xml.Event.EventData.Data){ $data[$d.Name] = $d.'#text' }
# Filtrar por usuario objetivo y devolver datos útiles
if($data["TargetUserName"] -ieq $User){
[pscustomobject]@{
User = $data["TargetUserName"]
CallerComputerName = $data["CallerComputerName"]
DomainController = $PDC
When = $e.TimeCreated
}
}
}
$parsed | Sort-Object When | Format-Table -Auto
Tip: si
CallerComputerName
está vacío, revisa otros DCs (siguiente opción) o comprueba DNS/NetBIOS del equipo origen.
Opción 2 (exhaustiva): consultar todos los DCs
Útil cuando el bloqueo se originó en otro DC o hay replicación retrasada.
param([string]$User = "usuario.bloqueado", [int]$HoursBack = 168) # 7 días
$Since = (Get-Date).AddHours(-$HoursBack)
$DCs = Get-ADDomainController -Filter * | Select-Object -ExpandProperty HostName
$result = foreach($dc in $DCs){
try{
$events = Get-WinEvent -ComputerName $dc -FilterHashtable @{
LogName = "Security"
Id = 4740
StartTime = $Since
} -ErrorAction Stop
foreach($e in $events){
$xml = [xml]$e.ToXml()
$data = @{}
foreach($d in $xml.Event.EventData.Data){ $data[$d.Name] = $d.'#text' }
if($data["TargetUserName"] -ieq $User){
[pscustomobject]@{
User = $data["TargetUserName"]
CallerComputerName = $data["CallerComputerName"]
DomainController = $dc
When = $e.TimeCreated
}
}
}
} catch {
Write-Warning "No se pudo leer el Security log en $dc: $_"
}
}
$result | Sort-Object When | Tee-Object -Variable Lockouts | Format-Table -Auto
# (Opcional) Exportar a CSV
# $Lockouts | Export-Csv -Path .\lockout-origen.csv -NoTypeInformation -Encoding UTF8
Con esto obtendrás una tabla con equipo origen, DC donde se registró y la fecha/hora.
Desbloquear la cuenta (si procede)
Unlock-ADAccount -Identity "usuario.bloqueado"
Bonustrack: ¿cuándo caduca la contraseña?
Un usuario concreto
$u = Get-ADUser -Identity "usuario.bloqueado" -Properties "msDS-UserPasswordExpiryTimeComputed"
[datetime]::FromFileTime($u."msDS-UserPasswordExpiryTimeComputed")
Lista completa (habilitados y con caducidad)
Get-ADUser -Filter { Enabled -eq $True -and PasswordNeverExpires -eq $False } -Properties "DisplayName","msDS-UserPasswordExpiryTimeComputed" |
Select-Object DisplayName,userPrincipalName,@{
Name="ExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}
} | Sort-Object ExpiryDate
Errores frecuentes (y cómo resolverlos)
- Sin resultados → amplía la ventana temporal (
-HoursBack
), verifica el nombre del usuario y confirma que el bloqueo ocurrió en el periodo. - Acceso denegado al Security log → ejecuta con credenciales elevadas y desde un equipo con acceso a los DCs.
- CallerComputerName en blanco → puede tratarse de servicios, dispositivos móviles, tareas programadas o credenciales guardadas; mira también TargetLogonId / IpAddress en el XML del evento para más pistas.
Resumen
El evento 4740 te da el equipo origen del bloqueo de cuenta. Con los fragmentos anteriores podrás consultar el PDC (rápido) o todos los DCs (exhaustivo), desbloquear la cuenta si hace falta y responder a usuarios sobre caducidad de contraseña con un solo comando.