Page 1 of 1 1
Topic Options
#133329 - 2005-02-02 11:12 PM How to enumerate session-level processes when in Terminal Server session
pearly Offline
Getting the hang of it
*****

Registered: 2004-02-04
Posts: 92
I have a KiXtart script which is a front-end to an application (we'll call it, 'X'). It first detects if 'X' is already opened. If it is, it terminates, else it launches.

In single-session, client workstations, my KiXtart script works fine. But in Terminal Server, the UDF, 'EnumProcess' seems to enumerate from a master list of all processes running on the server (including processes from other sessions).

Is there a way to control the enumeration to only enumerate within the process list of the active session? Any thoughts?

Top
#133330 - 2005-02-03 07:38 AM Re: How to enumerate session-level processes when in Terminal Server session
Howard Bullock Offline
KiX Supporter
*****

Registered: 2000-09-15
Posts: 5809
Loc: Harrisburg, PA USA
You can use the GetOwner method to return the process owner then only process the data owned by the user. Unfortunately I can not get it to work in KiXtart. Here is the VBS code which does work.
Code:
strComputer = "."

Set colProcesses = GetObject("winmgmts:" & _
"{impersonationLevel=impersonate}!\\" & strComputer & _
"\root\cimv2").ExecQuery("Select * from Win32_Process")

For Each objProcess in colProcesses

Return = objProcess.GetOwner(strNameOfUser)
If Return <> 0 Then
Wscript.Echo "Could not get owner info for process " & _
objProcess.Name & VBNewLine _
& "Error = " & Return
Else
Wscript.Echo "Process " _
& objProcess.Name & " is owned by " _
& "\" & strNameOfUser & "."
End If
Next



I think you need to pass by reference but KiX can not do that. Can anyone else provide a solution or better description of this issue?
_________________________
Home page: http://www.kixhelp.com/hb/

Top
#133331 - 2005-02-03 09:45 AM Re: How to enumerate session-level processes when in Terminal Server session
Richard H. Administrator Offline
Administrator
*****

Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
A simpler solution is just to limit the returned processes to those started by this session.

The following code does that. I've not tried it on a farm member server console but it should work there too as it works OK on a stand-alone machine.

Code:
If InStr(%SESSIONNAME%,"#") $sSession=Split(%SESSIONNAME%,'#')[1] EndIf

If Not CInt($sSession) $sSession=0 EndIf

$strComputer = "."
$colProcesses = GetObject("winmgmts:"
+ "{impersonationLevel=impersonate}!\\"
+ $strComputer
+ "\root\cimv2").ExecQuery("Select * from Win32_Process Where SessionID='"+$sSession+"'")

For Each $objProcess in $colProcesses
$objProcess.SessionId ": " $objProcess.Name ?
Next


Top
#133332 - 2005-02-03 09:06 PM Re: How to enumerate session-level processes when in Terminal Server session
pearly Offline
Getting the hang of it
*****

Registered: 2004-02-04
Posts: 92
Thanks guys for the quick response.

Richard, I have used your function and it works fine on a stand-alone, but I don't get any processes returned when running it on a Terminal Server session. It's able to get the Session # (which was 8 in my case), but it doesn't list any processes. Do I need to change $strComputer or anything else. I'm very new to WinMgmt stuff, so any help would be appreciated.

Btw, this is the EnumProcess code I used for stand-alone machines :

Code:
Function EnumProcess($exe, optional $terminate, optional $Computer)
Dim $winmgmts, $ExecQuery, $Process, $id
Dim $GetObject
If NOT $computer $computer=@wksta EndIf
$winmgmts="winmgmts:{impersonationLevel=impersonate}!//$COMPUTER"
Select
Case Val($exe)>0
$ExecQuery="select * from Win32_Process where ProcessId='$exe'"
$GetObject=GetObject($winmgmts).ExecQuery($ExecQuery)
For Each $Process in $GetObject
If $terminate $=$Process.Terminate EndIf
$EnumProcess = $Process.name
Next
$GetObject=''
Case VarType($exe)=8
$ExecQuery="select * from Win32_Process where Name='$exe'"
$GetObject=GetObject($winmgmts).ExecQuery($ExecQuery)
For Each $Process in $GetObject
If $terminate $=$Process.Terminate EndIf
$id=$Process.ProcessId
$EnumProcess = "$Id" + "|" + "$EnumProcess"
Next
$EnumProcess=Left($EnumProcess,Len($EnumProcess)-1)
$GetObject=''
Case 1
Exit 1
EndSelect
EndFunction


Top
#133333 - 2005-02-03 09:22 PM Re: How to enumerate session-level processes when in Terminal Server session
pearly Offline
Getting the hang of it
*****

Registered: 2004-02-04
Posts: 92
After further testing, it looks like the code is not getting the Session ID correctly. I hard-coded the session id for testing purposes and it returned the processes active for that session.

But I'm not sure how to fix the session id retrieval code.

Top
#133334 - 2005-02-03 11:10 PM Re: How to enumerate session-level processes when in Terminal Server session
pearly Offline
Getting the hang of it
*****

Registered: 2004-02-04
Posts: 92
After extensive testing, I found out that the number referenced in %SESSIONNAME% is not the same number as the session id under Win32_Process.

However, I did find that the %TEMP% and %TMP% env variables contain the session id at the end of the path.

Example : C:\Documents and Settings\[username]\Local Settings\Temp\[session_id]

I'm not sure how solid this is, but it'll do for now unless you guys have a better idea to get the session id. Here is the revised EnumProcess function which supports Terminal Server sessions.

Code:

Function ProductSuite ($Product)
Dim $res, $x

Select
Case $Product = "None"
$x=0
Case $Product = "Small Business"
$x=1
Case $Product = "Enterprise"
$x=2
Case $Product = "BackOffice"
$x=4
Case $Product = "CommunicationServer"
$x=8
Case $Product = "Terminal Server"
$x=16
Case $Product = "Small Business (Restricted)"
$x=32
Case $Product = "Embedded NT"
$x=64
Case $Product = "DataCenter"
$x=128
Case $Product = "Single User Terminal Server"
$x=256
Case $Product = "Home Edition"
$x=512
Case $Product = "Blade Server"
$x=1024
Case 1
$res=MessageBox ("Invalid parameter used in function ProductSuite ($Product)",48)
EndSelect

$ProductSuite = $x & Val(@ProductSuite)
EndFunction

Function GetSessionID
Dim $sPath[]

$sPath = Split(%TEMP%, "\")
$GetSessionID = Trim($sPath[Ubound($sPath)])
EndFunction

Function EnumProcess($exe, optional $terminate, optional $Computer)
Dim $winmgmts, $ExecQuery, $Process, $id, $sessionid
Dim $GetObject
If NOT $computer $computer=@wksta EndIf
$winmgmts="winmgmts:{impersonationLevel=impersonate}!//$COMPUTER"
Select
Case Val($exe)>0
If ProductSuite("Terminal Server")
$sessionid = GetSessionID
$ExecQuery="select * from Win32_Process where ProcessId='$exe' and SessionId='$sessionid'"
Else
$ExecQuery="select * from Win32_Process where ProcessId='$exe'"
EndIf
$GetObject=GetObject($winmgmts).ExecQuery($ExecQuery)
For Each $Process in $GetObject
If $terminate $=$Process.Terminate EndIf
$EnumProcess = $Process.name
Next
$GetObject=''
Case VarType($exe)=8
If ProductSuite("Terminal Server")
$sessionid = GetSessionID
$ExecQuery="select * from Win32_Process where Name='$exe' and SessionId='$sessionid'"
Else
$ExecQuery="select * from Win32_Process where Name='$exe'"
EndIf
$GetObject=GetObject($winmgmts).ExecQuery($ExecQuery)
For Each $Process in $GetObject
If $terminate $=$Process.Terminate EndIf
$id=$Process.ProcessId
$EnumProcess = "$Id" + "|" + "$EnumProcess"
Next
$EnumProcess=Left($EnumProcess,Len($EnumProcess)-1)
$GetObject=''
Case 1
Exit 1
EndSelect
EndFunction


Top
#133335 - 2005-02-04 09:26 AM Re: How to enumerate session-level processes when in Terminal Server session
Richard H. Administrator Offline
Administrator
*****

Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
I confess I thought that the value in the session ID matched the sessions and the brief testing that I did bore this out.

Maybe it's because I have a Citrix environment with RDP disabled.

Anyhoo, well done on finding an alternative that works for you and thanks for posting the info back.

BTW, I don't think that you need to differentiate the WMI code for non-TS machines. I found that on a normal desktop login the session ID is "0", so just change your GetSessionID UDF to:
Code:
Function GetSessionID()

$GetSessionID = CInt(SubStr(%TEMP%,1+InStrRev(%TEMP%,"\")))
EndFunction



You can now use the same WMI SELECT statement regardless of login type:
Code:
$ExecQuery="select * from Win32_Process where Name='"+$exe+"' and SessionId='"+GetSessionID()+"'"



Top
#133336 - 2005-02-04 06:22 PM Re: How to enumerate session-level processes when in Terminal Server session
pearly Offline
Getting the hang of it
*****

Registered: 2004-02-04
Posts: 92
Ahhh, thanks for putting the final finishing to the code. I will definitely put that in.

Edit:

I found out that the %TEMP% environment variable returns letters for session_ids greater than 9. Therefore, session_id '10' is 'a', etc.

i.e. C:\Documents and Settings\[username]\Local Settings\Temp\a

So I have modified the function, GetSessionID with the following (I know everyone here likes one-liner functions, but I couldn't do it with this one! Call me a traditional coder! )

Code:

Function GetSessionID
Dim $s_sessionid

$s_sessionid = SubStr(%TEMP%,1+InStrRev(%TEMP%,"\"))
If $s_sessionid <> CInt($s_sessionid)
If Len($s_sessionid) = 1
$s_sessionid = CStr(Asc(Ucase($s_sessionid))-55)
Else
$s_sessionid = CStr(CInt($s_sessionid))
EndIf
EndIf

$GetSessionID = $s_sessionid
EndFunction


Code:

Function EnumProcess($exe, optional $terminate, optional $Computer)
Dim $winmgmts, $ExecQuery, $Process, $id, $sessionid
Dim $GetObject
If NOT $computer $computer=@wksta EndIf
$winmgmts="winmgmts:{impersonationLevel=impersonate}!//$COMPUTER"
$sessionid = GetSessionID
Select
Case Val($exe)>0
$ExecQuery="select * from Win32_Process where ProcessId='$exe' and SessionId='$sessionid'"
$GetObject=GetObject($winmgmts).ExecQuery($ExecQuery)
For Each $Process in $GetObject
If $terminate $=$Process.Terminate EndIf
$EnumProcess = $Process.name
Next
$GetObject=''
Case VarType($exe)=8
$ExecQuery="select * from Win32_Process where Name='$exe' and SessionId='$sessionid'"
$GetObject=GetObject($winmgmts).ExecQuery($ExecQuery)
For Each $Process in $GetObject
If $terminate $=$Process.Terminate EndIf
$id=$Process.ProcessId
$EnumProcess = "$Id" + "|" + "$EnumProcess"
Next
$EnumProcess=Left($EnumProcess,Len($EnumProcess)-1)
$GetObject=''
Case 1
Exit 1
EndSelect
EndFunction



Edited by pearly (2005-02-09 01:32 AM)

Top
Page 1 of 1 1


Moderator:  Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart 
Hop to:
Shout Box

Who's Online
0 registered and 874 anonymous users online.
Newest Members
StuTheCoder, M_Moore, BeeEm, min_seow, Audio
17884 Registered Users

Generated in 0.059 seconds in which 0.026 seconds were spent on a total of 12 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org