Windows Variablen bzw. Infos zu RDP Sessions auslesen

  • Bei einer RDP Session wird immer auch der Computername des verbundenen Clients im Taskmanager angezeigt. Diesen String kann man per Kommandozeile mit "echo %clientname%" für den aktuellen Benutzer auslesen. Nun möchte ich aber bevorzugt darauf verzichten dies per run() zu realisieren und dann den Stdout mitzulesen. Deswegen habe ich mir die Funktion envget() angeschaut, doch leider liefert mir envget("CLIENTNAME") immer einen leeren String zurück. Ich vermute mal, dass envget nur Systemvariablen und keine lokalen user Variablen anzeigen kann. Gibt es noch andere Funktionen die entweder den Variableninhalt auslesen können oder über andere Wege an die gewünschte Information kommen können?

    autoit.de/wcf/attachment/12858/

  • Über die WMI gibts da einiges, hier mal beispielsweise rauskopiert aus AutoIt-Scriptomatic gefiltert nach "user" ergab u.a. einen Treffer Win32_LoggedOnUser
    Das Script wurde komplett von Scriptomatic erstellt

    Spoiler anzeigen
    [autoit]

    ; Generated by AutoIt Scriptomatic

    [/autoit] [autoit][/autoit] [autoit]

    $wbemFlagReturnImmediately = 0x10
    $wbemFlagForwardOnly = 0x20
    $colItems = ""
    $strComputer = "localhost"

    [/autoit] [autoit][/autoit] [autoit]

    $Output=""
    $Output = $Output & "Computer: " & $strComputer & @CRLF
    $Output = $Output & "==========================================" & @CRLF
    $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_LoggedOnUser", "WQL", _
    $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

    [/autoit] [autoit][/autoit] [autoit]

    If IsObj($colItems) then
    For $objItem In $colItems
    $Output = $Output & "Antecedent: " & $objItem.Antecedent & @CRLF
    $Output = $Output & "Dependent: " & $objItem.Dependent & @CRLF
    if Msgbox(1,"WMI Output",$Output) = 2 then ExitLoop
    $Output=""
    Next
    Else
    Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_LoggedOnUser" )
    Endif

    [/autoit]
  • Hi Andy

    Hab mir dieses Script-O-matic mal beschafft, aber so wirklich weiterhelfen tut mir das erstmal nicht. Leider hab ich keinen Schimmer von WMI und somit auch nicht die geringste Idee welche der zahlreichen Funktionen da in Frage kommen. Dein Beispiel liefert jedenfalls nicht das gewünschte, sondern nur Informationen über die genutzten Windows Accounts und den lokalen Computernamen, nicht den der verbundenen Clients. Ich vermute das ganze eher in der TeminalServerVerwaltung. Scriptomatic hat sich aber leider dazu entschieden abzustürzen nachdem ich mir da mal eine der Funktionen anschauen wollte. Vielleicht hab ich auch eine veraltete Version davon erwischt, es fehlten sogar includes für die GUI Konstanten der scriptomatic gui.

    Auch google liefert was WMI und den "clientname" der RDP Session angeht leider nichts brauchbares (zumindestens so wie ichs überflogen hatte), ausser den Tipp man solle doch einfach die Umgebungsvaribale welche ich oben bereits erwähnt habe nutzen.

    Vielleicht findest du ja noch etwas passendes. Ahja das ganze muss im übrigen auch ohne Admin Berechtigung funktionieren und sollte primär nur den clientname der eigenen Verbindung anzeigen, nicht die der anderen angemeldeten Benutzer.
    Am einfachsten wäre wie gesagt wenn envget() die Variabe finden würde, was offenbar nicht der Fall ist...

  • Keiner mehr Ideen? Hab das ganze nun via run und stdout mitlesen versucht, aber seltsamerweise unterscheiden sich die Ergebnisse bei manueller Ausführung in der Eingabeaufforderung von denen via Autoit. Die gewünschte Variable %clientname% wird über die Eingabeaufforderung korrekt ausgegeben:

    Von Hand via Eingabeaufforderung:

    Code
    C:\>echo %clientname%
    MEINPCNAME-VISTA

    Nun das erste Problem ist, dass ich per Autoit nicht den Varibalen Inhalt bekomme sondern in der msgbox des folgenden Testscripts nur "%clientname%" erscheint:

    [autoit]


    #include <Constants.au3>
    Local $foo = Run(@ComSpec & " /c " & 'echo %clientname%', @SystemDir, @SW_HIDE, $STDOUT_CHILD)
    Local $line = ""

    [/autoit][autoit][/autoit][autoit]

    While 1
    $line = $line & StdoutRead($foo)
    If @error Then ExitLoop
    Wend

    [/autoit][autoit][/autoit][autoit]

    MsgBox(0, "Debug", $line)

    [/autoit]

    Auch Versuche ohne @CompSpec oder anderen workingdirs oder ohne workingdir brachten immer das selbe Ergebnis. Selbst shellexecute hatte ich versucht, da wird dann "echo" nicht als Programm akzeptiert, was anzunehmen war.
    Nungut da man sich den Inhalt der Variablen auch über den DOS Befehl "set" anzeigen lassen kann habe ich die run() Zeile wie folgt geändert:

    [autoit]


    Local $foo = Run(@ComSpec & " /c " & 'set', @SystemDir, @SW_HIDE, $STDOUT_CHILD)

    [/autoit]

    Jetzt passiert das was mich sehr verwundert, ich bekomme nicht das selbe Ergebnis das ich über die Kommandozeile bekomme:

    Kommandozeile:

    Spoiler anzeigen

    Autoit:

    Spoiler anzeigen

    Hat da jemand eine Erklärung dafür oder kann mir eine Lösung zeigen mit der ich diese Variable ausgelesen bekomme? Bin langsam am verzweifeln...

  • Habs nun über ein externes Tool realsiert: http://home.fnal.gov/~jklemenc/tslistusers.html

    Der Vollständigheithalber noch der Autoit Code dazu:

    [autoit]


    #include <Constants.au3>
    #include <array.au3>
    #include <file.au3>
    #include <Date.au3>
    #NoTrayIcon

    [/autoit][autoit][/autoit][autoit]

    ; Das kompilierte Script wird extern mit dem Usernamen als Parameter aufgerufen der ausgegeben werden soll
    ; Alternativ kann man das Script natürlich auch direkt auf dem betroffenen Useraccount ausführen und statt der Variable $username das Makro @UserName verwenden
    ; In meinem Fall führe ich das Script aber auf einem Account mit mehr Berechtigungen aus um das Logfile an einem für den User gesperrten Ort zu speichern
    ; Das Script wird bei mir über die Aufgabenplannung beim Login und Connect des zu loggenden Users aufgerufen
    ; Link zu tslistusers.exe: http://home.fnal.gov/~jklemenc/tslistusers.html

    [/autoit][autoit][/autoit][autoit]

    if $CmdLine[0] <> 1 Then
    Exit
    Else
    $UserName = $CmdLine[1]
    EndIf

    [/autoit][autoit][/autoit][autoit]

    Local $logfile = @scriptdir & "\RDP_LOG.txt" ; Achtung die Datei muss bereits existieren, ich frage im folgenden nicht ab ob diese existiert
    Local $foo = Run(@ComSpec & " /c " & @ScriptDir & '\tslistusers.exe', "", @SW_HIDE, $STDOUT_CHILD)
    Local $line = ""
    Local $arrOldLog

    [/autoit][autoit][/autoit][autoit]

    While 1
    $line = $line & StdoutRead($foo)
    If @error Then ExitLoop
    Wend

    [/autoit][autoit][/autoit][autoit]

    $line = StringSplit($line,@CRLF)
    ;_ArrayDisplay($line) ; für debug Zwecke...
    $test = _ArrayFindAll($line,$UserName,0,0,0,1)
    if $test <> -1 Then
    for $i=0 to UBound($test)-1
    $test[$i]=$line[$test[$i]]
    Next
    ;_ArrayDisplay($test) ; für debug Zwecke...
    _FileReadToArray($logfile,$arrOldLog)
    _ArrayAdd($arrOldLog,_NowCalc() & ": " & $test[0]) ; ich schreibe nur den ersten Treffer da der Username eindeutig sein sollte, bei Bedarf können auch mehrere Treffer geschrieben werden, zum Beispiel alle User die mit A anfangen...
    _FileWriteFromArray($logfile,$arrOldLog,1)
    Else
    ;MsgBox(0,"Fehler", "Logging fehlerhaft") ; für debug Zwecke...
    EndIf

    [/autoit]

    Einmal editiert, zuletzt von misterspeed (17. März 2011 um 16:04)

  • Hallo misterspeed,

    ich konnte das gerade erst probieren, aber wenn ich folgendes Script

    [autoit]

    $ClientName = EnvGet("CLIENTNAME")
    MsgBox(0, "ClientName", "ClientName : " & $ClientName)

    [/autoit]


    innerhalb einer RDP-Sitzung kompiliert auf dem Server ausführe (Server 2003 32-Bit), liefert es mir den korrekten Wert.

  • Mit einem Server 2008 R2 kann ich nicht testen. Es gibt ihn ja aber nur als 64-Bit Version. Hast Du es sowohl mit 32- als auch mit 64-Bit Compilaten versucht?

  • Ja nach deinem Hinweis, dass es unter Server 2003 32bit in kompilierter Form funktioniert habe ich sowohl 32bit als auch 64bit Versionen erstellt (UPX wurde testweise ebenfalls aktiviert/deaktiviert), bei allen Varianten bleibt der String der Variablen unter 2008 R2 leer. Getestet wurde über den Admin Account. Auch das explizite Ausführen als Administrator wurde getestet.

    Vielleicht ein Bug/Feature der 2008 R2 ?(

  • Hallo,

    schau Dir das mal an:

    Spoiler anzeigen


    Ich kann das erst wieder in der kommenden Woche probieren, deshalb habe ich auch nicht versucht, es in einen DllCall() umzusetzen. Vielleicht bringt es ja aber etwas.

  • Danke das schaut gut aus ;)
    Leider hab ich bislang nie mit DLL's gearbeitet (mal von ein wenig copy & paste abgesehn). Meine Versuche waren glaube ich weniger erfolgreich, ich vermute mir fehlt hier noch einiges an Wissen...

    [autoit]


    #Region ;**** Directives created by AutoIt3Wrapper_GUI ****
    #AutoIt3Wrapper_UseX64=n
    #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****

    [/autoit][autoit][/autoit][autoit]

    #include <array.au3>

    [/autoit][autoit][/autoit][autoit]

    Local $ergebnis
    $ergebnis = DllCall("Wtsapi32.dll","BOOL","WTSQuerySessionInformation","HANDLE","WTS_CURRENT_SERVER_HANDLE","DWORD","WTS_CURRENT_SESSION","int",10,"str*","*ppBuffer","DWORD","*pBytesReturned")
    MsgBox(0,"errorcode",@error)
    _ArrayDisplay($ergebnis)

    [/autoit][autoit][/autoit][autoit]

    ;~ [0]|0 <--- hier sollte ein wert ungleich 0 stehen wenn alles klappt
    ;~ [1]|0x00000000 <--- hmm current server handle... kA ob dieser Wert korrekt ist
    ;~ [2]|0 <--- current session... kA ob das so stimmt
    ;~ [3]|10 <--- dürfte korrekt sein
    ;~ [4]|*ppBuffer <--- hier liegt vermutlich mein Fehler...
    ;~ [5]|0 <--- 0 Byte ist eindeutig falsch

    [/autoit]

    Hatte auch ein wenig rumgetestet, entweder stürzt das Programm ganz ab (lag denke ich anfangs an 64bit) oder, error wird auf 1 gesetzt oder das ergebnis schaut aus wie in diesem Fall.

  • Hab dazu was im englischen Forum gefunden, funktioniert nun :)
    Dank dir nochmals.

    [autoit]


    Local $ergebnis
    Local $clientname

    [/autoit][autoit][/autoit][autoit]

    $ergebnis = DllCall("Wtsapi32.dll","BOOL","WTSQuerySessionInformationW","int",0,"int",-1,"int",10,"ptr*",0,"DWORD*",0)
    If @error Or $ergebnis[0] = 0 Then
    $clientname = "unknown"
    Else
    $clientname = BinaryToString( DllStructGetData(DllStructCreate("byte[" & $ergebnis[5] & "]" , $ergebnis[4]),1) ,2)
    DllCall("Wtsapi32.dll", "int", "WTSFreeMemory", "ptr", $ergebnis[4])
    EndIf

    [/autoit][autoit][/autoit][autoit]

    MsgBox(0,"Fertig",$clientname)

    [/autoit]