WinRM y WS-Management. Automatizar Windows desde Linux
Que es WinRM y WS-Management
Windows Remote Management (WinRM) es un protocolo diseñado para facilitar la automatización y administración remota de equipos basados en Windows.
Se basa en el protocolo WS-Management, un estándar público para intercambiar datos de administración de forma remota con cualquier dispositivo informático que implemente el protocolo.
El protocolo WS-Management garantiza la compatibilidad entre dispositivos y sistemas. Resulta útil cuando se combina con la comunicación remota de PowerShell, que permite a los administradores gestionar varios dispositivos mediante scripts y comandos.
Qué hace WinRM
WinRM permite la comunicación entre dispositivos, lo que permite a los administradores interactuar con sistemas remotos, ejecutar comandos de forma remota, recuperar datos y administrar configuraciones de sistemas. Se utiliza ampliamente para tareas como resolución de problemas, implementación de software y monitorización del rendimiento.
Autenticación y cifrado
WinRM admite varios mecanismos de autenticación, entre ellos, autenticación básica, Kerberos y NTLM.
También admite el cifrado para proteger la comunicación entre el cliente y el servidor, lo que garantiza la protección de los datos confidenciales durante el proceso de administración remota.
Administración de equipos Windows
Para administar equipos Windows remotos hay basicamente dos opciones:
- Mediante SSH
- Mediante WS-Management
Mediante SSH
Esta opción es totalmente operativa y permite administrar equipos desde Windows ó desde Linux.
Permite ejecutar tanto comandos CMD, como comandos PowerShell.
- CMD:
ssh -o PreferredAuthentications=password -o StrictHostKeyChecking=no -p 2222 guillermo@localhost 'whoami'
- PowerShell:
ssh -o PreferredAuthentications=password -o StrictHostKeyChecking=no -p 2222 guillermo@winpc 'powershell -Command "Write-Output 'SoloConLinux conectado'"'
Captura de la ejecución:

Para el funcionamiento correcto de la conexion ssh
desde un equipo Linux hay que forzar la autenticación, en mi caso lo he realizado con el parámetro: -o PreferredAuthentications=password
En caso contrario nos podemos encontrar con el siguiente error:
Received disconnect from winpc: Too many authentication failures
Disconnected from winpc
Tambien podemos usar Ansible.
En el caso de usar BashFlow
, (producto propio, sin liberar aun) podremos crear nuestro propio playbook y usarlo para realizar la conexion al equipo Windows.
Ejemplo de Playbook en bashflow: winremote_exec.yaml
tasks:
- name: Ejecutar comando remoto en Windows vía SSH
module: winremote_exec
args:
winuser: guillermo
winpassword: "{{ clave_guillermo }}"
port: 2222
#command: "Get-Process | Where-Object {$_.CPU -gt 1}"
command: "whoami"
Ejecutamos el playbook:
bashflow -f winremote_exec.yml -h winpc
La salida de la ejecución se vería así:

Mediante WS-Management
Para la administración automatiza de equipos Windows se puede realizar atacando al servicio winrm.exe
Este es el servicio que se ejecuta en los equipos Windows y permite aceptar y responder a las peticiones de administración remota.
Escucha las solicitudes entrantes en puertos específicos (el valor predeterminado es 5985
para HTTP y 5986
para HTTPS).
Para que lo entendamos, podemos decir de forma simplificada que todo se realiza mediante llamadas SOAP.
Para la administración remota, los admistradores de Windows
, disponen de PowerShell Remoting
que se basa en WinRM y permite ejecutar comandos de PowerShell en sistemas remotos mediante un canal seguro.
Para los equipos Linux, se dispone de pwsh
una shell de Powershell, sin embargo esta shell para Linux ya no permite ejecutar comando WS-Management, debido a los cambios de versiones de librerías de OpenSSL y otras medidas de seguridad ampliadas por Microsoft.
Basicamente el problema actual de pwsh
en Linux es:
- PowerShell Core (
pwsh
) en Linux no incluye el cliente WSMan necesario para poder ejecutar:
Invoke-Command -ConnectionUri
. - WSMan depende de bibliotecas nativas de Windows (
winrm.dll
) que no existen en Linux. - Microsoft lo documenta e indica claramente:
“WSMan remoting is not supported on non-Windows platforms.”
Existen alternativas como usar pywinrm
pero volvemos al problema de dependencias de Python.
En mi caso quería disponer de alguna "herramienta" que no tuviese dependencias y fuese un único binario al que invocar, tras localizar algunos proyectos relacionados con WS-Management:
-
OpenWSMan
http://openwsman.github.io/
Es un desarrollo Open Source de WS-Management, sin embargo tambien termina siendo una implementación en Python. wsmancli
https://github.com/Openwsman/wsmancli
Tras varios intentos de compilación, resultó que ademas de usar una implementación incompleta de la API, hay numerosas dependencias de paquetes de terceros y no conseguí hacerlo funcionar correctamente.wsman
Empaquetado y ajuste de librerias de wsman 2.6
Existen algunos binarios del cliente de ws-managerwsman
pero que tienen dependencias de librerías que ya no están disponibles en las versiones actuales de la paquetería Debian, como para mi el uso de este binario era quizás la opción más sencilla he optado por solventar los problemas de librerias del binario y generar un paquete.deb
Los programas wsman
y wseventmgr
los podeis instalar en vuestro Debian 13 si teneis configurado el repositorio de SoloConLinux simplemente ejecutando:
sudo apt update
sudo apt -y install wsmancli
Si deseasis decargar el paquete wsmancli.deb
para instalarlo a mano mediante: sudo dpkg -i wsmancli.deb
Os dejo el enlace del paquete en el enlace:
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Service\Auth\Basic -Value $true
Set-Item WSMan:\localhost\Service\AllowUnencrypted -Value $true
Restart-Service WinRM
Habilitar WinRM en Windows (desde PowerShell)
Ejecución de comandos en Windows desde Linux con wsman
Para la ejecución hay que ejecutarlo con la sintaxis propia de wsman, y ademas hay que encapsular los comandos
a ejecutar y dejarlo en formato XML.
Os dejo dos ejemplos de comandos para que veais la sintaxis necesaria:
comando.xml
<p:Create_INPUT xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process">
<p:CommandLine>cmd.exe /c echo hola > C:\salida.txt</p:CommandLine>
</p:Create_INPUT>
abrir_notepad.xml
<p:Create_INPUT xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process">
<p:CommandLine>notepad.exe</p:CommandLine>
</p:Create_INPUT>
Para lanzar los comandos usaremos wsman
:
wsman invoke http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process -a Create -h winpc -P 5985 -u guillermo -p ****** -y basic -J comando.xml
Y obtendremos el siguiente resultado:
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:x="http://schemas.xmlsoap.org/ws/2004/09/transfer" xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd" xml:lang="en-US">
<s:Header>
<a:Action>http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process/CreateResponse</a:Action>
<a:MessageID>uuid:052BAF01-65FC-45D0-83A1-467B3BA951CE</a:MessageID>
<a:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To>
<a:RelatesTo>uuid:a2f7fea2-414a-114a-8002-06d11fb660a8</a:RelatesTo>
</s:Header>
<s:Body>
<p:Create_OUTPUT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process" xmlns:cim="http://schemas.dmtf.org/wbem/wscim/1/common">
<p:ProcessId>364</p:ProcessId>
<p:ReturnValue>0</p:ReturnValue>
</p:Create_OUTPUT>
</s:Body>
</s:Envelope>
Nos fijamos en ProcessID
se ha creado un nuevo proceso en Windows para ejecutar el comando y además obtenemos un ReturnValue
con valor 0
que nos indica que ha finalizado correctamente.
Vamos al equipo Windows y vemos que se ha creado el fichero salida.txt
correctamente:

Windows para Pruebas
En mi caso dado que no tengo ningun equipo con Windows, he tenido que usar Docker + KVM
para poder iniciar un Windows usando https://github.com/dockur/windows
Todas las versiones de windows probadas son versiones Trial oficiales proporcionadas por Microsoft.
Además, para poder simular correctamente un PC con Windows y un Servidor Windows, he tenido que ampliar y ajustar los puertos necesarios para poder usar SSH y WinRM en ese contenedor.
Escucha de Eventos Windows
Además de wsman
, si usas los binarios del paquete wsmancli tienes el programa wseventmgr
que permite subscribirte via WS-Manager a los eventos de Windows.
Para obtener ayuda sobre todos los parametros necesarios para gestionar los eventos de windows ejecuta:
man wseventmgr
Tambien puedes usar wsman
para realizar la subscripción, en este caso te recomiendo usar un XML para facilitar la ejecución.
subscripcion.xml
<w:Subscribe xmlns:w="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd">
<w:Delivery Mode="Push">
<w:NotifyTo>
<a:Address>http://localhost:8080/receiver</a:Address>
</w:NotifyTo>
</w:Delivery>
<w:Filter Dialect="http://schemas.microsoft.com/wbem/wsman/1/WQL">
SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Service'
</w:Filter>
</w:Subscribe>
Y el comando a ejecutar en tu Linux sería:
wsman subscribe -h winpc -P 5985 -u guillermo -p ***** -y basic -J suscripcion.xml
Comandos WinRM con BashFlow
Como ya os he comentado sigo trabajando en BashFlow
como herramienta de automatización que funciona unicamente mediante comandos bash.
Como demostración os muestro como se simplifica el uso de WinRM, el playbook es muy sencillo.
winremote_exec_winrm.yaml
tasks:
- name: Ejecutar comando remoto en Windows vía WinRM (WS-Manager)
module: winremote_exec_winrm
args:
winuser: guillermo
winpassword: "{{ clave_guillermo }}"
command: "cmd.exe /c echo hola > C:\\salida.txt"
Simplemente debemos llamar a bashflow
indicando el playbook con los comandos windows deseados, ya sean CMD o PowerShell.
BashFlow recorre el playbook, extrae la password de guillermo del Vault y la usa de forma transparente en la llamada. Además se encapsula el comando y se crea al vuelo en XML necesario para la ejecución facilitando el uso de WinRM desde Linux en procesos de automatización.
bashflow -f winremote_exec_winrm.yml -h winpc
Captura de la ejecución y la salida:

¡ Nos vemos en el próximo artículo !