#133329 - 2005-02-02 11:12 PM
How to enumerate session-level processes when in Terminal Server session
|
pearly
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
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?
|
|
Top
|
|
|
|
#133331 - 2005-02-03 09:45 AM
Re: How to enumerate session-level processes when in Terminal Server session
|
Richard H.
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
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
|
|
|
|
#133334 - 2005-02-03 11:10 PM
Re: How to enumerate session-level processes when in Terminal Server session
|
pearly
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
   
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
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
|
|
|
|
Moderator: Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart
|
0 registered
and 874 anonymous users online.
|
|
|