IT

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, diesem den nächsten freien COM-Port einfach 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 noch freien COM-Ports zuweisen:

Auch eine Umsortierung der COM-Ports ist hier über die GUI möglich. Ob ein Port schon vergeben ist erkennt man durch den Zusatz „(bereits belegt)“ hinter dem COM-Port. Sollte der gewünschte COM-Port bereits durch ein anderes Gerät belegt sein ist das aber auch kein Problem. Hierzu muss man den gewünschten COM-Port einfach wieder freigeben, indem man dem zugeordneten Gerät einfach einen anderen COM-Port zuweist.

 

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 vor Ort, 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 dies oft der Fall und grausig, dass ein Umkonfigurieren per GUI erledigt werden muss und nicht in einer Silent-Installation verteilt werden kann.

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

Komplizierter konnte man das wohl kaum in der Registry abbilden.

 

Skripten mit 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:

 

Info: Die devcon.exe bekommt man aus dem Windows Driver Kit, dass man hier runterladen kann: https://docs.microsoft.com/de-de/windows-hardware/drivers/download-the-wdk. Diese ist unter Windows nicht standardmäßig zu finden.

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 erzwingen müssen danach alle Ports, bis auf den gewünschten, als belegt in der Registry markiert werden und dann wieder ein „Rescan“ mit „devcon.exe“ nach neuen Geräten stattfinden. Das Gerät bekommt dann automatisch den gewünschten einzigen noch freien Port zugewiesen. Man geht hier also „umgekehrt“ vor und nimmt dem Gerät einfach alle unerwünschten Ports weg.

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:

 

Wenn du noch nicht so fit im Umgang mit der Powershell bist, gibt es hier einen Anfängerkurs* mit 23 Lektionen, Testfragen, Skriptbeispielen, Handouts und mehr als 4 Stunden Videomaterial!

 

 

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.exe sparen und muss nicht dauernd die COM-Geräte wieder scannen…

 

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 Stunden mit Hilfe meiner Funktion für die PowerShell. Auch wenn die Lösung extrem „von hinten durch die Brust“ geraten ist, passt sie doch nun sehr zu der Art wie bei Microsoft so manches implementiert ist 😀

 

Weitere interessante Artikel zur Windows Powershell:

Screenshots mit PowerShell automatisch unter Windows speichern
Welche PowerShell-Version habe ich? – PowerShell-Version anzeigen
Was ist PowerShellCore? Windows PowerShell unter Linux und MacOS?
Powershell und CMD: Clear um Konsole zu leeren?
Powershell: Sudo-Befehl wie unter Linux nutzen für Administratorrechte?
COM-Port eines Geräts ändern per Powershell
CMD/Powershell: Ping-Ergebnis mit Errorlevel auswerten
Powershell: Netzwerkadapter-Konfiguration ändern (IP-Adresse, Gateway, DNS, DHCP)
Powershell-Skript als Benutzer-Anmeldeskript in einer Domäne nutzen?
Powershell: Fenster nach Skriptausführung nicht automatisch schließen
Powershell: UTF8-Problem beim Export
XML-Bearbeitung mit Powershell
Replace und Escaping in Powershell
MessageBox mit Powershell auf anderen Computern anzeigen
While- und Until-Schleifen in PowerShell und Batch
Einfaches inkrementelles Backup mit Powershell
Einfache Außer-Haus-Sicherung mit Powershell
Schnittstelle von XML zu MS-SQL mit Powershell realisieren
Powershell: Automatische Anwendungssteuerung
Macht die ExecutionPolicy für Powershell-Skripte Sinn?
Wiederkehrende E-Mail-Abwesenheitsnotiz für Outlook mit Powershell
HyperV-Netzwerkadapter per Powershell umbenennen und entfernen
Powershell: DELL Service Tags auslesen
Powershell-Backup-Skript für den Thunderbird-Profilordner
Download-Skript in Powershell
Einfache Powershell-Skripte
Java-Anwendungen über CMD oder Powershell starten
Pfad im Explorer schneller kopieren – auch als vollständigen UNC-Pfad
Windows 11: Startmenü anpassen, klassische Taskleiste, links ausrichten
Wie lange läuft mein PC schon? – PC Laufzeit auslesen unter Windows 10
Windows 10: Standorttyp des Netzwerks ändern
Windows Server 2016: WSUS startet nicht vernünftig
 
Tobias Langner

Tobias Langner

Ich arbeite seit mehreren Jahren als Software-Release-Manager, zuvor als IT-Administrator, bin ausgebildeter Fachinformatiker für Systemintegration und Studium-"Pausierer" an der FernUni Hagen. Achtung: Für die Richtigkeit der zur Verfügung gestellten Informationen, Skripte, etc. übernehme ich keine Gewähr. Deren Nutzung geschieht ausdrücklich auf eigene Gefahr!

Alle Beiträge ansehen von Tobias Langner →

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert