PowerShell bringt keine MQTT-Cmdlets mit, aber es gibt zwei zuverlässige Wege, aus einem Windows-Skript mit einem Broker zu sprechen: die Programme mosquitto_pub / mosquitto_sub aufrufen und ihre Ausgabe als Pipeline behandeln oder die .NET-Bibliothek MQTTnet direkt in PowerShell 7 laden. Der erste Weg ist ideal für Einzeiler, Health Checks und geplante Aufgaben; der zweite gibt dir eine dauerhafte Verbindung und volle Kontrolle aus einer einzigen .ps1-Datei.
Dieser Guide behandelt beide – inklusive der zwei Fallen, in die fast jeder tappt: Anführungszeichen, die aus JSON-Payloads verschwinden, und Event-Handler, die mit „no Runspace available“ abstürzen. Alle Beispiele nutzen broker.connectmq.com; lass den Online-MQTT-Client offen, um die Nachrichten ankommen zu sehen.
Welcher Ansatz?
| mosquitto-Clients | MQTTnet in PowerShell 7 | |
|---|---|---|
| Installation | Mosquitto-Installer für Windows | Eine DLL von NuGet |
| Läuft in Windows PowerShell 5.1 | Ja | Nicht empfohlen |
| Dauerhafte Verbindung | Nein (ein Prozess pro Aufruf) | Ja |
| Nachrichten empfangen | stdout zeilenweise lesen | Queue + Polling-Schleife |
| Ideal für | Alarme, Health Checks, schnelle Tests | Lang laufende Skripte, Tooling, Glue-Code |
Wenn du am Ende mehr als eine Seite PowerShell rund um MQTTnet schreibst, ist eine kleine C#-Konsolen-App meist das bessere Werkzeug – siehe MQTT in C# mit MQTTnet.
Option 1: mosquitto_pub und mosquitto_sub
Lade den Windows-Installer von mosquitto.org herunter. Er installiert den Broker (den Dienst kannst du weglassen) und die Kommandozeilen-Clients nach C:\Program Files\mosquitto. Füge diesen Ordner zum PATH hinzu und teste die Verbindung:
@@CODE1@@
$LASTEXITCODE ist bei Erfolg 0 und ungleich null, wenn Verbindung oder Authentifizierung scheitern – mehr braucht ein Skript nicht. Ist TcpTestSucceeded False, liegt das Problem im Netzwerk und nicht bei MQTT – prüfe, ob der Port offen ist, und die Windows-Firewall. Willst du einen Broker auf derselben Maschine betreiben, erklärt MQTT-Broker unter Windows die Einrichtung als Dienst.
JSON senden, ohne die Anführungszeichen zu verlieren
Das ist der häufigste PowerShell-spezifische MQTT-Bug. In Windows PowerShell 5.1 und PowerShell 7.0–7.2 werden eingebettete doppelte Anführungszeichen entfernt, wenn Argumente an eine native .exe gehen – der Subscriber erhält dann {device:pc-01} statt gültigem JSON. PowerShell 7.3 hat die Argumentübergabe korrigiert, aber die robuste Lösung funktioniert überall: Baue das Objekt mit ConvertTo-Json und leite es per Pipe an mosquitto_pub -s weiter, das die Nachricht von der Standardeingabe liest.
@@CODE2@@
PowerShell hängt beim Pipen an ein natives Programm einen Zeilenumbruch an; JSON-Parser ignorieren ihn. Nutze -l statt -s, um jede Eingabezeile als eigene Nachricht zu senden.
Eingehende Nachrichten in einer Pipeline verarbeiten
mosquitto_sub -v gibt pro Zeile topic payload aus, und PowerShell macht aus jeder Zeile ein Pipeline-Objekt:
@@CODE3@@
Für einen Check, der auf genau eine Nachricht wartet, ergänze -C 1 -W 10: mosquitto_sub beendet sich nach der ersten Nachricht oder nach zehn Sekunden, bei Timeout mit einem Exit-Code ungleich null. Weitere Flags findest du in mosquitto_pub- und mosquitto_sub-Beispiele.
Option 2: MQTTnet in PowerShell 7
MQTTnet ist die meistgenutzte MQTT-Bibliothek für .NET. PowerShell 7 läuft auf modernem .NET und kann die DLL daher direkt laden. Lade ein 4.x-Paket von NuGet herunter und entpacke den netstandard2.0-Build:
@@CODE4@@
Verbinden und Publizieren funktioniert direkt aus PowerShell. Async-Methoden liefern Tasks; rufe .GetAwaiter().GetResult() auf, um auf sie zu warten (das zeigt außerdem die eigentliche Exception statt einer AggregateException):
@@CODE5@@
Das Method Chaining mit führendem Punkt erfordert PowerShell 7. Ein fehlgeschlagener Login wirft eine Exception wie Connecting with MQTT server failed (BadUserNameOrPassword). oder (NotAuthorized); das MQTT-Reason-Code-Nachschlagewerk erklärt jeden Wert.
Nachrichten empfangen ohne Runspace-Absturz
Der naheliegende Ansatz – $client.add_ApplicationMessageReceivedAsync({ ... }) – scheitert früher oder später mit:
There is no Runspace available to run scripts in this thread.
MQTTnet löst das Event auf einem .NET-Threadpool-Thread aus, und ein PowerShell-Scriptblock kann nur auf einem Thread mit Runspace laufen. Die saubere Lösung sind ein paar Zeilen C#, die jede Nachricht in eine threadsichere Queue legen; deine PowerShell-Schleife holt sie auf ihrem eigenen Thread ab.
@@CODE6@@
Der Timeout von 500 ms hält die Schleife für Strg+C ansprechbar, und der finally-Block sendet ein sauberes DISCONNECT, damit der Broker keinen Last Will auslöst. Add-Type kann einen Typ nur einmal pro Sitzung definieren; startest du das Skript zweimal in derselben Konsole, erhältst du Cannot add type. The type name 'MqttInbox' already exists. – öffne eine neue pwsh-Sitzung oder schütze den Aufruf mit if (-not ('MqttInbox' -as [type])).
Publiziere aus dem Online-Client auf testmqtt/ps/hello, und die Zeile sollte innerhalb einer Sekunde erscheinen.
Eine Nachricht an deinen PowerShell-Listener senden
TLS
Wechsle auf Port 8883 und aktiviere TLS im Options-Builder. MQTTnet prüft das Broker-Zertifikat gegen den Windows-Zertifikatspeicher, ein Broker mit öffentlichem Zertifikat braucht also nichts weiter:
@@CODE7@@
Ein geplanter Heartbeat
Alles zusammen: ein Skript, das den Maschinenstatus publiziert, und eine geplante Aufgabe, die es alle fünf Minuten ausführt.
@@CODE8@@
@@CODE9@@
--cafile zeigt auf eine PEM-Datei mit der CA, die das Zertifikat deines Brokers signiert hat. Fehler landen in einer Logdatei, und der Exit-Code ungleich null erscheint in der Aufgabenplanung als „Letztes Ausführungsergebnis“. Die obige Aufgabe läuft unter deinem Benutzer, solange du angemeldet bist – für unbeaufsichtigte Server registrierst du sie mit einem Dienstkonto und hinterlegst die Zugangsdaten als Umgebungsvariablen dieses Kontos oder mit dem SecretManagement-Modul. Abonniere testmqtt/ps/+/status, um jede Maschine melden zu sehen.
Fehlerbehebung
| Fehler | Ursache | Lösung |
|---|---|---|
mosquitto_pub : The term 'mosquitto_pub' is not recognized | Installationsordner nicht im PATH | C:\Program Files\mosquitto zum PATH hinzufügen |
Error: Connection refused | Falscher Port oder der Broker hat die Verbindung abgelehnt | Test-NetConnection -Port; Port vs. TLS prüfen |
Unable to find type [MQTTnet.MqttFactory] | DLL nicht geladen oder eine 5.x-DLL mit anderen Namespaces | Zuerst Add-Type -Path ausführen; ein 4.x-Paket nutzen |
Connecting with MQTT server failed (BadUserNameOrPassword). | Falsche Zugangsdaten oder leere Umgebungsvariablen | $env:MQTT_USER ausgeben; auf Tippfehler prüfen |
There is no Runspace available to run scripts in this thread. | Scriptblock als MQTTnet-Event-Handler | Die oben gezeigte C#-Queue verwenden |
| JSON kommt ohne Anführungszeichen an | Native Argumentübergabe in PS 5.1 / 7.0–7.2 | Per Pipe an mosquitto_pub -s übergeben |
PowerShell ist ein völlig brauchbarer MQTT-Client, sobald du seine Eigenheiten kennst: JSON über stdin schicken, $LASTEXITCODE prüfen und MQTTnet-Events auf der .NET-Seite einer Queue halten. Dieselbe Automatisierung unter Linux zeigt MQTT in Bash-Skripten.
Häufig gestellte Fragen
Kann PowerShell MQTT-Nachrichten ohne zusätzliche Software senden?
Nicht nativ – PowerShell hat keine MQTT-Cmdlets. Die zwei praktischen Optionen sind die Programme mosquitto_pub und mosquitto_sub aus dem Mosquitto-Installer für Windows oder die .NET-Bibliothek MQTTnet, die du mit Add-Type in PowerShell 7 lädst.
Warum bekomme ich "There is no Runspace available to run scripts in this thread"?
Du hast einen PowerShell-Scriptblock an ein MQTTnet-Event gehängt. MQTTnet löst Events auf .NET-Threadpool-Threads aus, die keinen PowerShell-Runspace haben, daher kann der Scriptblock nicht laufen. Stelle Nachrichten in einem kleinen C#-Helper in eine Queue und lies diese in deiner PowerShell-Schleife aus.
Warum kommt mein JSON in PowerShell ohne Anführungszeichen bei mosquitto_pub an?
Windows PowerShell 5.1 und PowerShell 7.0 bis 7.2 entfernen eingebettete doppelte Anführungszeichen, wenn sie Argumente an native Programme übergeben. Aktualisiere auf PowerShell 7.3 oder neuer oder leite das JSON per Pipe an mosquitto_pub -s weiter, damit es von der Standardeingabe gelesen wird.


