Windows: Alle Terminalserver-Benutzer per Skript abmelden

Bei einem Kunden bestand die Anforderung alle Benutzer zu einem bestimmten Zeitpunkt vom Terminalserver abzumelden. Die gängigen Mittel wie z.B. nach einer gewissen Leerlaufzeit abmelden waren für das Szenario unpassend, da es zwar eine Kernarbeitszeit gibt, aber auch flexible Arbeitszeiten als auch Außendienstmitarbeiter, die sich mit dem System verbinden, wann Sie können. Darüber hinaus meldet sich nicht jeder Benutzer ab, teilweise wird bewusst oder bei schlechter Verbindung die Sitzung nur getrennt (z.B. wenn man auf dem Weg zum nächsten Termin ist und/oder später an gleicher Stelle weiterarbeiten möchte oder das mobile Internet nicht gerade der „Hit“ ist).

Wieso eigentlich alle Benutzer abmelden?

Diese Frage ist schnell beanwortet: Die beim Kunden eingesetzte Branchenlösung verlangt zum Zeitpunkt der Datensicherung, das niemand mit der Datenbank verbunden ist. Schattenkopie (VSS) o.ä. kennt diese Anwendung nicht. Eine Option wäre nun alle entsprechenden Prozesse zu beenden oder eben alle Benutzer abzumelden. Letzteres erschien als die bessere Lösung, da man Sie mit weiteren Befehlen kombinieren kann (siehe weiter unten) und man so sicher sein kann, das nicht doch etwas „hängen“ bleibt.

Seitens der Bordmittel von Microsoft gibt es den Befehl „logoff“ den man zum Abmelden verwenden kann, dieser erwartet allerdings die Angabe eines Sitzungsnamens oder einer Sitzungs-ID. Beides kann über den Befehl „query session“ („query user“ würde wahrscheinlich genauso funktionieren), ermittelt werden. Leider gibt es bei „logoff“ keine Wildcard, damit alle Benutzer auf einmal abgemeldet werden können.

Die Lösung

Mit AutoIt wurde ein Skript bzw. Tool entwickelt, das den Befehl „query session“ ausführt, aus der Ausgabe die Sitzungs-ID ermittelt und alle aktiven wie auch getrennten Sitzungen abmeldet.

Download (WTS-LogOff-AllUsers_v2.zip)

Download (wts-logoff-allusers_v3.zip) – Siehe Update vom 19.02.2017.

(64-bit Version [32-bit kann kompiliert werden], Quellcode)

Hinweise: Das Tool meldet die Benutzer ohne jede Vorwarnung ab! Führt man das Tool z.B. als Administrator aus, so wird dieser nicht abgemeldet. Wird das Tool mittels Aufgabe ausgeführt, so wird, sofern angemeldet, selbst der Benutzer abgemeldet, dessen Anmeldedaten für die Aufgabe verwendet werden!

Entwickelt und getestet wurde unter Windows 7 Professional 64-bit das mit einer entsprechenden Lösung zum Terminalserver gemacht wurde, beim Kunden ist ein Windows Server 2012 Standard (64-bit) mit RDS-Rolle im Einsatz. Andere Lösungen sollten ebenso funktionieren, sind allerdings nicht getestet.

Für den Fall, das man zunächst testen möchte, welche Sitzungen abgemeldet werden, kann im Quellcode die Zeile 68 auskommentieren und die Zeile 70 einkommentieren, dadurch wird das Abmelden deaktiviert und stattdessen erscheint eine MessageBox mit Sitzungs-ID, die abgemeldet werden würde.

Kombination mit weiteren Befehlen

Das hier vorgestellte Skript bzw. das daraus resultierende Tool kann z.B. mit den Befehlen

  • change logon /disable (neue Anmeldungen verweigern) und
  • change logon /enable (Anmeldungen wieder zulassen)

kombiniert werden. Man könnte folgenden Ablauf realisieren:

  1. Neue Anmeldungen verweigern.
  2. Alle aktiven oder getrennten Sitzungen beenden.
  3. Datensicherung/Wartung/… durchführen.
  4. Anmeldungen wieder zulassen.

Update 19.02.2017

In der neuen Version 3 des Tools besteht die Möglichkeit, Benutzer vom automatischen Abmelden auszunehmen. Dies kann notwendig sein z.B. für administrative Tätigkeiten, bei Programmen die zwingend mit einem angemeldetem Benutzer laufen müssen, etc.

Diese Version wurde hauptsächlich unter Windows Server 2012 R2 entwickelt und getestet.

Update 03.04.2017

Kleiner Tipp am Rande:

Wer eine Benachrichtigung versenden möchte, bevor die Abmeldung stattfindet, kann dies mit Bordmitteln tun:

@echo off

rem Benachrichtigung anzeigen

 msg.exe * Um 21:55 Uhr werden alle aktiven Sitzungen abgemeldet.
 
rem Pause

 timeout /t 300 /nobreak
 
rem Abmeldungen durchfuehren

 wts-logoff-allusers_v3_x64.exe

16 Kommentare

  • Der AutoIT-Quell-Code ist nicht korrekt, oder mit einer alten Version geschrieben.

    Funktion _FileReadToArray mit falschen Parametern, Includes vergessen, etc

  • „FileReadToArray“ benötigt kein Include. Siehe dazu:

    FileReadToArray

    „_FileReadToArray“ ist eine andere Funktion, die in diesem Fall/Tool/Skript nicht verwendet wird, aber ein Include benötigt:

    _FileReadToArray

  • Hallo allerseits,

    vorab einmal ein großes Lob und Anerkennung an die/den Betreiber dieses Blogs. Ich bin vor Jahren mal auf diesen Blog gestoßen und seither lese ich ausnahmslos jeden Beitrag.
    Eine Frage zum Abmelde-Script:
    out-of-the-box läuft es nicht und mir erschlichst sich leider nicht, ob und an welchen Stellen das Script an die jeweilige Umgebung angepasst werden muss (getestet auf Win7 x64 standalone und einem RDSH 2012 R2 in einer Domänenumgebung, sowohl V2 als auch V3). Nachdem man das Script ausgeführt hat, sieht man für eine Sekunden die Session.txt, anschließend beendet sich das Script/Programm auch wieder, ohne das Abmeldung(en) erfolgt ist/sind.
    Ich würde mich freuen, wenn der Artikelersteller (oder auch gerne Blog-Gäste) mich diesbezüglich beleuchten könnten. Danke vorab.

  • Hallo,

    das Skript (zumindest v3) funktioniert bei uns und Kunden nach wie vor ohne Probleme. Gerade vergangene Woche auf einem neuem WTS 2016 mit eingebunden.
    Zunächst wäre die Frage, mit welchen Rechten das Skript ausgeführt wird? Wir lassen es mittels Aufgabe mit höchsten Rechten starten. Als weiteres kann es vorkommen, das ein Virenscanner die Ausführung verhindert (bekannte AutoIt/UPX-Geschichte, ist im Blog ebenfalls beschrieben).

    Angepasst werden kann/soll/muss min. nur die „blacklist.txt“, d.h. welche Benutzer nicht automatisch abgemeldet werden sollen (Angabe des Benutzernamens).
    Die „sessions.txt“ wird nur kurz erstellt, dann in ein Array eingelesen und im Anschluss gelöscht (kann man im Quelltext nachlesen, ist kommentiert).
    Dann werden die Sessions mit der Blacklist abgeglichen und die nicht ausgeschlossenen Benutzer abgemeldet.

  • Vielen Dank für diese elegante Lösung. Könnten Sie bitte noch 32 bit Version kompilieren?
    Danke sehr.

  • Das kann man ganz einfach und schnell selbst tun:

    – AutoIt-Zip-Archiv herunterladen (AutoIt Downloads) und entpacken.
    – In den Ordner „installAut2Exe“ wechseln.
    – Die Datei „Aut2exe.exe“ ausführen.
    – Die *.au3 aus dem Archiv des Beitrags bei „Source“ laden.
    – Alles andere kann so belassen werden, wie es per Default ist.
    – Auf „Convert“ klicken.

    Hinweis: Ggf. muss der Virenschutz wegen False Positive vorher deaktiviert werden.

  • Hallo, ich hätte kurz eine Frage. Was muss ich im Skript abändern, damit ich nur getrennte User abmelden lasse.
    Und kann ich vielleicht noch eine Zeit hinterlegen, das heißt das ein getrennter User nach 5 Minuten abgemeldet wird. Danke vorab 🙂

  • Da aber diese Richtlinien sowie der ServerManager aus unerklärlichen Gründen bei mir nicht funktionieren, möchte ich zu einen Skript greifen und diesen in einem Dienst packen.
    Ich möchte einfach alle getrennten User bis auf Admins abmelden lassen. Dies erfüllt ja der Skript bis auf das, das er auch aktive User abmeldet, das darf halt nicht sein.

  • Solche Schwierigkeiten kenne ich leider auch.
    Man müsste das Skript dahingehend abändern, das nur getrennte Sessions berücksichtigt werden.
    Evtl. fällt mir dazu auch noch ein anderer Weg ein.
    Muss ich mir mal in Ruhe anschauen, kann aber etwas dauern.

  • Hey nochmal. Ich habe mir eine Möglichkeit überlegt, das ich noch eine Status.txt (in welcher der Status „Aktiv“ steht) zur Blacklist.txt erstelle. Das heißt das Skript soll zum einen die Blackliste auslesen und dabei die ID’s ausfiltern, zum anderen soll es auch die Statusliste auslesen und mit den ID’s filtern. Zum Schluss sollen die übrigen ID’s zusammengetragen werden und ausgeloggt werden. Das habe ich soweit schon hinbekommen. Allerdings bekomme ich es nicht hin, das die While Schleife, welche die Status „Spalte“ aus der Session.txt nimmt, auslesen kann. Diese Geschichte mit der StringTrimRight/Left. Ich kann dir den Skript auch gern mal zusenden.

  • Ein Schnellschuss um getrennte Sitzungen via Batch abzumelden sieht z.B. so aus:

    @echo off

    setlocal enabledelayedexpansion

    rem Getrennte Sitzungen ermitteln:

    query session | find "Getr." > sessions.txt

    rem IDs ermitteln und getrennte Sitzungen abmelden

    for /f "delims=" %%v in (sessions.txt) do (

    rem Variable uebernehmen
    set session=%%v

    rem Session-ID ermitteln (beruecksichtigt 5-stellige IDs)
    set id=!session%:~41,5!

    if !id! gtr 0 ( rem Sitzung services 0 ausfiltern
    if !id! lss 65536 ( rem Sitzung rdp-tcp 65536 ausfiltern
    logoff !id! rem Info: logoff akzeptiert die ID samt vorangestellten Leerzeichen
    )
    )

    )

    rem Temporaere Datei entfernen

    del sessions.txt /q

    Zum Testen sollte man ein „echo“ vor „logoff…“ setzen.
    Da ist noch keine Blacklist o.ä. berücksichtigt.

  • Hallo Zusammen,

    könnte man das Toll so abwandeln, das alle Sessions getrennt werden die 24 Stunden nach der Anmeldezeit überschreiten?

  • Skripten/Programmieren lässt sich fast alles.
    Bei der angedachten Variante wäre vmtl. zu beachten, ob die User noch aktiv sind oder nicht.
    Zudem müssten, im Gegensatz zu jetzigen Form, irgendwo/irgendwie festgehalten werden, wann sich wer angemeldet hat.
    Da kommt dann wegen „möglicher Überwachung“ noch die rechtliche Seite hinzu.

  • Eigentlich funktioniert das Skript sehr gut, allerdings werden bei unserem 2012er Terminal alle User bei Ausführung einmal gekickt. Zwar bleiben diejenigen in der Blacklist angemeldet, aber es kommt eben zur Zwangstrennung. Kann man da noch etwas machen?

  • Hallo Torsten,

    leider kann ich dir nicht ganz folgen.
    Die Benutzer in der Blacklist werden getrennt und alle anderen abgemeldet oder wie ist das gemeint?

Schreibe einen Kommentar

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