COM-Port eines Geräts ändern per Powershell

Einen COM-Port setzen? Nutzt man das heutzutage noch? Tatsächlich wird, wenn auch nur virtuell, für viele Anwendungen für ein USB-Gerät, wie einen Barcode-Scanner, ein COM-Port benötigt. In diesem Artikel zeige ich wie man diesen COM-Port per GUI zuweist und wie man dies auch per PowerShell machen kann. Man könnte denken, dies sei ein Einzeiler mit einem einfachen Kommando. Leider weit gefehlt, wie sich herausgestellt hat. Wieso das gar nicht so einfach ist und wie es trotzdem funktioniert zeige ich ausführlich in diesem Artikel.

 

COM-Ports ändern? Geht das?

Grundsätzlich weist Windows beim Anschließen eines entsprechenden Gerätes, das einen virtuellen COM-Port nutzt, den nächsten freien COM-Port automatisch zu.

Die einfache Variante um einen anderen COM-Port unter Windows zuzuweisen, findet man im Geräte-Manager. Hier kann man dem gewünschten Gerät einfach im Dropdown-Feld einen der freien COM-Ports zuweisen:

 

COM-Port-Zuweisung per PowerShell oder CMD?

Warum könnte es nötig sein die COM-Port-Belegung per Skript anzupassen? Dies ist dann der Fall, wenn eine ganze Menge von Endgeräten ohne entsprechend kundige Personen um das gewünschte Gerät erweitert werden sollen. Dies könnten beispielsweise POS-Geräte in Geschäften sein. Wenn die Anwendung die Eingabegeräte unter bestimmten COM-Ports erwartet, ist die Konfiguration der Ports nach dem Anstecken der Geräte nötig.

Leider ist es von Microsoft nicht empfohlen die COM-Ports manuell zuzuweisen. Laut Microsoft sollten Anwendungen den zum gewünschten Gerät passenden COM-Port selber auslesen oder damit konfiguriert sein. Per CMD oder PowerShell-Befehlen ist dies von Microsoft also nicht vorgesehen. Es gibt deshalb keine native Möglichkeit dafür.

Über Umwege funktioniert es allerdings doch. Der Weg dorthin ist tatsächlich ziemlich umständlich und erfordert tiefergehende Kenntnisse darüber, wie die Belegung der COM-Ports in der Registry gespeichert wird.

 

Manuelles Zuweisen mit der Registry

Das Zuweisen funktioniert über Umwege mit Hilfe der Registry. Dort werden in folgendem Registry-Eintrag die aktuell belegten bzw. freien Ports gespeichert:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter

Bei diesem Wert handelt es sich um 32 Hexadezimal-Zahlen. Zu allem Überfluss muss man den Inhalt dieser Zahlen binär betrachten:
In jedem Byte ist der Zustand von 8 Ports gespeichert. Im ersten Byte von Port 1 bis 8 und im letzten Byte von Port 248 bis 256.
Die dezimal gesehen zur Verfügung stehenden Zahlen gehen dabei pro Eintrag von 0 (Hexadezimal: 0) bis 255 (Hexademzimal: FF).

Hier einige Beispiele zu verschiedenen Belegungen wodurch die Funktionsweise hoffentlich klar wird:

  • Im ersten Byte FF (255) bedeutet Port 1 bis 8 sind belegt.
  • Im ersten Byte 7F (127) bedeutet Port 1 bis 7 sind belegt und Port 8 ist frei (noch 128 „frei“).
  • Im zweiten Byte 00 (0) bedeutet Port 9 bis 17 sind frei.
  • Alle Bytes mit FF bedeutet, dass kein COM-Port frei ist. In dem Fall scheint Windows weitere COM-Ports hinzu zu dichten und erweitert den gesamten Registry-Eintrag, wenn ein weiteres Gerät angeschlossen wird.

Die Änderungen im Registry-Eintrag kann man schön beobachten, wenn man einen Port per GUI umkonfiguriert und sich zuvor und danach den Registry-Eintrag und die dort stattfindenden Änderungen ansieht:

 

 

Skripten mt Hilfe der Powershell

Da es leider keine native Funktion für die CMD oder die Powershell gibt, muss man sich leider selbst behelfen.

Um sicher zu gehen, dass alle Geräte einen Port haben und beim Skriptabschluss keine Fehlzuweisung statfindet, wird erst einmal mit devcon nach neu angeschlossenen Geräten gescannt, damit alle Geräte im System mit einem COM-Port registriert sind:

Danach wird das Gerät, für welches der COM-Port geändert werden soll, mit Hilfe von devcon und der Vendor und Product-ID wieder aus der Systemkonfiguration herausgeschmissen:

 

Indo: Die devcon.exe bekommt man aus dem Windows Driver Kit (https://docs.microsoft.com/de-de/windows-hardware/drivers/download-the-wdk).

Damit man anhand der Port-Nummer „komfortabel“ eine Zuweisung vornehmen kann, muss man nun ein bisschen herumrechnen und herumtricksen. Wenn man die gewünschte Port-Nummer durch die Anzahl an Ports pro Hex-Eintrag im Registry-Eintrag teilt, erhält man eine Kommazahl. Anhand der Stellen nach dem Komma kann man den entsprechenden Wert der den Port binär repräsentiert ermitteln. Das war wahrscheinlich recht unverständlich beschrieben, anhand folgender Tabelle kann man die Zusammenhänge aber vermutlich besser nachvollziehen:

COM-Port Portnummer durch Anzahl der Ports pro Eintrag geteilt Nur Nachkommastellen ermittelt zugeordneter Bit-Wert Position in der Registry (durch Aufrunden)
1 0,125 0,125 1 1
2 0,250 0,250 2 1
3 0,375 0,375 4 1
4 0,500 0,500 8 1
5 0,625 0,625 16 1
6 0,750 0,750 32 1
7 0,875 0,875 64 1
8 1,000 0,000 128 1
9 1,125 0,125 1 2
10 1,250 0,250 2 2
11 1,375 0,375 4 2
12 1,500 0,500 8 2
13 1,625 0,625 16 2
14 1,750 0,750 32 2
15 1,875 0,875 64 2
16 2,000 0,000 128 2

 

Bevor irgendeine Änderung vorgenommen wird, ist es wichtig den aktuellen Zustand der Port-Belegung, nachdem man das Gerät entfernt hat, in einer Variable zwischenzusichern:

Die Position im Registry-Eintrag kann man durch Aufrunden der Kommazahl auf die nächste höhere Zahl ermitteln (Null Kommastellen).

 

Um nun einen bestimmten Port per Skript zu forcen müssen danach alle Ports, bis auf den gewünschten, als belegt in der Registry markiert werden und dann wieder ein Rescan mit devcon nach neuen Geräten stattfinden. Das Gerät bekommt dann automatisch den gewünschten einzigen noch freien Port zugewiesen. Den zuvor zugeordneten Bit-Wert muss man von 255 abziehen um zu ermitteln welcher Port freibleiben muss, um dadurch Windows dazu zu bringen diesen Port zu vergeben:

Am Ende muss der Arbiter-Eintrag in der Registry dann wieder korrigiert werden, sodass nur die tatsächlich belegten Ports dort stehen. Dies passiert durch den vor den Änderungen in der Variable zwischengespeicherten Registry-Eintrag der rechnerisch um den nun belegten Port abgeändert wird:

 

 

 

Alternative?

Auf einer Seite las ich, dass der COM-Port unter Windows 10 auch irgendwo unter Einträgen der entsprechenden Geräte angegeben werden kann. Allerdings muss der „Arbiter“-Eintrag in der Registry trotzdem noch angepasst werden. Von daher hätte man durch diese „einfache“ Änderung nichts gewonnen, da das Herumrechnen trotzdem stattfinden muss. Allerdings könnte man sich dadurch dieses Herumhantieren mit devcon sparen…

 

Einschränkungen der Funktion

  • Wenn der Arbiter-Eintrag in der Registry bei Aufruf der Funktion schon schief hängt und nicht zur tatsächlichen Port-Belegung passt wird dieser nicht gerade gezogen.
  • Der COM-Port 256 sollte nach Möglichkeit nicht genutzt werden, da dieser als „temporärer“ Port „missbraucht“ wird um einer Doppelbelegung vorzubeugen.

 

Fazit

Manchmal ziehen für theoretisch einfache Dinge wie das automatische Anpassen eines COM-Ports ordentlich Stunden ins Land. Hoffentlich erspart sich der ein oder andere diese mit Hilfe meiner Funktion für PowerShell. Auch wenn die Lösung extrem „von hinten durch die Brust“ geraten ist, pass sie doch nun sehr der Art wie bei Microsoft so manches implementiert ist 😀

 

Schreibe einen Kommentar