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?
Windows Variablen bzw. Infos zu RDP Sessions auslesen
-
- [ gelöst ]
-
misterspeed -
14. März 2011 um 17:15 -
Geschlossen -
Erledigt
-
-
Ü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 erstelltSpoiler anzeigen
[autoit]; Generated by AutoIt Scriptomatic
[/autoit] [autoit][/autoit] [autoit]$wbemFlagReturnImmediately = 0x10
[/autoit] [autoit][/autoit] [autoit]
$wbemFlagForwardOnly = 0x20
$colItems = ""
$strComputer = "localhost"$Output=""
[/autoit] [autoit][/autoit] [autoit]
$Output = $Output & "Computer: " & $strComputer & @CRLF
$Output = $Output & "==========================================" & @CRLF
$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
$colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_LoggedOnUser", "WQL", _
$wbemFlagReturnImmediately + $wbemFlagForwardOnly)If IsObj($colItems) then
[/autoit]
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 -
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:
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]
[/autoit][autoit][/autoit][autoit]
#include <Constants.au3>
Local $foo = Run(@ComSpec & " /c " & 'echo %clientname%', @SystemDir, @SW_HIDE, $STDOUT_CHILD)
Local $line = ""While 1
[/autoit][autoit][/autoit][autoit]
$line = $line & StdoutRead($foo)
If @error Then ExitLoop
WendMsgBox(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.
[autoit]
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)Jetzt passiert das was mich sehr verwundert, ich bekomme nicht das selbe Ergebnis das ich über die Kommandozeile bekomme:
Kommandozeile:
Spoiler anzeigen
Code
Alles anzeigenC:\set ALLUSERSPROFILE=C:\ProgramData APPDATA=C:\Users\Administrator\AppData\Roaming CLIENTNAME=MEINPCNAME-VISTA <--------------------------------------------- Das will ich haben :-) CommonProgramFiles=C:\Program Files\Common Files CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files CommonProgramW6432=C:\Program Files\Common Files COMPUTERNAME=xxxxxxxxxxxxxxxxxxxxxx ComSpec=C:\Windows\system32\cmd.exe FP_NO_HOST_CHECK=NO HOMEDRIVE=C: HOMEPATH=\Users\Administrator LOCALAPPDATA=C:\Users\Administrator\AppData\Local LOGONSERVER=\\xxxxxxxxxxxxxxxxxxxx NUMBER_OF_PROCESSORS=8 OS=Windows_NT Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\AMCC\CLI;C:\Program Files (x86)\Smart Projects\IsoBuster PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC PROCESSOR_ARCHITECTURE=AMD64 PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 26 Stepping 5, GenuineIntel PROCESSOR_LEVEL=6 PROCESSOR_REVISION=1a05 ProgramData=C:\ProgramData ProgramFiles=C:\Program Files ProgramFiles(x86)=C:\Program Files (x86) ProgramW6432=C:\Program Files PROMPT=$P$G PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ PUBLIC=C:\Users\Public SESSIONNAME=RDP-Tcp#1 <------------------------------ Das hier fehlt genau wie der Clientname im Autoit Output SystemDrive=C: SystemRoot=C:\Windows TEMP=C:\Users\ADMINI~1\AppData\Local\Temp\2 TMP=C:\Users\ADMINI~1\AppData\Local\Temp\2 USERDOMAIN=xxxxxxxxxxxxxxxxxxxxxxx USERNAME=xxxxxxxxx USERPROFILE=C:\Users\Administrator windir=C:\Windows
Autoit:
Spoiler anzeigen
Code
Alles anzeigenALLUSERSPROFILE=C:\ProgramData APPDATA=C:\Users\Administrator\AppData\Roaming CommonProgramFiles=C:\Program Files (x86)\Common Files CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files CommonProgramW6432=C:\Program Files\Common Files COMPUTERNAME=xxxxxxxxxxxxxxxxxxx ComSpec=C:\Windows\system32\cmd.exe FP_NO_HOST_CHECK=NO HOMEDRIVE=C: HOMEPATH=\Users\Administrator LOCALAPPDATA=C:\Users\Administrator\AppData\Local LOGONSERVER=\\xxxxxxxxxxxxxxxxxxxxxxx NUMBER_OF_PROCESSORS=8 OS=Windows_NT Path=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\AMCC\CLI;C:\Program Files (x86)\Smart Projects\IsoBuster PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC PROCESSOR_ARCHITECTURE=x86 PROCESSOR_ARCHITEW6432=AMD64 PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 26 Stepping 5, GenuineIntel PROCESSOR_LEVEL=6 PROCESSOR_REVISION=1a05 ProgramData=C:\ProgramData ProgramFiles=C:\Program Files (x86) ProgramFiles(x86)=C:\Program Files (x86) ProgramW6432=C:\Program Files PROMPT=$P$G PSModulePath=C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ PUBLIC=C:\Users\Public SystemDrive=C: SystemRoot=C:\Windows TEMP=C:\Users\ADMINI~1\AppData\Local\Temp TMP=C:\Users\ADMINI~1\AppData\Local\Temp USERDOMAIN=xxxxxxxxxxxxxx USERNAME=xxxxxxxxxx USERPROFILE=C:\Users\Administrator windir=C:\Windows
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]
[/autoit][autoit][/autoit][autoit]
#include <Constants.au3>
#include <array.au3>
#include <file.au3>
#include <Date.au3>
#NoTrayIcon; Das kompilierte Script wird extern mit dem Usernamen als Parameter aufgerufen der ausgegeben werden soll
[/autoit][autoit][/autoit][autoit]
; 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.htmlif $CmdLine[0] <> 1 Then
[/autoit][autoit][/autoit][autoit]
Exit
Else
$UserName = $CmdLine[1]
EndIfLocal $logfile = @scriptdir & "\RDP_LOG.txt" ; Achtung die Datei muss bereits existieren, ich frage im folgenden nicht ab ob diese existiert
[/autoit][autoit][/autoit][autoit]
Local $foo = Run(@ComSpec & " /c " & @ScriptDir & '\tslistusers.exe', "", @SW_HIDE, $STDOUT_CHILD)
Local $line = ""
Local $arrOldLogWhile 1
[/autoit][autoit][/autoit][autoit]
$line = $line & StdoutRead($foo)
If @error Then ExitLoop
Wend$line = StringSplit($line,@CRLF)
[/autoit]
;_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 -
Hallo misterspeed,
ich konnte das gerade erst probieren, aber wenn ich folgendes Script
[autoit]$ClientName = EnvGet("CLIENTNAME")
[/autoit]
MsgBox(0, "ClientName", "ClientName : " & $ClientName)
innerhalb einer RDP-Sitzung kompiliert auf dem Server ausführe (Server 2003 32-Bit), liefert es mir den korrekten Wert. -
Sehr seltsam, ich nutze Win2008 R2 und da funktioniert es nicht über envget(). In meiner 2003er VM klappt es.
-
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
Code
Alles anzeigenBOOL WTSQuerySessionInformation( __in HANDLE hServer, __in DWORD SessionId, __in WTS_INFO_CLASS WTSInfoClass, __out LPTSTR *ppBuffer, __out DWORD *pBytesReturned ); #define WTS_CURRENT_SERVER_HANDLE ((HANDLE)NULL) #define WTS_CURRENT_SESSION ((DWORD)-1) typedef enum _WTS_INFO_CLASS { WTSInitialProgram = 0, WTSApplicationName = 1, WTSWorkingDirectory = 2, WTSOEMId = 3, WTSSessionId = 4, WTSUserName = 5, WTSWinStationName = 6, WTSDomainName = 7, WTSConnectState = 8, WTSClientBuildNumber = 9, WTSClientName = 10, WTSClientDirectory = 11, WTSClientProductId = 12, WTSClientHardwareId = 13, WTSClientAddress = 14, WTSClientDisplay = 15, WTSClientProtocolType = 16, WTSIdleTime = 17, WTSLogonTime = 18, WTSIncomingBytes = 19, WTSOutgoingBytes = 20, WTSIncomingFrames = 21, WTSOutgoingFrames = 22, WTSClientInfo = 23, WTSSessionInfo = 24, WTSSessionInfoEx = 25, WTSConfigInfo = 26, WTSValidationInfo = 27, WTSSessionAddressV4 = 28, WTSIsRemoteSession = 29 } WTS_INFO_CLASS;
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
[autoit]
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][autoit][/autoit][autoit]
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseX64=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****#include <array.au3>
[/autoit][autoit][/autoit][autoit]Local $ergebnis
[/autoit][autoit][/autoit][autoit]
$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);~ [0]|0 <--- hier sollte ein wert ungleich 0 stehen wenn alles klappt
[/autoit]
;~ [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 falschHatte 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
[autoit]
Dank dir nochmals.
[/autoit][autoit][/autoit][autoit]
Local $ergebnis
Local $clientname$ergebnis = DllCall("Wtsapi32.dll","BOOL","WTSQuerySessionInformationW","int",0,"int",-1,"int",10,"ptr*",0,"DWORD*",0)
[/autoit][autoit][/autoit][autoit]
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])
EndIfMsgBox(0,"Fertig",$clientname)
[/autoit]