feat: initiale Version 0.1.0 des MSTSC Script Hooks

- Native x64 MSTSC-DVC-Erweiterung für lokalen Programmstart
- Automatischer Script-/Programmstart bei RDP-Verbindungsaufbau
- Separater Programmstart über Trigger innerhalb der RDP-Sitzung
- Bidirektionaler DVC zur Ermittlung des lokalen Client-Hostnamens
- SIOMIN-Trigger zur Anbindung lokaler Sidexis-Installationen
- SIOMIN-Datensatzlängen und Hostname-Felder bytegenau angepasst
- Temporäre SIOMIN-Einträge nach erfolgreicher Übernahme bereinigt
- Native Win32-Konfigurationsoberfläche ohne .NET-Abhängigkeit
- Mehrfachstartschutz und optionaler unsichtbarer Programmstart
- Debug- und Plugin-Logging ergänzt
- RemoteVDDS-Anwendungsfall integriert
- Installer/Registrierung des MSTSC-Plugins über Client-Konfigurator
- Techniker-, Entwickler- und Projektdokumentation ergänzt
- Proprietäre Lizenz für Copyright Patrick Gniza hinzugefügt
This commit is contained in:
2026-08-11 16:32:33 +02:00
parent ee88f1ff30
commit 4c51989600
37 changed files with 4885 additions and 1475 deletions
+195 -244
View File
@@ -1,283 +1,234 @@
# Plandent MSTSC Script Hook
Windows-Projekt für den klassischen Microsoft Remote Desktop Connection Client (`mstsc.exe`). Das Client-Plugin kann lokale Programme auf zwei voneinander getrennten Wegen starten:
Native Windows-x64-Lösung zur Verbindung von lokal auf einem RDP-Client installierten Programmen mit Anwendungen und Abläufen innerhalb einer Terminalserver-Sitzung.
1. **Automatisch beim erfolgreichen RDP-Verbindungsaufbau**.
2. **Gezielt durch `PlandentRdpClientTrigger.exe` innerhalb der Terminalserver-Sitzung**.
Das Projekt ist insbesondere für drei praktische Einsatzfälle vorgesehen:
Der Terminalserver überträgt dabei **keinen Programmpfad und keine Argumente**. Die Server-EXE sendet ausschließlich einen festen `START`-Befehl über einen RDP Dynamic Virtual Channel (DVC). Welches lokale Programm mit welchen Parametern gestartet wird, wird ausschließlich auf dem Client in der Registry konfiguriert.
1. **RemoteVDDS-Receiver beim Aufbau einer RDP-Verbindung automatisch lokal starten.**
2. **Ein fest vorkonfiguriertes lokales Programm bei Bedarf aus der RDP-Sitzung starten.**
3. **Eine Anwendung innerhalb der RDP-Sitzung über SIOMIN/SLIDA mit einem lokal installierten Sidexis verbinden.**
Die Lösung ist für den klassischen Microsoft Remote Desktop Connection Client `mstsc.exe` ausgelegt.
## Typischer Einsatzzweck
In einer Terminalserver-Umgebung befinden sich Praxissoftware oder andere Fachanwendungen innerhalb der RDP-Sitzung, während bestimmte Programme auf dem lokalen Arbeitsplatzrechner ausgeführt werden müssen.
Der Plandent MSTSC Script Hook stellt dafür eine kontrollierte Verbindung zwischen Terminalserver-Sitzung und lokalem Client bereit. Programme und Parameter werden ausschließlich auf dem Client vorkonfiguriert. Eine Anwendung auf dem Terminalserver kann keinen beliebigen lokalen Programmpfad übergeben.
## Komponenten
### Client
### Lokaler RDP-Client
- **PlandentMstscScriptHook.dll** – native x64 DVC-Plugin-DLL, die von `mstsc.exe` geladen wird.
- **PlandentMstscScriptHook.exe** – WinForms-Konfigurator/Installer. Die Release-EXE enthält die DLL als Resource und extrahiert sie bei der Installation.
**`PlandentMstscScriptHook.exe`**
Konfiguration und Installation des Client-Plugins. Hier werden zwei voneinander unabhängige Starts eingerichtet:
- automatischer Programm-/Scriptstart nach erfolgreichem RDP-Verbindungsaufbau,
- Programm-/Scriptstart auf Anforderung aus der Terminalserver-Sitzung.
Die benötigte Plugin-DLL ist in der EXE eingebettet und wird bei der Installation automatisch eingerichtet.
### Terminalserver
- **PlandentRdpClientTrigger.exe** – kleine native x64 Windows-EXE ohne GUI und ohne Parameter. Sie wird **innerhalb der betreffenden RDP-Benutzersitzung** ausgeführt und sendet den festen Start-Trigger an den Client dieser Sitzung.
**`PlandentRdpClientTrigger.exe`**
## Architektur
Löst innerhalb der aktuellen RDP-Sitzung den auf dem Client vorkonfigurierten Programmstart aus.
Die EXE benötigt keine Parameter. Welches Programm gestartet wird, ist ausschließlich auf dem lokalen Client hinterlegt.
**`PlandentSiominClientTrigger.exe`**
Spezialisierter Trigger zur Anbindung einer Anwendung innerhalb der RDP-Sitzung an ein lokal installiertes Sidexis.
Der Trigger:
- ermittelt den tatsächlichen Hostnamen des lokalen RDP-Clients,
- übernimmt einen temporär erzeugten SIOMIN-/SLIDA-Eintrag,
- ersetzt darin den Terminalservernamen durch den Hostnamen des lokalen Clients,
- schreibt den angepassten Eintrag in die finale `siomin.sdx`,
- leert anschließend die temporäre Datei,
- startet danach das auf dem Client konfigurierte Programm.
## RemoteVDDS
Ein vorgesehener Anwendungsfall ist die Verwendung mit den **RemoteVDDS-Scripten von Tobias Bauer**.
Der RemoteVDDS-Receiver kann über den Bereich **Automatischer Start bei RDP-Verbindung** auf dem Client eingetragen werden. Dadurch wird der Receiver beim Aufbau der Terminalserver-Verbindung automatisch und auf Wunsch unsichtbar im Hintergrund gestartet.
Beispiel:
```text
LOKALER CLIENT TERMINALSERVER
================ ==============
Programm/Script:
C:\RemoteVDDS\RemoteVDDS_Receiver_TS.bat
mstsc.exe
│
└── PlandentMstscScriptHook.dll
│
├── Connected()
│ └── optional: lokales RDP-Verbindungsprogramm
│
└── DVC Listener
plandent::mstsc-script-hook
▲
│ fester Befehl:
│ PLANDENT_MSTSC_HOOK/1 START
│
└──────────────────── PlandentRdpClientTrigger.exe
│
└── läuft in der RDP-Sitzung
Argumente:
MIN
Nach START liest die DLL ausschließlich lokal:
HKCU\Software\Plandent\MstscScriptHook
TriggerProgramPath
TriggerArguments
TriggerWorkingDirectory
Unsichtbar starten:
Ja
Mehrfachstart verhindern:
Ja
```
## Sicherheit des Triggers
Bei Auswahl einer Datei mit `RemoteVDDS_Receiver_TS` im Namen schlägt der Konfigurator bei leeren Argumenten automatisch `MIN` vor.
Die Server-Komponente ist absichtlich minimal gehalten:
Die RemoteVDDS-Scripte selbst sind **nicht Bestandteil dieses Projekts** und unterliegen den Rechten ihres jeweiligen Autors.
- keine Kommandozeilenparameter für das Client-Programm,
- kein Pfad wird vom Terminalserver übertragen,
- keine beliebigen Befehle werden akzeptiert,
- ausschließlich die exakte Protokollnachricht `PLANDENT_MSTSC_HOOK/1 START` wird verarbeitet,
- Programmpfad und Argumente stammen nur aus der lokalen HKCU-Konfiguration des angemeldeten Client-Benutzers.
## Programmstart aus der RDP-Sitzung
Damit kann `PlandentRdpClientTrigger.exe` nur den vorher auf dem Client festgelegten Start auslösen.
Soll ein lokales Programm nicht bei jeder RDP-Verbindung, sondern nur bei Bedarf gestartet werden, wird es auf dem Client im Bereich **Programmstart durch Terminalserver** konfiguriert.
## Registry
MSTSC-Registrierung pro Benutzer:
```text
HKCU\Software\Microsoft\Terminal Server Client\Default\AddIns\PlandentMstscScriptHook
Name = C:\Users\<Benutzer>\AppData\Local\Plandent\MstscScriptHook\PlandentMstscScriptHook.dll
```
Konfiguration:
```text
HKCU\Software\Plandent\MstscScriptHook
Enabled REG_DWORD 1
EnableLogging REG_DWORD 1
; Automatischer Start bei RDP-Verbindung
ScriptPath REG_EXPAND_SZ C:\RemoteVDDS\RemoteVDDS_Receiver_TS.bat
Arguments REG_SZ MIN
WorkingDirectory REG_EXPAND_SZ C:\RemoteVDDS
StartOnConnect REG_DWORD 1
StopOnDisconnect REG_DWORD 0
Hidden REG_DWORD 1
PreventDuplicates REG_DWORD 1
; Separates Programm für den Terminalserver-Trigger
TriggerEnabled REG_DWORD 1
TriggerProgramPath REG_EXPAND_SZ C:\Program Files\Plandent\ClientTool.exe
TriggerArguments REG_SZ --receive --silent
TriggerWorkingDirectory REG_EXPAND_SZ C:\Program Files\Plandent
TriggerHidden REG_DWORD 1
TriggerPreventDuplicates REG_DWORD 1
```
Die bisherigen Registry-Werte für den automatischen RDP-Start bleiben kompatibel.
## Unterstützte lokale Starttypen
Für beide Startarten werden unterstützt:
- `.bat` / `.cmd` → `cmd.exe /D /S /C ...`
- `.ps1` → Windows PowerShell mit `-NoProfile -NonInteractive -ExecutionPolicy Bypass -File ...`
- `.exe` → direkter Start
Bei aktivierter Option **Unsichtbar starten** werden Konsolenprogramme ohne sichtbares Konsolenfenster gestartet.
## Mehrfachstartschutz
Für beide Programme existiert eine getrennt konfigurierbare Option **Mehrfachstart verhindern**.
Der Schutz wird aus dem expandierten Programmpfad abgeleitet und verwendet einen Named Mutex unter:
```text
Local\Plandent.MstscScriptHook.<Hash>
```
Das Mutex-Handle wird an den gestarteten Root-Prozess vererbt. Solange dieser Prozess läuft, wird ein erneuter Start desselben Pfades verhindert.
## Dynamic Virtual Channel
Das Client-Plugin registriert in `IWTSPlugin::Initialize()` den DVC-Listener:
```text
plandent::mstsc-script-hook
```
Wenn `PlandentRdpClientTrigger.exe` innerhalb der RDP-Sitzung läuft, öffnet sie mit `WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, ..., WTS_CHANNEL_OPTION_DYNAMIC)` genau diesen Kanal und sendet den festen Startbefehl.
Auf dem Client nimmt `IWTSListenerCallback::OnNewChannelConnection()` den Kanal an. `IWTSVirtualChannelCallback::OnDataReceived()` akzeptiert ausschließlich die definierte `START`-Nachricht und startet anschließend das lokal konfigurierte Trigger-Programm.
## Terminalserver-Trigger verwenden
`PlandentRdpClientTrigger.exe` benötigt keine Argumente:
```powershell
.\PlandentRdpClientTrigger.exe
```
Sie sollte von einem Prozess innerhalb der Benutzer-RDP-Sitzung gestartet werden, deren Client angesprochen werden soll.
Die EXE öffnet **keinen Netzwerkport**, benötigt keine zusätzliche Firewallfreigabe und kommuniziert ausschließlich über den bestehenden RDP-DVC.
### Exitcodes
```text
0 Trigger wurde an den DVC geschrieben
10 DVC konnte nicht geöffnet werden
11 Schreiben auf den DVC fehlgeschlagen
12 Trigger-Nachricht wurde nicht vollständig geschrieben
```
Ein Exitcode `10` tritt beispielsweise auf, wenn die EXE nicht innerhalb einer passenden RDP-Sitzung läuft, das Client-Plugin nicht geladen wurde oder der DVC nicht verfügbar ist.
## Client-Konfigurator
Die GUI enthält jetzt zwei getrennte Bereiche:
### Automatischer Start bei RDP-Verbindung
- Programm/Script
- Argumente
- Arbeitsverzeichnis
- Bei erfolgreicher RDP-Verbindung starten
- Bei RDP-Trennung beenden
- Unsichtbar starten
- Mehrfachstart verhindern
- lokaler Test
### Programmstart durch Terminalserver
- Trigger aktivieren/deaktivieren
- separates Programm/Script
- separate Argumente
- separates Arbeitsverzeichnis
- Unsichtbar starten
- Mehrfachstart verhindern
- lokaler Test
## Logging
Bei aktiviertem Logging:
```text
%LOCALAPPDATA%\Plandent\MstscScriptHook\plugin.log
```
Dort werden sowohl der normale RDP-Lifecycle als auch DVC-Verbindungen und Triggerstarts protokolliert.
## Voraussetzungen zum Bauen
- Windows 10/11 x64 als Entwicklungsrechner
- Visual Studio 2022 oder entsprechende Build Tools
- Workload **Desktopentwicklung mit C++**
- Windows 10/11 SDK
- .NET 8 SDK
## Debug-Build in Visual Studio
`Configurator.csproj` ist für **Debug** jetzt absichtlich framework-dependent konfiguriert. Dadurch werden beim normalen F5-Build keine `Microsoft.*.Runtime.win-x64`-Runtime-Pakete benötigt.
Als Startprojekt in Visual Studio:
```text
PlandentMstscScriptHook.Configurator
```
Die Plugin-DLL wird über die Projektabhängigkeit zuerst gebaut und anschließend als Resource in den Configurator eingebettet.
## Release bauen
PowerShell im Projektverzeichnis:
```powershell
.\build-release.ps1 -Clean
```
Ergebnis:
```text
dist\
├── PlandentMstscScriptHook.exe
└── PlandentRdpClientTrigger.exe
```
- `PlandentMstscScriptHook.exe` → auf dem **lokalen RDP-Client** verwenden.
- `PlandentRdpClientTrigger.exe` → auf den **Terminalserver** kopieren.
Die Client-EXE ist im Release x64, self-contained und Single-File. Die native Plugin-DLL ist darin eingebettet.
## Installation auf dem Client
1. `PlandentMstscScriptHook.exe` starten.
2. Gewünschten automatischen RDP-Start konfigurieren oder deaktivieren.
3. Optional unter **Programmstart durch Terminalserver** das lokale Trigger-Programm einschließlich Argumenten konfigurieren.
4. **Start durch Terminalserver-Trigger erlauben** aktivieren.
5. Optional beide Programme mit den Testbuttons lokal testen.
6. **Plugin installieren** anklicken.
7. Alle bereits laufenden `mstsc.exe`-Instanzen vollständig schließen.
8. MSTSC neu starten und die RDP-Verbindung herstellen.
Die Client-Installation erfolgt unter `HKCU` und `%LOCALAPPDATA%`; dafür sind normalerweise keine Administratorrechte nötig.
## Installation auf dem Terminalserver
Es ist keine Registrierung erforderlich. Lediglich:
Innerhalb der RDP-Sitzung wird anschließend lediglich ausgeführt:
```text
PlandentRdpClientTrigger.exe
```
an einen geeigneten Ort kopieren und von der Anwendung ausführen, die den lokalen Start anfordern soll.
Der Trigger startet das auf dem Client hinterlegte Programm. Programmpfad und Parameter werden nicht vom Terminalserver übertragen.
Beispiel aus einer Batchdatei innerhalb der RDP-Sitzung:
## Sidexis über SIOMIN aus einer RDP-Sitzung ansprechen
```bat
C:\Tools\PlandentRdpClientTrigger.exe
Für Programme, die innerhalb der Terminalserver-Sitzung laufen, aber ein **lokal installiertes Sidexis** ansprechen sollen, steht `PlandentSiominClientTrigger.exe` zur Verfügung.
Im betreffenden Terminalprogramm wird als Sidexis-Programm bzw. Sidexis-EXE nicht direkt Sidexis, sondern beispielsweise folgende Datei hinterlegt:
```text
C:\PDATA\exe\PlandentSiominClientTrigger.exe
```
Beispiel PowerShell mit Exitcode-Prüfung:
Das Terminalprogramm sollte seinen SLIDA-/SIOMIN-Eintrag zunächst in eine **lokale temporäre Datei auf dem Terminalserver** schreiben, beispielsweise:
```text
C:\PDATA\temp_siomin.sdx
```
Der SIOMIN-Trigger übernimmt diesen Eintrag anschließend in die finale `siomin.sdx`, die typischerweise im gemeinsamen PDATA-Verzeichnis liegt:
```text
\\SERVER\PDATA\siomin.sdx
```
Die Konfiguration erfolgt über eine INI-Datei mit demselben Basisnamen wie die EXE:
```text
PlandentSiominClientTrigger.exe
PlandentSiominClientTrigger.ini
```
Beispiel:
```ini
[SIOMIN]
SIOMIN_TEMP_PATH=C:\PDATA\temp_siomin.sdx
SIOMIN_PATH=\\SERVER\PDATA\siomin.sdx
DEBUG=0
```
Existiert die INI beim ersten Start nicht, wird sie mit lokalen Standardpfaden automatisch erzeugt:
```ini
[SIOMIN]
SIOMIN_TEMP_PATH=C:\PDATA\temp_siomin.sdx
SIOMIN_PATH=C:\PDATA\siomin.sdx
DEBUG=0
```
Für die Fehlersuche kann `DEBUG=1` gesetzt werden. Dann wird neben der EXE eine gleichnamige `.log`-Datei erzeugt.
## Installation auf dem Client
1. `PlandentMstscScriptHook.exe` starten.
2. Gewünschten automatischen Start konfigurieren oder deaktivieren.
3. Optional ein separates Programm für den Terminalserver-Trigger konfigurieren.
4. Bei Bedarf **Start durch Terminalserver-Trigger erlauben** aktivieren.
5. Einstellungen speichern bzw. **Plugin installieren** wählen.
6. Bereits laufende `mstsc.exe`-Instanzen vollständig schließen.
7. RDP-Verbindung neu aufbauen.
Die Installation erfolgt benutzerbezogen und benötigt im Normalfall keine Administratorrechte.
## Bereitstellung auf dem Terminalserver
Je nach Anwendungsfall werden nur die benötigten EXE-Dateien auf den Terminalserver kopiert:
```text
PlandentRdpClientTrigger.exe
PlandentSiominClientTrigger.exe
```
Es ist dort keine Installation oder Registrierung erforderlich.
## Unterstützte lokale Programme
Der Client kann folgende Typen starten:
- `.exe`
- `.bat`
- `.cmd`
- `.ps1`
Programme können sichtbar oder unsichtbar gestartet werden. Optional kann ein Mehrfachstart verhindert werden.
## Logging
Das Client-Plugin kann ein Log unter folgendem Pfad führen:
```text
%LOCALAPPDATA%\Plandent\MstscScriptHook\plugin.log
```
Für den SIOMIN-Trigger kann separat über
```ini
DEBUG=1
```
eine Logdatei neben `PlandentSiominClientTrigger.exe` aktiviert werden.
## Build
Voraussetzungen:
- Windows 10/11 x64
- Visual Studio 2022 oder Build Tools
- Workload **Desktopentwicklung mit C++**
- Windows 10/11 SDK
Release erstellen:
```powershell
& 'C:\Tools\PlandentRdpClientTrigger.exe'
if ($LASTEXITCODE -ne 0) {
Write-Warning "Client-Trigger fehlgeschlagen. ExitCode: $LASTEXITCODE"
}
.\build-release.ps1 -Clean
```
## Deinstallation auf dem Client
Ausgabe:
**Plugin entfernen** löscht den MSTSC-Registryeintrag und die installierte DLL. Ist die DLL noch in einer laufenden `mstsc.exe` geladen, wird die Registrierung entfernt und die DLL kann nach dem Schließen aller MSTSC-Instanzen erneut entfernt werden.
```text
dist\
├── PlandentMstscScriptHook.exe
├── PlandentRdpClientTrigger.exe
└── PlandentSiominClientTrigger.exe
```
Die eigentliche Programmkonfiguration unter `HKCU\Software\Plandent\MstscScriptHook` bleibt absichtlich erhalten.
Alle Komponenten sind native x64-Binaries. Eine .NET-Runtime wird nicht benötigt.
## Wichtige Grenzen
## Dokumentation
- Das Plugin ist für den klassischen Microsoft-RDC-Pluginmechanismus ausgelegt. Andere RDP-Clients müssen diesen Mechanismus unterstützen.
- Der Server-Trigger muss innerhalb einer aktiven RDP-Sitzung ausgeführt werden, wenn `WTS_CURRENT_SESSION` verwendet wird.
- Das lokale Programm läuft mit den Rechten des Benutzers, der `mstsc.exe` auf dem Client gestartet hat.
- Der Server kann über dieses Protokoll **keine** beliebigen Programme oder Parameter vorgeben.
- `StopOnDisconnect` gilt ausschließlich für das automatische RDP-Verbindungsprogramm, nicht für das per Server ausgelöste Programm.
- AppLocker/WDAC oder andere Application-Control-Richtlinien können das Laden einer nicht signierten DLL bzw. den Programmstart blockieren.
- `Home.md` – Anwender-/Technikerdokumentation
- `DEVELOPMENT.md` – technische Entwicklerdokumentation
## Hinweise
Das Projekt ist für den klassischen Microsoft-RDP-Client `mstsc.exe` vorgesehen. Der Trigger muss innerhalb der RDP-Sitzung ausgeführt werden, deren lokaler Client angesprochen werden soll.
Der lokale Programmstart erfolgt mit den Rechten des Benutzers, unter dem `mstsc.exe` auf dem Client ausgeführt wird.
Produktnamen wie Sidexis sind Eigentum der jeweiligen Rechteinhaber. Die RemoteVDDS-Scripte von Tobias Bauer sind nicht Bestandteil dieses Projekts.
## Lizenz
Copyright (c) 2026 Patrick Gniza.
All rights reserved.
Siehe [LICENSE](LICENSE).