PowerShell Remoting: cómo corregir el error “usuario o contraseña incorrectos” tras 20 minutos

¿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.

Índice

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:

  1. Negociación de autenticación (Kerberos, NTLM o CredSSP).
  2. Asignación de un shell ID en el host remoto.
  3. 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 revisarQué comprobarPosible solución
Mantenimiento o ventanas de red nocturnasCambios 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 / concurrenciaUso 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 ticketsBloqueos 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 WinRMReinicios 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‑skewAjustes 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 o Remove‑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 y MaxPollInterval adecuados.

Procedimiento guiado para aislar la causa

  1. 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.
  2. Capturar excepciones detalladas. Envolviendo Invoke‑Command con -ErrorVariable ev y escribiendo $ev[0].Exception.StackTrace en un log.
  3. Reducir el lote. Repite la tarea con 10‑20 máquinas. Si no falla pasados 25 minutos, el cuello está en la escala.
  4. Monitorizar recursos. Habilita trazas ETW WSMan (netsh trace start capture=yes protocol=wsap), contadores de rendimiento y netstat.
  5. Analizar logs de seguridad. Busca repetidos 4771 Kerberos pre‑authentication failed4625 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.

Índice