¿Alguna vez tu automatización nocturna de PowerShell Remoting se detiene de forma inexplicable después de los primeros veinte minutos y cada nueva sesión devuelve “usuario o contraseña incorrectos”? A continuación encontrarás un análisis exhaustivo de las causas más probables, con técnicas de diagnóstico y mitigación que han demostrado eficacia en entornos de producción exigentes.
Resumen del escenario
Una aplicación .NET abre, justo pasada la medianoche, más de cien sesiones remotas (New‑PSSession
) contra distintos equipos Windows para tareas de mantenimiento. Durante los primeros 15‑20 minutos todo funciona, pero a partir de ese punto cualquier intento de conexión responde con error de autenticación. Repetir la misma operación en horario diurno no reproduce el fallo.
Por qué el fallo solo ocurre de madrugada
La franja horaria crítica coincide con:
- Ventanas de mantenimiento de red (copias de seguridad, rotación de VLAN, reinicios programados de switches).
- Jobs de sistema que reinician servicios o reciclan application pools en IIS.
- Re‑sincronizaciones de NTP que corrigen clock‑skew acumulado durante el día.
- Procesos automatizados intensivos en uso de recursos (en tu caso, apertura de cientos de sockets).
Anatomía de una sesión WinRM
PowerShell Remoting se basa en WinRM, que a su vez utiliza HTTP/HTTPS en el puerto 5985/5986, más un puerto efímero para cada canal de retorno. Cada apertura de sesión implica:
- Negociación de autenticación (Kerberos, NTLM o CredSSP).
- Asignación de un shell ID en el host remoto.
- Reserva de memoria y handles en el servicio WinRM.
Si cualquiera de estos pasos falla —sea por recursos, políticas de seguridad o incoherencia de tiempo— obtendrás respuestas de credenciales no válidas aun usando el usuario correcto.
Hipótesis más comunes y su validación
Área a revisar | Qué comprobar | Posible solución |
---|---|---|
Mantenimiento o ventanas de red nocturnas | Cambios de firewall, reinicios de switches, tareas de respaldo, actualizaciones programadas. | Coordinar con el equipo de redes; pedir registros de cambios o monitorizar con ping , tracert , NetMon o Wireshark durante la franja afectada. |
Limitaciones de recursos / concurrencia | Uso intensivo al abrir 100 sesiones: agotamiento de puertos efímeros o límites de WinRM. | Reducir la ráfaga: lanzar lotes más pequeños o introducir retrasos (Start‑Sleep ). Reutilizar sesiones persistentes en lugar de abrir una nueva por equipo. Aumentar MaxConcurrentOperations y MaxShellsPerUser con winrm set winrm/config . |
Autenticación y tiempo de vida de tickets | Bloqueos automáticos por re‑emisión masiva de credenciales; expiración de tickets. | Revisar Visor de eventos (Security 4625 y 4771). Comprobar umbrales de bloqueo de cuenta. Si se usa NTLM, auditar la caché y las directivas. |
Servicio WinRM | Reinicios nocturnos, políticas de reciclado de IIS o límites de memoria. | Aumentar IdleTimeout o reiniciar controladamente antes de la operación; validar que WinRM no se recicla a medianoche. |
Clock‑skew | Ajustes de NTP que invalidan tokens de autenticación. | Asegurar sincronización cronométrica en todos los nodos y en el controlador de dominio. |
Análisis de autenticación Kerberos y NTLM
Kerberos genera un Ticket Granting Ticket (TGT) cada vez que el cliente arranca sesión de dominio y un Service Ticket por cada recurso. Si disparas 100 conexiones en cascada disparas 100 peticiones al KDC. Si los tickets se emiten pero nunca se usan —o se usan fuera de tiempo por clock‑skew— el KDC entrega un error KRB5KRBAPERRBADINTEGRITY que WinRM interpreta como “usuario o contraseña incorrectos”.
Para diagnosticar:
klist sessions
klist –li 0x3e7
Get-WinEvent -LogName Security -FilterHashtable @{Id=4769,StartTime=(Get-Date).AddMinutes(-30)} |
Select TimeCreated,Message
Si el resultado muestra repetidos 4769 Service Ticket Request y luego códigos 0x18 (bad credentials) o 0x1F (integrity check failed) en el DC, tu problema es Kerberos.
Estrangulamiento por concurrencia y puertos efímeros
Windows 10/Server 2016+ dispone de ~16 000 puertos efímeros por protocolo. Pero una aplicación .NET que abra 100 runspaces en paralelo puede:
- Consumir todos los puertos locales si no cierra sesiones (
Disconnect‑PSSession
oRemove‑PSSession
). - Superar los valores por defecto de
MaxConnections
en WinRM (10 por 60 segundos para clientes HTTP y 32 máx. para HTTP/HTTPS persistente).
Comandos de inspección en el momento del fallo:
# En el cliente
netstat -ano | find ":5985"
Get-PSSession | Measure-Object
En el host remoto
winrm enumerate winrm/config/listener
winrm get winrm/config/service
Si ves cientos de sockets en TIME_WAIT o múltiples shells en estado Opened, activa cierre explícito o KeepAlive
más breve.
Cómo comprobar puerto, shell y recursos
# Dump de handles WinRM
Get-Process -Name winrm | ForEach-Object {
$.Modules | Where-Object {$.ModuleName -like "http*.dll"}
}
Get-Counter '\WSMan*' -Continuous -SampleInterval 5
El contador WSMan\* expone Current Shells, Current Connections y Requests Queued. Si alguno alcanza el máximo (50 shells por usuario o 150 operaciones concurrentes) verás nuevas solicitudes rechazadas con mensaje de credenciales.
Impacto del recicle de WinRM e IIS
Si tu listener WinRM se aloja detrás de IIS (escenario típico en servidores con Management OData IIS Extension) el reciclado de Application Pool a media noche puede invalidar los WSMan Shell IDs. Configura:
Idle Time-out (minutes)
⟶ 0 (ilimitado) o un valor superior al de la ventana de operaciones.Regular Time Interval
⟶ 0 para evitar reciclado programado.
En WinRM puro, incrementa IdleTimeoutms
:
winrm set winrm/config @{MaxTimeoutms="7200000"}
y reinicia el servicio con Restart-Service winrm
fuera de horario.
Influencia de la sincronización horaria
Un adelanto o atraso de más de 5 minutos entre cliente, servidor y DC basta para invalidar tokens Kerberos. Ejecuta:
w32tm /query /status
w32tm /monitor
en los tres nodos justo antes y después del fallo. Si ves un cambio grande de Offset cerca de las 00:00, ajusta la política GPO:
- Configura un servidor NTP interno con
SpecialPollInterval
de 3600 s. - Inhabilita correcciones bruscas con
MinPollInterval
yMaxPollInterval
adecuados.
Procedimiento guiado para aislar la causa
- Trazar la línea temporal. Registra hora exacta del primer 401 o 403 en el cliente y cruza con eventos del DC, del equipo remoto y del firewall.
- Capturar excepciones detalladas. Envolviendo
Invoke‑Command
con-ErrorVariable ev
y escribiendo$ev[0].Exception.StackTrace
en un log. - Reducir el lote. Repite la tarea con 10‑20 máquinas. Si no falla pasados 25 minutos, el cuello está en la escala.
- Monitorizar recursos. Habilita trazas ETW WSMan (
netsh trace start capture=yes protocol=wsap
), contadores de rendimiento ynetstat
. - Analizar logs de seguridad. Busca repetidos 4771 Kerberos pre‑authentication failed o 4625 An account failed to log on.
Estrategias definitivas de mitigación
Reutilizar conexiones persistentes
# Crear un pool de sesiones y reutilizarlo
$cred = Get-Credential
$sessionPool = @{}
$Targets | ForEach-Object {
$sessionPool[$] = New-PSSession -ComputerName $ -Credential $cred
}
foreach (\$srv in \$Targets) {
Invoke-Command -Session \$sessionPool\[\$srv] -ScriptBlock { ... }
}
De este modo generas un único ticket y un único shell por host.
Aplicar exponente de retardo
Si prefieres abrir sesiones de forma secuencial, añade un pequeño back‑off exponencial:
for ($i=0; $i -lt $Targets.Count; $i++) {
$delay = [math]::Min(2000,$i*50)
Start-Sleep -Milliseconds $delay
New-PSSession -ComputerName $Targets[$i] -Credential $cred
}
Optimizar políticas WinRM
winrm set winrm/config @{MaxConcurrentOperations="300"}
winrm set winrm/config @{MaxShellsPerUser="100"}
En hosts con gran RAM 300‑400 operaciones son manejables. Asegúrate de que MaxMemoryPerShellMB
sea acorde.
Proteger la capa de autenticación
- Implementa Threshold de bloqueo > 20 intentos si controlas el DC y es un entorno seguro.
- Activa Smart‑card logon o Key Distribution Center Proxy para reducir peticiones masivas de tickets.
Ejemplo de script robusto con control de errores
$ErrorActionPreference = 'Stop'
$cred = Get-Credential
$targets = Get-Content .\servers.txt
$log = ".\remoting_$(Get-Date -Format yyyyMMdd).log"
function Invoke-Safe {
param(\$Computer, \$Script)
try {
Invoke-Command -ComputerName \$Computer -Credential \$cred \`
-ScriptBlock \$Script -Authentication Kerberos -ErrorAction Stop
"\$Computer,OK,\$(Get-Date)" | Out-File \$log -Append
} catch {
"\$Computer,FAIL,\$*,\$(Get-Date)" | Out-File \$log -Append
Write-Warning "\$Computer failed with \$(\$*.Exception.Message)"
}
}
\$sb = { Get-Service | Where-Object {$\_.Status -eq 'Running'} }
foreach (\$c in \$targets) {
Invoke-Safe -Computer \$c -Script \$sb
}
Registro, observabilidad y alertas recomendadas
Para erradicar definitivamente este tipo de fallos crea un panel que cubra:
- Contadores WSMan Current Connections, Requests/sec y Response Time.
- Eventos 4625, 4768, 4769 y 4771 agregados por minuto.
- Número de sockets en estado TIMEWAIT y SYNSENT.
- Línea base de latencia de autenticación Kerberos (KDC response time).
Una alerta temprana cuando se superen los valores umbral (p. ej., > 40 shells concurrentes o 50 eventos 4625 en 5 min) permitirá reiniciar el servicio o throttlear la aplicación antes de que el problema impacte al negocio.
Preguntas frecuentes
- ¿Reiniciar WinRM resuelve el problema? Solo si la causa son límites internos o fugas de memoria. El reinicio no arreglará clock‑skew ni bloqueos de cuenta.
- ¿Cambiar de Kerberos a NTLM ayuda? NTLM es más tolerante a clock‑skew pero consume más CPU en el servidor y es menos seguro. Es preferible arreglar el origen.
- ¿Basta con aumentar
MaxShellsPerUser
? A veces; sin embargo, abrir demasiadas shells incrementa uso de RAM y handles, pudiendo empeorar la situación si no cierras sesiones. - ¿Exponer el puerto 5985 en Internet es seguro? Solo si forzas HTTPS, limitas IP source y aplicas autenticación de certificado. De lo contrario, mejor usar VPN o SSH sobre PowerShell 7.
Conclusión
Los mensajes de “usuario o contraseña incorrectos” tras 15‑20 minutos en PowerShell Remoting rara vez se deben a credenciales realmente erróneas. Son el síntoma de una combinación de estrangulamiento de recursos, ventanas de mantenimiento o incoherencias de autenticación. Si documentas la línea temporal, monitorizas WinRM y Kerberos, y aplicas técnicas de limitación de concurrencia podrás restaurar la estabilidad de tus programas nocturnos y liberar al equipo de incertidumbre.