WinRM y WS-Management. Automatizar Windows desde Linux

Linux Nivel Alto 16 de oct. de 2025

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:

ssh y ejecucion de comandos en Windows

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í:

bashflow conectandose a un equipo Windows

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-manager wsman 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:

Comando para crear fichero, ejecutado en remoto 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:

bashflow ejecutando playbooks mediante WS-Manager
¡ Nos vemos en el próximo artículo !

Etiquetas

Luis GuLo

🐧 SysAdmin GNU/Linux - 🐳 Docker - 🖥️ Bash Scripting - 🐪 Perl - 🐬 MySQL - 👥 Formador de TI - 👥 Formador de SysAdmin's - 💢 Ansible - ☁️ Cloud Computing - ❤️ Debian GNU/Linux