Si tras promover un nuevo controlador de dominio en Windows Server 2025 alojado en XCP‑ng tus procesos que se ejecutan como SYSTEM
(tareas programadas, PsExec
, scripts de mantenimiento, etc.) se congelan al detenerse, es muy probable que el origen sea un servicio propio que abre una interfaz gráfica durante OnStart
. A continuación encontrarás una guía práctica y exhaustiva para diagnosticar, reproducir y, sobre todo, eliminar definitivamente este bloqueo sin comprometer seguridad, rendimiento ni buenas prácticas de administración de controladores de dominio.
Resumen de la pregunta
Después de instalar en el DC un servicio de Windows escrito en C# con Autostart, dicho servicio genera un formulario vacío en su evento OnStart
. Tras reiniciar el servidor, todo proceso lanzado bajo la identidad NT AUTHORITY\SYSTEM
se queda colgado cuando el sistema intenta cerrarlo. El objetivo es averiguar la causa exacta y la forma de evitarlo.
Entorno y síntoma
- Sistema operativo : Windows Server 2025 Datacenter (versión para SAC) actualizado a la última “Patch Tuesday”.
- Rol del servidor : Controlador de dominio (nivel funcional 2025).
- Hipervisor : XCP‑ng 8.3 con drivers paravirtual modernos (PV‑drivers 9.3).
- Servicio problemático : Binario .NET 8.0 que, durante
OnStart
, creaApplicationContext
+Form
vacío y queda a la espera de eventos. - Síntoma : cualquier proceso bajo SYSTEM deja de responder en la fase de “Stopping”, forzando
TerminateProcess
y generando eventos de error 7022/7036 en el visor.
Causa técnica
Desde Windows Vista los servicios que se ejecutan como SYSTEM quedan aislados en la Sesión 0, mientras que los escritorios interactivos viven en sesiones de usuario (> 1). El servicio, al crear un formulario, intenta inicializar subsistemas de UI (User32
, GDI+
) que:
- Requieren un contexto de ventana asociado a un “desktop” válido.
- Bloquean la cola de mensajes de Sesión 0 si no existe un entorno visible.
- Impiden la finalización ordenada de otros servicios o procesos que comparten la misma sesión y cuenta SYSTEM, provocando deadlocks en
ExitProcess
.
En Windows Server 2025 el aislamiento es aún más estricto: políticas de seguridad predeterminadas impiden incluso la suplantación de sesión o la creación de escritorios temporales sin privilegio explícito (SETCBNAME
), por lo que el bloqueo se manifiesta de forma inmediata.
Metodología de diagnóstico
Acción | Propósito | Resultado esperado |
---|---|---|
Desplegar el servicio en un servidor miembro físico (no DC) | Descartar impacto del rol de controlador | Bloqueo desaparece ➜ factor DC |
Desplegar en DC físico | Aislar impacto de la capa de virtualización | Si el bloqueo continúa ➜ la virtualización no es la causa |
Iniciar el servicio con sc start y parar con sc stop | Observar tiempos de parada | Vemos espera >30 s → timeout 30 000 ms |
Comentarios Form.Show() | Confirmar que la UI provoca el deadlock | Sin UI no hay cuelgue |
Monitoreo con procmon + filtros “System” | Detectar llamadas bloqueantes (WaitForSingleObjectEx ) | Handle relacionado con \Sessions\0\BaseNamedObjects\... |
Buenas prácticas para diseñar servicios en un DC
Separar lógicas
Divide la solución en dos binarios:
- Servicio backend sin UI, limitado a la lógica de negocio y expuesto por IPC.
- Aplicación cliente (WinUI, WPF, MAUI, consola) que se ejecuta bajo un usuario interactivo y se comunica con el servicio.
Canales de comunicación recomendados
Named Pipes
(rápidas en la misma máquina, ACL integradas).gRPC
sobrenPipe
o TCP cuando necesitas “streaming” y contratos fuertemente tipados.HTTP(s)
local conHttpListener
o Kestrel si planeas exponer el servicio a terceros.
Cuenta de servicio
Evita SYSTEM salvo que sea absolutamente necesario. Alternativas:
- Cuenta administrada de tipo gMSA (Group Managed Service Account) – ideal en entornos con varios DC.
- Cuenta virtual
NT SERVICE\NombreServicio
– suficiente para la mayoría de servicios internos.
Recuerda delegar solo los privilegios mínimos (principio de menor privilegio) vía GPO o sc.exe
.
Manejo de dependencias
Configura dependencias explícitas con sc config ServicioA depend= ServicioB
para asegurar el orden correcto de arranque y parada. Evita dependencias circulares.
Tiempo de espera personalizado
Si el servicio requiere una fase de inicialización larga, ajusta ServicesPipeTimeout
en HKLM\SYSTEM\CurrentControlSet\Control
(DWORD, milisegundos). No multiplicar el valor por encima de lo razonable (60–90 s) para no enmascarar problemas reales.
Procedimiento paso a paso para la corrección
- Extraer la UI del servicio existente
// Antes protected override void OnStart(string[] args){ Application.Run(new MainForm()); // ❌ } // Después protected override void OnStart(string[] args){ // Lógica sin UI MyEngine.Start(); } - Crear aplicación cliente
Simple proyecto WinForms/WPF que invoqueMyEngine
vía gRPC o Pipe. - Registrar el servicio
sc create MyEngine binPath= “C:\Srv\MyEngine.exe” obj= “NT SERVICE\MyEngine” - Probar parada/arranque varias veces asegurándote de que los eventos 7036 aparecen con duración <1 s.
- Instrumentar con
ETW
si persisten demoras: logman start UIBlock -p Microsoft-Windows-Win32k -ets Analiza con Windows Performance Analyzer.
Notas específicas para XCP‑ng
En entornos paravirtualizados el subsistema de sesiones puede tardar unos milisegundos extra en inicializar durante el arranque, pero no es causa directa del bloqueo. Sin embargo:
- Comprueba que los PV‑drivers estén actualizados; versiones antiguas (< 8.2) registran hooks
Win32k
que afectan a Sesión 0. - Deshabilita la opción “Wait for tools to respond on shutdown” en la política de energizado de la VM para evitar tiempos de espera fantasma.
Riesgos de seguridad
Presentar una interfaz gráfica desde SYSTEM en un DC:
- Rompe la superficie de ataque 0 que Microsoft defiende desde Windows Server 2008.
- Permite shatter attacks, donde un proceso de menor privilegio inyecta mensajes ventana que elevan privilegios.
- Dificulta aplicar
Credential Guard
y las protecciones LSASS PPL, pues interpones APIs UI clasicamente vulnerables.
Por ello, la separación UI‑servicio no es solo cuestión de estabilidad sino de seguridad corporativa.
Conclusión
El bloqueo de procesos SYSTEM al detenerse en un controlador de dominio Windows Server 2025 se debe, en la mayoría de los casos, a que un servicio mezcla lógica de backend con presentación gráfica dentro de la Sesión 0. La solución definitiva pasa por una arquitectura desacoplada: servicio sin UI + cliente interactivo. Adoptar esta estructura elimina deadlocks, respeta políticas de seguridad y simplifica el mantenimiento tanto en hardware físico como en entornos virtualizados XCP‑ng.
Aplica la metodología de diagnóstico descrita, refactoriza tu código, limita privilegios y verás cómo los eventos de error desaparecen y tu DC vuelve a iniciar y detener servicios de forma impecable.