Tutoriales

MQTT desde PowerShell en Windows

Publica y suscríbete a MQTT desde PowerShell en Windows: mosquitto_pub y mosquitto_sub en pipelines, MQTTnet cargado en pwsh, TLS y tareas programadas.

Actualizado · 9 min de lectura

MQTT desde PowerShell en Windows

PowerShell no trae cmdlets de MQTT, pero hay dos formas fiables de hablar con un broker desde un script de Windows: llamar a los ejecutables mosquitto_pub / mosquitto_sub y tratar su salida como un pipeline, o cargar la librería .NET MQTTnet directamente en PowerShell 7. La primera es perfecta para one-liners, health checks y tareas programadas; la segunda te da una conexión persistente y control total desde un único archivo .ps1.

Esta guía cubre ambas, incluidas las dos trampas en las que cae casi todo el mundo: comillas que desaparecen de los payloads JSON y event handlers que fallan con "no Runspace available". Todos los ejemplos usan broker.connectmq.com; deja abierto el cliente MQTT online para ver llegar los mensajes.

¿Qué enfoque elegir?

Clientes mosquittoMQTTnet en PowerShell 7
InstalaciónInstalador de Mosquitto para WindowsUna DLL de NuGet
Funciona en Windows PowerShell 5.1SíNo recomendado
Conexión persistenteNo (un proceso por llamada)Sí
Recepción de mensajesLeer stdout línea a líneaCola + bucle de sondeo
Ideal paraAlertas, health checks, pruebas rápidasScripts de larga duración, tooling, código de integración

Si acabas escribiendo más de una página de PowerShell alrededor de MQTTnet, una pequeña app de consola en C# suele ser mejor herramienta: consulta MQTT en C# con MQTTnet.

Opción 1: mosquitto_pub y mosquitto_sub

Descarga el instalador para Windows desde mosquitto.org. Instala el broker (puedes omitir el servicio) y los clientes de línea de comandos en C:\Program Files\mosquitto. Añade esa carpeta a tu PATH y prueba la conexión:

@@CODE1@@

$LASTEXITCODE vale 0 si todo va bien y es distinto de cero cuando falla la conexión o la autenticación, que es todo lo que necesita un script. Si TcpTestSucceeded es False, el problema es la red y no MQTT: comprueba si el puerto está abierto y el firewall de Windows. Si quieres ejecutar un broker en la misma máquina, broker MQTT en Windows explica cómo configurar el servicio.

Enviar JSON sin perder las comillas

Este es el bug de MQTT más común y específico de PowerShell. En Windows PowerShell 5.1 y PowerShell 7.0–7.2, las comillas dobles internas se eliminan al pasar argumentos a un .exe nativo, así que el suscriptor recibe {device:pc-01} en lugar de JSON válido. PowerShell 7.3 corrigió el paso de argumentos, pero la solución robusta funciona en todas partes: construye el objeto con ConvertTo-Json y pásalo por pipe a mosquitto_pub -s, que lee el mensaje desde la entrada estándar.

@@CODE2@@

PowerShell añade un salto de línea final al enviar datos por pipe a un programa nativo; los parsers de JSON lo ignoran. Usa -l en lugar de -s para enviar cada línea de entrada como un mensaje separado.

Procesar mensajes entrantes en un pipeline

mosquitto_sub -v imprime topic payload por línea, y PowerShell convierte cada línea en un objeto del pipeline:

@@CODE3@@

Para una comprobación que espera exactamente un mensaje, añade -C 1 -W 10: mosquitto_sub termina tras el primer mensaje o tras diez segundos, con un código de salida distinto de cero si vence el tiempo. Tienes más flags en ejemplos de mosquitto_pub y mosquitto_sub.

Opción 2: MQTTnet dentro de PowerShell 7

MQTTnet es la librería MQTT para .NET más utilizada. PowerShell 7 corre sobre .NET moderno, así que puede cargar la DLL directamente. Descarga un paquete 4.x de NuGet y extrae el build netstandard2.0:

@@CODE4@@

Conectar y publicar funciona directamente desde PowerShell. Los métodos async devuelven tasks, así que llama a .GetAwaiter().GetResult() para esperarlos (además muestra la excepción real en lugar de una AggregateException):

@@CODE5@@

El encadenamiento de métodos con punto al inicio de línea requiere PowerShell 7. Un login fallido lanza una excepción como Connecting with MQTT server failed (BadUserNameOrPassword). o (NotAuthorized); la consulta de reason codes MQTT explica cada valor.

Recibir mensajes sin el fallo del runspace

El enfoque obvio — $client.add_ApplicationMessageReceivedAsync({ ... }) — falla tarde o temprano con:

There is no Runspace available to run scripts in this thread.

MQTTnet lanza el evento en un hilo del thread pool de .NET, y un script block de PowerShell solo puede ejecutarse en un hilo que tenga un runspace. La solución limpia son unas pocas líneas de C# que meten cada mensaje en una cola thread-safe; tu bucle de PowerShell los saca en su propio hilo.

@@CODE6@@

El timeout de 500 ms mantiene el bucle sensible a Ctrl+C, y el bloque finally envía un DISCONNECT limpio para que el broker no dispare un Last Will. Add-Type solo puede definir un tipo una vez por sesión; ejecutar el script dos veces en la misma consola da Cannot add type. The type name 'MqttInbox' already exists. — abre una nueva sesión pwsh o protege la llamada con if (-not ('MqttInbox' -as [type])).

Publica en testmqtt/ps/hello desde el cliente online y la línea debería aparecer en menos de un segundo.

Envía un mensaje a tu listener de PowerShell

TLS

Cambia al puerto 8883 y activa TLS en el builder de opciones. MQTTnet valida el certificado del broker contra el almacén de certificados de Windows, así que un broker con certificado público no necesita nada más:

@@CODE7@@

Un heartbeat programado

Combinando las piezas: un script que publica el estado de la máquina y una tarea programada que lo ejecuta cada cinco minutos.

@@CODE8@@

@@CODE9@@

--cafile apunta a un archivo PEM que contiene la CA que firmó el certificado de tu broker. Los fallos se escriben en un archivo de log, y el código de salida distinto de cero aparece como "Last Run Result" de la tarea en el Programador de tareas. La tarea anterior se ejecuta como tu usuario mientras tienes la sesión iniciada; para servidores desatendidos, regístrala con una cuenta de servicio y guarda las credenciales como variables de entorno de esa cuenta o con el módulo SecretManagement. Suscríbete a testmqtt/ps/+/status para ver cómo informa cada máquina.

Solución de problemas

ErrorCausaSolución
mosquitto_pub : The term 'mosquitto_pub' is not recognizedLa carpeta de instalación no está en el PATHAñade C:\Program Files\mosquitto al PATH
Error: Connection refusedPuerto incorrecto o el broker rechazó la conexiónTest-NetConnection -Port; revisa puerto frente a TLS
Unable to find type [MQTTnet.MqttFactory]DLL no cargada, o una DLL 5.x con otros namespacesEjecuta antes Add-Type -Path; usa un paquete 4.x
Connecting with MQTT server failed (BadUserNameOrPassword).Credenciales incorrectas o variables de entorno vacíasImprime $env:MQTT_USER; busca erratas
There is no Runspace available to run scripts in this thread.Script block usado como event handler de MQTTnetUsa la cola en C# mostrada arriba
El JSON llega sin comillasPaso de argumentos nativos en PS 5.1 / 7.0–7.2Pásalo por pipe a mosquitto_pub -s

PowerShell es un cliente MQTT perfectamente válido cuando conoces sus manías: pasa el JSON por stdin, comprueba $LASTEXITCODE y deja los eventos de MQTTnet en el lado .NET de una cola. Para la misma automatización en Linux, consulta MQTT en scripts Bash.

Preguntas frecuentes

¿Puede PowerShell publicar mensajes MQTT sin software adicional?

No de forma nativa: PowerShell no tiene cmdlets de MQTT. Las dos opciones prácticas son los ejecutables mosquitto_pub y mosquitto_sub del instalador de Mosquitto para Windows, o cargar la librería .NET MQTTnet en PowerShell 7 con Add-Type.

¿Por qué recibo "There is no Runspace available to run scripts in this thread"?

Has asociado un script block de PowerShell a un evento de MQTTnet. MQTTnet lanza los eventos en hilos del thread pool de .NET que no tienen runspace de PowerShell, así que el script block no puede ejecutarse. Encola los mensajes en un pequeño helper de C# y lee la cola desde tu bucle de PowerShell.

¿Por qué mosquitto_pub recibe mi JSON sin comillas en PowerShell?

Windows PowerShell 5.1 y PowerShell 7.0 a 7.2 eliminan las comillas dobles internas al pasar argumentos a programas nativos. Actualiza a PowerShell 7.3 o superior, o pasa el JSON por pipe a mosquitto_pub -s para que se lea desde la entrada estándar.