Jump to content

Terminal Server: Howto get a list of all processes of *THIS* session?


Go to solution Solved by rudi,

Recommended Posts

Hi.

For Terminal Server Session Admin Tasks I need to check, if certain EXEs are running for THIS session.

Currently I use a ugly CMD script to catch processes started from *THIS* session.

REM search for the program "DVWIN.EXE", started from "THIS SESSION"
REM
REM for /f "usebackq ...         -> use new semantic, allowing commands in the brackets
REM ... tokens=3" %%a in         -> return 3rd column of each matching result line only. (Default separator = WhiteSpace)
REM (`query session^|find ">"`) 
REM query session                -> this returns all currently existing TS sesstions. The line of "This session" is preceeded by a ">"
REM ^|                           -> pipe the results to the next command, "^" is required to "escape |"
REM find ">"                     -> find the line for "This session" (">")
REM
REM the next search is basically the same, just looking for DVWIN.EXE running in "THIS SESSION ID". 
REM %%r = explicit variable, %%s & %%t = implicit, by the "tokens" statement.
REM to run not from CMD file but directly a the command line, replace the "%%" by "%".

REM the following is ONE line.
for /f "usebackq tokens=3" %%a in (`query session^|find ">"`) do for /f "usebackq tokens=3,4,5" %%r in (`qprocess /ID:%%a ^| find /i "dvwin"`) do echo Session: %%r - PID: %%s - Process Name: %%t

REM Then I can processclose() the DVWIN.EXE started from this session, %%s

Isn't there a possibility to do such a usual thing with pure Autoit? If so, then I miss it 100% >_<

Any suggestions appreciated, Rudi.

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

You could WMI, just one solution. I'm sure there prob a way to do it via DLL, but that's a bit beyond my expertise.

#include <Array.au3>

$arrProcesses = _GetProcessIds(@ComputerName)
_ArrayDisplay($arrProcesses)

Func _GetProcessIds($strHost)
    If Not Ping($strHost,200) Then SetError(1)
    $objWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strHost & "\root\CIMV2")
    If Not IsObj($objWMI) Then SetError(2)
    $colItems = $objWMI.ExecQuery ("SELECT * FROM Win32_Process")
    Dim $arrResults[1][3] = [["Processname","ProcessID","SessionID"]]
    For $objItem In $colItems
        ReDim $arrResults[UBound($arrResults)+1][3]
        $arrResults[UBound($arrResults)-1][0] = $objItem.Name
        $arrResults[UBound($arrResults)-1][1] = $objItem.ProcessId
        $arrResults[UBound($arrResults)-1][2] = $objItem.SessionId
    Next
    Return $arrResults
EndFunc
Link to comment
Share on other sites

You could WMI, just one solution. I'm sure there prob a way to do it via DLL, but that's a bit beyond my expertise.

#include <Array.au3>

$arrProcesses = _GetProcessIds(@ComputerName)
_ArrayDisplay($arrProcesses)

Func _GetProcessIds($strHost)
    If Not Ping($strHost,200) Then SetError(1)
    $objWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strHost & "\root\CIMV2")
    If Not IsObj($objWMI) Then SetError(2)
    $colItems = $objWMI.ExecQuery ("SELECT * FROM Win32_Process")
    Dim $arrResults[1][3] = [["Processname","ProcessID","SessionID"]]
    For $objItem In $colItems
        ReDim $arrResults[UBound($arrResults)+1][3]
        $arrResults[UBound($arrResults)-1][0] = $objItem.Name
        $arrResults[UBound($arrResults)-1][1] = $objItem.ProcessId
        $arrResults[UBound($arrResults)-1][2] = $objItem.SessionId
    Next
    Return $arrResults
EndFunc

Great, thanks!

With Scriptomatic V2 I just went through all the TerminalServ* and TS*, but couldn't figure out, how to retrieve the session ID of THIS session. Any idea, how to pull that info as well?

I'm thinking of using fileinstall() to a random temp EXE file name, an autoit script that will just run a few seconds to pull from your array the seesion ID first. Then I can lookup what programs are running with the same session ID.

Regards, Rudi.

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

Great, thanks!

With Scriptomatic V2 I just went through all the TerminalServ* and TS*, but couldn't figure out, how to retrieve the session ID of THIS session. Any idea, how to pull that info as well?

I'm thinking of using fileinstall() to a random temp EXE file name, an autoit script that will just run a few seconds to pull from your array the seesion ID first. Then I can lookup what programs are running with the same session ID.

Regards, Rudi.

Hi Rudi,

search in Forum for WTSQuerySessionInformation. Maybe this helps you.

;-))

Stefan

Link to comment
Share on other sites

Hi Stefan.

search in Forum for WTSQuerySessionInformation. Maybe this helps you.

I did readup all the hits for WTSQuerySessionInformation, as well as all the WTS* entries nearby this MSDN topic.

It was quite interesting, BUT still I'ven't got a clue how to use these DLL calls to

1.) retrieve the session ID of THIS Session

2.) then to pull a list of all processes started from that Session ID.

To me that's like nice descriptions how to smoothly fly a complicated looping -- but up to now I can't fly at all :/

In the autoit help file there are several "DLL*" entries in the "Process Management" section: Well, I don't know almost anything about DLL calls, so all I can do is to test the sample snippets provided there, but honestly, I don't get the whole thing about calling DLLs, that's all too far beyond my current skills. >_<

I'll try to move on searching for DLL*() calls in the sample code forum here.

Frustrated, Rudi.

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

Hi.

My (ugly) workaround to avoid the DLL*() stuff I'm unable to deal with is this:

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_outfile=z:\TSThisSessionsProcesses.exe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <Constants.au3>
Dim $CMD = ' /c @for /f "usebackq tokens=3" %a in (`query session^|find ">"`) do @for /f "usebackq tokens=3,4,5" %r in (`qprocess /ID:%a^|find /i ">"`) do @echo %r\%s\%t'
Dim $MyRead

$PID = Run(@ComSpec & $CMD, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)

Sleep(2000) ; then the first stdoutread() will already return the results
While 1
    $MyRead = StdoutRead($PID)
    If @error Then ExitLoop
    ; here I do what's needed. Next line just to demonstrate...
    MsgBox(0, "Session-ID\PID\Process", $MyRead,5)
WEnd

While 1
    $MyRead = StderrRead($PID)
    If @error Then ExitLoop
    MsgBox(0, "STDERR read:", $MyRead,5)
WEnd

MsgBox(0, "Done", "Exiting...",3)

From there I use stringsplit to do what's needed.

>_< DLLCall() or some WMI stuff would be much more nifty :(

Now :( Frustrated :D AND ;) unhappy ;)

Rudi.

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

  • 2 weeks later...

Hi.

Bump.

Anyone >_<, who knows a much more easy way to retrieve a list of all process IDs started on a Terminal Server from *THIS* session?

Any further suggestions :( mostly appreciated,

regards, Rudi.

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

  • 13 years later...
  • Solution

Just found a quite straight forward solution, so I update this thread, I've opened quite a number of years ago, in case someone else should search for it:

Choose a $ProcessName, you would like to see just the PIDs started by "ThisUser".

To create some "Differen-User-Processes" start them for a user, you know the password of with:

 

open CMD.EXE box

runas /user:yourdomain\someotheruser cmd.exe

<blind type the pwd of other user>

--> a new CMD box will open, there type

whoami

... to see, it's running as a different user

 

; #RequireAdmin - to retrieve the user's *OWN* process information RequireAdmin is not required

#include <Array.au3>
#include <WinAPIProc.au3>


$ProcessName = "cmd.exe"
$BackSlash="\" ; " to fix forum highlighting
$whoami=@LogonDomain & $BackSlash & @UserName

Local $aAdjust, $aList = 0
Local $hToken = _WinAPI_OpenProcessToken(BitOR($TOKEN_ADJUST_PRIVILEGES, $TOKEN_QUERY))
; Retrieve user names for all processes the system
If Not (@error Or @extended) Then
    $aList = ProcessList($ProcessName)
    If $aList[0][0] = 0 Then
        MsgBox(0, $ProcessName, "No processes found matching  """ & $ProcessName & """.")
    Else
        Local $aData
        For $i = 1 to $aList[0][0]
            $aData = _WinAPI_GetProcessUser($aList[$i][1])
            If IsArray($aData) Then
                if $whoami = $aData[1] & $BackSlash & $aData[0] then ; this is a process of *THIS* user
                    if ProcessClose($aList[$i][1]) Then
                        $aList[$i][1] = $aList[$i][1] & " - "  & $aData[1] & $BackSlash & $aData[0] & " - Process closed successfully."
                    Else
                        $aList[$i][1] = $aList[$i][1] & " - "  & $aData[1] & $BackSlash & $aData[0] & " - Process could *NOT* be closed!"
                    EndIf
                Else
                    if $aData[1]="" Then
                    $aList[$i][1] = $aList[$i][1] & " - "  & $aData[1] & $BackSlash & $aData[0] & " - user couldn't be retrieved."
                    Else
                    $aList[$i][1] = $aList[$i][1] & " - "  & $aData[1] & $BackSlash & $aData[0] & " - other user."
                    EndIf
                    ConsoleWrite( $ProcessName & @TAB & $aList[$i][1] & @TAB & $aData[1] & $BackSlash & $aData[0] & @TAB & "not this user / user cannot be retrieved." & @CRLF)
                EndIf
            Else
                $aList[$i][1] = $aList[$i][1] & " - This user: " & $whoami & " - process user could *NOT* be retrieved."
                ConsoleWrite($ProcessName & @TAB & $aList[$i][1] & @TAB & "process user could *NOT* be retrieved" & @CRLF )

            EndIf
        Next
        $aList[0][0]=UBound($aList)-1
        ; Enable SeDebugPrivilege privilege by default
        ; _WinAPI_AdjustTokenPrivileges($hToken, $aAdjust, 0, $aAdjust)
        _WinAPI_CloseHandle($hToken)
        _ArrayDisplay($aList, $ProcessName & ' by user')
    EndIf
EndIf

 

Edited by rudi

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

I found a way to do what I think you're looking for with the code from 2009 by @spudw2k  (modified a bit for my tastes) give this a shot and see if it works for you (just curious):

#include <Array.au3>

Local $iSession = _GetSessionByPid(@AutoItPID, @ComputerName)
If @error Then
    ConsoleWrite('Error getting Session of pid: ' & @AutoItPID & ' \\ ' & @ComputerName & @CRLF)
    Exit
EndIf
ConsoleWrite('Session of this process: ' & $iSession & @CRLF)

$arrProcesses = _GetProcessIds(@ComputerName, $iSession)
_ArrayDisplay($arrProcesses)

Func _GetProcessIds($strHost = @ComputerName, $iSession = -1)
    Local $oWMI = __WinMgmtsObj($strHost)
    If @error Then Return False

    Local $sSessionWhere = ''
    If $iSession >= 0 Then
        $sSessionWhere = ' WHERE SessionID = ' & $iSession
    EndIf

    $colItems = $oWMI.ExecQuery("SELECT * FROM Win32_Process" & $sSessionWhere)

    Local $iRows = 0
    For $objItem In $colItems
        $iRows += 1
    Next
    Local $arrResults[$iRows + 1][3] = [["Processname", "ProcessID", "SessionID"]]

    $iRows = 1
    For $objItem In $colItems
        $arrResults[$iRows][0] = $objItem.Name
        $arrResults[$iRows][1] = $objItem.ProcessId
        $arrResults[$iRows][2] = $objItem.SessionId
        $iRows += 1
    Next
    Return $arrResults
EndFunc   ;==>_GetProcessIds


Func _GetSessionByPid($iPid, $strHost = @ComputerName)
    Local $oWMI = __WinMgmtsObj($strHost)
    If @error Then
        Return SetError(1, 0, False)
    EndIf

    If Not ($iPid > 0) Then
        Return SetError(2, 0, False)
    EndIf

    $colItems = $oWMI.ExecQuery("SELECT * FROM Win32_Process WHERE ProcessID = " & $iPid)

    For $objItem In $colItems
        If $objItem.SessionId >= 0 Then
            Return $objItem.SessionId
        EndIf
    Next
EndFunc   ;==>_GetSessionByPid

Func __WinMgmtsObj($strHost = @ComputerName)
    Local Static $sPreviousHost = -1
    Local Static $oWMI

    If Not Ping($strHost, 200) Then
        Return SetError(1, 0, False)
    EndIf

    If $sPreviousHost <> $strHost Then
        $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strHost & "\root\CIMV2")
        $sPreviousHost = $strHost
    EndIf
    If Not IsObj($oWMI) Then
        Return SetError(2, 0, False)
    EndIf

    Return $oWMI
EndFunc   ;==>__WinMgmtsObj

 

Edited by mistersquirrle
Updated code

We ought not to misbehave, but we should look as though we could.

Link to comment
Share on other sites

Your code is *NOT* doing what I need. To see what I mean these steps are sufficient:

  • Start a CMD box as a different user as described in my last posting, verify it's running as a different user
  • run your script, sort by process name
  • run sysinternals PROCEXP.EXE, drag drop the crosshair to that CMD box to get the PID
  • Looking up the result array of your script, you will notice, that that PID of the CMD box running as a different user is listed for "your session"

<edit: grammar>

Edited by rudi

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

If the test works for you, then great. However when I follow your testing steps to open a CMD window, it is STILL opened as a process under MY session, not a new session. Normally I only use 1 account, but I do have another set up on this computer. This computer is 'RAVEN', my main user is Raven, and the second user is Poe.

image.png.60c13754a1ce73ce0886ae234cf87e0a.png

 

When I run "runas /user:poe cmd.exe", it opens just fine, but when I used both Process Explorer and AutoIt to get the PID of the window, it returns a process that is under Raven's session (1), not Poe (because Poe is not logged in, Poe does not have a session). 

I tested this however by using a PID of the SYSTEM user, which is session 0, and that works fine:

2023_02_04_10_12_13_C_Users_Raven_Documents_AutoIt_Forums_99000_terminal_server_howto_get_a_list_of.png.6a673ad2ce2e6cba542d63cf0383728b.png

 

I then went ahead and actually signed into the Poe user, switched back to Raven, and now in Task Manager and/or ProcExp I can see that there are actually Pids under session 2, user Poe, and if I take one of those Pids and plug it into the script, or just say show me session 2:

 2023_02_04_10_16_16_Processes_under_session_2.png.712cfdf2e3f3d1673e515392591e44ec.png

 

But even trying "runas /user:poe cmd.exe" AFTER Poe is signed in, it still creates a cmd.exe window under Raven's session (session 1), verified in Task Manager and ProcExp. The user name of the process does now show Poe in the User name column of Task Manager, but session is NOT Poes.

 

So your test/script is not testing the session, but rather the user (as should be clear from _WinAPI_GetProcessUser, it has nothing to do with sessions).

We ought not to misbehave, but we should look as though we could.

Link to comment
Share on other sites

As mentioned above I wanted to distinguish the user account, a process is running with.

 

You are right, for a terminal server, every user will have his/her own session. I'm not sure, if it is possible to start two different sessions using the same user account (e.g. one as console session), I don't think so, because both would need to access and lock files in %userprofile% dir (namely NTUSER.DAT).

 

As replacing signature information is a user based thing for me the "check if there is a outlook.exe running for the currently loggedon user" seems to be the best approach.

 

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...