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 beantwortet: 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 (gilt für v2, bei v3 sind es die Zeilen 94 und 98), 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

31 Kommentare

  1. SaftHimself

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

    Funktion _FileReadToArray mit falschen Parametern, Includes vergessen, etc

  2. andy

    “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

  3. Aladin

    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.

  4. andy

    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.

  5. Leshyk Storck

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

  6. andy

    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.

  7. Florian

    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 🙂

  8. andy

    Das sollte im Idealfall mit Bordmitteln über die GPO regelbar sein:

    Terminalserver 2012 R2: Automatische Abmeldung bei Inaktivität
    auto log off disconnected users

  9. Florian

    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.

  10. andy

    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.

  11. Florian

    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.

  12. andy

    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.

  13. Thomas

    Hallo Zusammen,

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

  14. andy

    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.

  15. Torsten

    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?

  16. andy

    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?

  17. Hubert

    Hallo,

    das Programm ist ganz nett.
    Allerdings habe ich oft Angst solche Tools zu verwenden, da ich nicht weiß was sich im Quelltext verbirgt.
    Hier habe auch auch noch eine Möglichkeit gefunden, wie man das mit CMD lösen kann:
    https://www.itnator.net/windows-benutzer-remote-abmelden-mit-cmd/

    Gruß Hubert

  18. Andy

    Der Quelltest liegt dem Skript bei und kann einfach gelesen werden, er ist zudem dokumentiert, ferner kann man ihn selbst mit AutoIt kompilieren. Letztlich wird ebenfalls zum eigentlichen Abmelden auf die Windows-Bordmittel zurückgegriffen.

  19. Ronald Kissling

    Hallo,

    tolles Tool.
    Genau das was ich gesucht habe.

    Nur hätte ich gerne, wie beschrieben erst den Test mit dem Anzeigen der MSG-Box ausgeführt.
    Dazu habe ich in der Version 3 die Zeile 94 aktiviert,
    und die Zeile 98 deaktiviert.

    — Code sieht jetzt so aus
    ; WTS-Benutzer mit Ausnahme der Blacklist abmelden
    If $Skip = 0 Then
    ; Debug-Code
    MsgBox (0, “”, “Abmelden: ” & StringLower ($Username) & ” | ” & $ID)
    ;$File = FileOpen (“Abmelden.txt”, 1)
    ;FileWriteLine ($File, “Abmelden von Benutzername: ” & StringLower ($Username) & ” | ID: ” & $ID)
    ;FileClose ($File)
    ;Run (@ComSpec & ” /c ” & ‘logoff ‘ & $ID, “”, @SW_HIDE)
    EndIf

    —————————————–

    Danach habe ich die Exe ausgeführt.
    Und: Er hat alle Benutzer abgemeldet.

    Klar, ich hätte die au3 Datei erst neu compilieren müssen.

    Frage 1: wie mache ich aus der au3-Datei ene Exe?
    Frage 2: habe ich die riechtigen Zeilen aktiviert/deaktiviert?

    Vielen Dank

  20. Andy

    Hallo Ronald,

    vielen Dank für dein Kommentar.

    Antwort 1: Bei jeder AutoIt-Installation bzw. im ZIP ist “Aut2Exe” enthalten. Dieses starten, die *.au3-Datei auswählen und dann kompilieren. Fertig ist die Exe.
    Antwort 2: Die Zeilen sind richtig, wenn’s nur darum geht angezeigt zu bekommen, wer abgemeldet wird und das keine Abmeldung wirklich durchgeführt wird.

    Die *.au3 ist nur der Quellcode. Die Exe wurde aus diesem Quellcode generiert. Ergo bringt das reine ändern der *.au3-Datei nichts ohne das Skript von AutoIt ausführen zu lassen oder wieder als Exe-Datei zu kompilieren.

    Man kann das AutoIt-Skript auch ohne vorige Kompilierung ausführen. Einfach “AutoIt3_x64.exe” starten und die *.au3-Datei auswählen oder aus einer Eingabeaufforderung heraus “AutoIt3_x64.exe dateiname.au3” starten.

  21. Andre82ms

    Hallo,

    bei mir scheint die Blacklist nicht zu funktionieren. Gibt es hier besonderheiten? ich habe die 3 Dateien in einem Ordner ableget und die Blacklist folgendermaßen gepflegt:

    administrator
    domäneadministrator

    trotzdem wird der Domain-Admin aus der RDP gekickt.

  22. Andy

    Hallo André,

    besonders zu beachten gibt es nichts. Alle Dateien in einen Ordner, die Benutzername in der Blacklist eintragen und das Ganze zum gewünschten Zeitpunkt ausführen.
    Aktuell haben wir das Tool unter Windows Server 2012 R2 und Windows Server 2016 am Laufen.

    Welche Windows-Version habt ihr denn im Einsatz?
    Mal in einer Eingabeaufforderung “query session” ausführen und nachschauen, wie die angemeldeten Benutzer bzw. in diesem Fall der Domain-Admin dargestellt wird und genau so mal in der Blacklist eintragen.

    Gross-/Kleinschreibung spielt für gewöhnlich keine Rolle, “domain” wird eigentlich auch nicht benötigt.

    Im Skript ist Debug-Code (ab Zeile 93) enthalten, d.h. man kann eine Debug-Version kompilieren, diesen “einkommentieren” und das eigentliche Abmelden (Zeile 98) auskommentieren.
    So kann man sowohl einen Dialog als auch eine Datei (“Abmelden.txt”) erstellen lassen, in der ausgegeben wird, welche Benutzer abgemeldet werden.

    Ansonsten gerne bei mir direkt in der Firma melden und wir klären das bzw. dann kann ich mir das mal direkt ansehen.

  23. André Kalthoff

    Hallo Andy,

    wir nutzen Windows Server 2016 Std..
    Query Session hab ich auch schon kontrolliert – da taucht die Sitzung auch nur als “administrator” auf. Ich habe die 3 Dateien (blacklist.txt, wts-logoff-allusers_v3.au3 und wts-logoff-allusers_v3_x64.exe) auf der lokalen C-Partition in einem Unterordner abgelegt und ausgeführt. in der Blacklist.txt ist wie oben erwähnt, der Name administrator mit enthalten. Ich starte die Exe zum Test direkt aus der administrator-RDP-Session und werde direkt abgemeldet.

    Was das Debuggen/ Scripten angeht, muss ich gestehen, dass ich da noch nicht so tief in der Materie bin. Ich vermute, das die Sessions.txt leer bleibt. Ich war so naiv und dachte, das die .au3-Datei von der .exe genutzt wird und ich dort das Löschen der Sessions.txt aukommentieren könnte. Dem scheint nicht so.

    Kannst Du mir ggfls. einen Tipp geben, wie ich aus der au3-Datei eeine Exe erstellen kann oder woran es ggfls. noch scheitern könnte?

    Viele Grüße
    André

  24. Andy

    Hallo André,

    die *.au3-Datei ist der AutoIt-Quellcode, aus dem man die *.exe-Datei erstellen kann.
    Das Kompilieren ist einfach, schau’ mal nach meinem Kommentar vom 28. April 2018 22:51.
    Wichtig: Den Haken setzen bei “x64”!

  25. André Kalthoff

    Hallo Andy,

    sorry ich hatte aufgrund von etwas Zeitmangel noch nicht so weit recherchiert. Hab es in diesem Moment aber auch gesehen und umgesetzt. ich habe das Script nun so kompiliert, dass die sessions.txt nicht gelöscht wird. Der Inhalt sieht gut aus – der Benutzer wird also aufgeführt. Daher frage ich mich, wieso die Blacklist dann nicht greift

    Hier mal der unformatierte Inhalt der Sessions.txt:
    SITZUNGSNAME BENUTZERNAME ID STATUS TYP GERŽT
    services 0 Getr.
    >rdp-tcp#9 administrator 1 Aktiv
    console 7 Verb.
    31c5ce94259d4… 65536 Abh”r.
    rdp-tcp 65537 Abh”r.

  26. Andy

    > Daher frage ich mich, wieso die Blacklist dann nicht greift

    Das wüsste ich jetzt auch gerne.

    Da es sowohl bei uns im Hause und bei Kunden klappt, ist die Frage, was da bei euch ggf. anders ist.
    Mal eine Debug-Variante wie zuvor beschrieben erstellen, dann wird keiner abgemeldet und man kann in Ruhe testen.

  27. André Kalthoff

    Erst mal vielen Dank für die schnelle Antwort und Unterstützung!

    Das Script meldet: Line42 – Error: Unknown function Name.

    Zeile 42 lautet: $Blacklist = FileReadToArray ($File)

    Der Befehl “FileReadToArray” wurde aber zuvor auch schon im Script verwendet, wo scheinbar kein Fehler gemeldet wird. Daher bin ich immer noch ratlos…

  28. Andy

    Habe es gerade mal mit dem Quellcode getestet, läuft bei mir. Kann ich leider nicht nachvollziehen.
    Selbst wenn keine Blacklist vorhanden ist läuft es bei mir durch.

  29. ANALytiker

    Zitat vom Artikel:
    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.

    Die Zeilen 68 und 70 beziehen sich auf welche Version des Scripts? …ich glaube bei der V3 haut das nicht mehr hin 😉

  30. Andy

    Das bezieht sich auf v2, v3 kam ja erst später, das ergibt sich aus dem zeitlichen Verlauf.
    In v2 sind das diese beiden Zeilen:

    If $SkipSession = 0 Then Run (@ComSpec & " /c " & 'logoff ' & $SessionID, "", @SW_HIDE)

    ; If $SkipSession = 0 Then MsgBox (0, "", "LogOff: " & $SessionID) ; Debug-Code

    v3 ist wegen der Blacklist etwas anders aufgebaut, da sind es die Zeilen 94 und 98:

    ;MsgBox (0, "", "Abmelden: " & StringLower ($Username) & " | " & $ID)
    Run (@ComSpec & " /c " & 'logoff ' & $ID, "", @SW_HIDE)

  31. Andy Felber

    Ich bin per Zufall auf diesen Blog und dieses Script gestossen, auf der Suche nach einer Lösung nur gewisse User regelmässig automatisch abzumelden. Das Script funktioniert auf unseren WTS 2016 einwandfrei. Vielen Dank an dieser Stelle an den Autor.

    Evtl. noch ein kleiner Hinweis an nachfolgende Benutzende des Scripts: Neben der Ausführung der Aufgabe mit höchsten Privilegien, damit die User überhaupt abgemeldet werden, war es bei uns wichtig, dass bei der Aktion “Programm starten” der Ordner mit dem Skript / der Blacklist bei “Starten in” angegeben wurde, damit das Script ganz bestimmt dort ausgeführt und die blacklist.txt gelesen sowie benutzt wurde.

Schreibe einen Kommentar

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

© 2024 Andy's Blog

Theme von Anders NorénHoch ↑