Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

VBScript with Sessionid and RDP

483 views
Skip to first unread message

Big Passeron

unread,
Feb 27, 2009, 4:40:07 AM2/27/09
to
Hi everybody, I'll try to do my best to explain the problem I encounter with
a little VB Script.
I've scheduled a script to run every few minutes to check for the presence
of a process running.
There must be ONLY 1 INSTANCE of this process executing and this instance
must be executed INSIDE THE LOCAL SESSION of a Windows 2003 server.

When the script executes, it must check for the presence of this process.
If it fails to find an instance it throws a new instance.
If it finds just one instance inside the local session it must do nothing.
If it find more than one instance it must kill non local instances (the
server can be accessed at the same time by a couple of people by means of RDP)
My assumption is that local session has always session id=0, while RDP
session #1 and RDP session #2 have session id 1 and 2.
Unfortunately, this assumption is far from being always true.

Sometimes local console has session id=1 so script fails; some others RDP
session #2 has session id=4 and so forth.

Is there a way to discriminate between local session and RDP session without
the chance to make a mistake?

Before attaching the code I wanna tell that it would be great if the script
could also realize if a process is blocked and take care of relaunch it.

The code follows:


Option Explicit
Dim objWMIService, objProcess, colProcess
Dim ActiveAcquisitionsConsole, ActiveAcquisitionsSession1,
ActiveAcquisitionsSession2

Dim objWMIServiceNewInstance, objProcessNewInstance
Dim strShellNewInstance, objProgramNewInstance, strComputerNewInstance,
strExeNewInstance

Dim objWMIService1, objProcess1, colProcess1
Dim objWMIService2, objProcess2, colProcess2


Dim strComputer, strAcquisitionProcess
strComputer = "."
strAcquisitionProcess = "'MySoftware.exe'"

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")


'Search for MySoftware.exe instances inside the local console
Set colProcess = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = " & strAcquisitionProcess )

ActiveAcquisitionsConsole=0

For Each objProcess in colProcess
ActiveAcquisitionsConsole= ActiveAcquisitionsConsole + 1
Next


Set objWMIService1 = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")

'Search for MySoftware.exe instances inside the first RDP session (assuming
this session id=1)
Set colProcess1 = objWMIService1.ExecQuery("Select Name from Win32_Process
Where Name='MySoftware.exe' and SessionID = 1" )


ActiveAcquisitionsSession1= 0
For Each objProcess1 in colProcess1
ActiveAcquisitionsSession1= ActiveAcquisitionsSession1 + 1
Next


'Kill every instance of MySoftware.exe inside the first RDP session
(assuming this session id=1)
For Each objProcess1 in colProcess1
objProcess1.Terminate()
Next


Set objWMIService2 = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _
& strComputer & "\root\cimv2")

'Search for MySoftware.exe instances inside the second RDP session
(assuming this session id=2)

Set colProcess2 = objWMIService2.ExecQuery("Select Name from Win32_Process
Where Name='MySoftware.exe' and SessionID = 2" )


ActiveAcquisitionsSession2= 0
For Each objProcess2 in colProcess2
ActiveAcquisitionsSession2= ActiveAcquisitionsSession2 + 1
Next

'Kill every instance of MySoftware.exe inside the second RDP session
(assuming this session id=2)
For Each objProcess2 in colProcess2
objProcess2.Terminate()
Next


'No instances of MySoftware.exe on local console -> let's launch an instance
if ActiveAcquisitionsConsole = 0 Then

strComputerNewInstance = "."
strExeNewInstance = "MyPathFolder\MySoftware.exe"
' Connect to WMI
set objWMIServiceNewInstance = getobject("winmgmts://"_
& strComputerNewInstance & "/root/cimv2")


Set objProcessNewInstance = objWMIServiceNewInstance.Get("Win32_Process")
Set objProgramNewInstance = objProcessNewInstance.Methods_( _
"Create").InParameters.SpawnInstance_
objProgramNewInstance.CommandLine = strExeNewInstance


Set strShellNewInstance = objWMIServiceNewInstance.ExecMethod( _
"Win32_Process", "Create", objProgramNewInstance)

End if

WScript.Quit


Thanks for your help!

Al Dunbar

unread,
Mar 1, 2009, 6:39:03 PM3/1/09
to

"Big Passeron" <BigPa...@discussions.microsoft.com> wrote in message
news:22E512FE-8821-4A98...@microsoft.com...

> Hi everybody, I'll try to do my best to explain the problem I encounter
> with
> a little VB Script.
> I've scheduled a script to run every few minutes to check for the presence
> of a process running.
> There must be ONLY 1 INSTANCE of this process executing and this instance
> must be executed INSIDE THE LOCAL SESSION of a Windows 2003 server.
>
> When the script executes, it must check for the presence of this process.
> If it fails to find an instance it throws a new instance.
> If it finds just one instance inside the local session it must do nothing.
> If it find more than one instance it must kill non local instances (the
> server can be accessed at the same time by a couple of people by means of
> RDP)
> My assumption is that local session has always session id=0, while RDP
> session #1 and RDP session #2 have session id 1 and 2.
> Unfortunately, this assumption is far from being always true.

Logon to the system directly and type SET at the command prompt, saving the
results in a text file. Then logon to the system via RDP and do the same
thing. You will likely find that some of the environment variables defined
have values depending on whether the session is an RDP session. I have
nothing to RDP against, however, I think you might find CLIENTNAME and
SESSIONNAME useful; when logged on directly, they are set to "Console".

/Al

Big Passeron

unread,
May 6, 2009, 4:26:01 AM5/6/09
to
Hi Al,
I've tried to take advantage of variable "SESSIONNAME" inside my script but
I couldn't manage to do it.
Furthermore, I'm everything but a programmer.

Eventually this (simple?) script would save me a lot of headache, so I'm
asking for futher assistance.

Can someone point me to the right direction with more straightforward
suggestions?

Thanks.

Pegasus [MVP]

unread,
May 6, 2009, 7:50:57 AM5/6/09
to

"Big Passeron" <BigPa...@discussions.microsoft.com> wrote in message
news:A17A3778-0B0D-4289...@microsoft.com...

> Hi Al,
> I've tried to take advantage of variable "SESSIONNAME" inside my script
> but
> I couldn't manage to do it.
> Furthermore, I'm everything but a programmer.
>
> Eventually this (simple?) script would save me a lot of headache, so I'm
> asking for futher assistance.
>
> Can someone point me to the right direction with more straightforward
> suggestions?
>
> Thanks.

WMI is a wonderful thing. However, when someone has already done most of the
work and delivered a suitable tool then it would make sense to use that
tool. Tasklist.exe / Taskkill.exe are such tools. Tasklist tells you
unambiguously whether a process is run from the console or from an RDP
session and it also gives you a process-ID that you can feed into
taskkill.exe. Try the following batch file:

[1] @ECHO off
[2] set active=no
[3] set task=MySoftware.exe
[4] for /F "tokens=1-3" %%a in ('tasklist /v /fo table ^| find /i "%task%"')
do (
[5] if /i [%%c]==[Console] (set active=yes) else (echo taskkill /f /pid
%%b)
[6] )
[7] if %active%==no echo "c:\Program Files\Passeron\%task%"

To activate the batch file, remove the word "echo" from lines [5] and [7].
Post again if you want to know what each line of code does. Make sure to
unwrap wrapped lines properly!


Big Passeron

unread,
May 6, 2009, 8:45:01 AM5/6/09
to
Hi Pegasus,
I didn't know taskkill until now.
Abyway, I've followed your suggestion, removed echo from line 5 and 7 but I
get a "The syntax of the command is incorrect"

The code follows:

@ECHO off
set active=no
set task="MySoftware.exe"


for /F "tokens=1-3" %%a in ('tasklist /v /fo table ^| find /i "%task%"')
do (

if /i [%%c]==[Console] (set active=yes) else (taskkill /f /pid %%b )
)
if %active%==no "C:\MyFolder\%task%"

Pegasus [MVP]

unread,
May 6, 2009, 10:23:19 AM5/6/09
to
By numbering my lines, I made it absolutely clear where each line starts and
ends. You did not add any line numbers, hence I cannot tell if you unwrapped
the lines correctly. I do not even know which line raises the error
message - how about starting the batch file with "echo on"?


"Big Passeron" <BigPa...@discussions.microsoft.com> wrote in message

news:5DDF9E04-D175-4050...@microsoft.com...

Big Passeron

unread,
May 6, 2009, 11:15:01 AM5/6/09
to
Ok, a few things. This is my script right now:

[1]@ECHO on
[2]set active=no
[3](set task='My Software 1.00.exe')


[4]for /F "tokens=1-3" %%a in ('tasklist /v /fo table ^| find /i "%task%"')
do (

[5]if /i [%%c]==[Console] (set active=yes) else ( taskkill /f /im %%b ))
[6]if %active%==no "C:\My Folder\%task%"

A problem is with task's name that's composed by more than one word and from
uncertainty with single and double quotes.

As a consequence, this is the output given by the command:


C:\My Folder\>set active=no

C:\My Folder\>(set task='My Software 1.00.exe' )

C:\My Folder\>for /F "tokens=1-3" %a in ('tasklist /v /fo table | find /i
"'My Software 1.00.exe'"') do (if /I [%c] == [Console] (set active=yes )
else (taskkill /f /im %b ) )

C:\My Folder\>if no == no "C:\My Folder\'My Software 1.00.exe'"

I guess the problem is with the single quote before my tasks's name. I also
tried with double quotes but the script fails to execute.

Pegasus [MVP]

unread,
May 6, 2009, 12:03:45 PM5/6/09
to
There were several problems with your version of the script:
- Most software houses avoid issuing executables with embedded spaces in the
name, because of known issues with simple scripts. Yours uses embedded
spaces, which causes the batch file to fail.
- You added a set of quotes in line [3]. Sorry, can't do this.
- You merged line [6] in my original code with line [5]. Sorry, can't do
this.
- I used the /pid switch for taskkill. You changed it to /im. This will
cause taskkill to fail.

Here is a modified version that can cope with executables that have embedded
spaces in the name.
[01] @echo off
[02] SetLocal EnableDelayedExpansion
[03] set active=no
[04] set task=My Software 1.00.exe
[05] for /F "tokens=1-3 delims=," %%a in ('tasklist /v /fo csv ^| find /i
"%task%"') do (
[06] for /F %%i in (%%b) do set pid=%%~i
[07] if /i [%%c]==[Console] (set active=yes) else (echo taskkill /f /pid
!pid!)
[08] )
[09] if %active%==no echo "C:\My Folder\%task%"


"Big Passeron" <BigPa...@discussions.microsoft.com> wrote in message

news:AC285389-B482-471F...@microsoft.com...

Big Passeron

unread,
May 12, 2009, 10:53:01 AM5/12/09
to
Pegasus,
your suggestions made me go a little further.
Now, if 2 instances are running (one in console and the other one in a
Remote Desktop Session), only RD Session instance is killed.
If only console instance is running nothing happens as I want it to be.
The problem occurs if I have no instances running: in this case a new
instance is thrown (that's ok), but process is execute inside a Remote
Desktop session.

I don't know if this behavior is caused by scheduled task be executed as
user Administrator, while user logged inside Console session is a Standard
User (for security purposes).

To make a long story short, I've made some little modifications to your
script (among the other things, I want the process to be launched with
StandardUser credentials, should an instance not be running), but it still
doesn't work as expected. The code follows:

"[1]@echo on
[2]SetLocal EnableDelayedExpansion
[3]set active=no
[4]set task=MyTask.exe
[5]for /F "tokens=1-3 delims=," %%a in ('tasklist /v /fo csv /fi "imagename
eq %task%"') do (
[6]for /F %%i in (%%b) do set pid=%%~i
[7]if /i [%%c]==[""] (set active=yes) else (taskkill /f /pid !pid!)
[8)
[9]if %active%==no Runas /user:MyServer\StandardUser /savecred
"C:\MyFolder\%task%"
"

Thanks for your help

Pegasus [MVP]

unread,
May 12, 2009, 11:37:45 AM5/12/09
to
Sorry, can't tell without sitting in front of you machine. You need to
execute the following commands at a Command Prompt in order to examine its
output:

set task=MyTask.exe


tasklist /v /fo csv /fi "imagename eq %task%

If you get no output then there you must run this command so that you can
tell the correct image name:

tasklist /v /fo List | more

"Big Passeron" <BigPa...@discussions.microsoft.com> wrote in message

news:72A29975-B448-4938...@microsoft.com...

Big Passeron

unread,
May 12, 2009, 11:51:02 AM5/12/09
to
Hello Pegasus and thanks for your feedback!
The commnad gives me the expected output, i.e. one process running in
"RDP-TCP#12" session.
But like I said before, that happens beacuase if no instance are found
running, a scehduled task throws a new instance but it fires it inside one
remote desktop session (in this case RDP-TCP#12), instead of console session.

i don't know how to correct this behavior...

Pegasus [MVP]

unread,
May 12, 2009, 12:11:26 PM5/12/09
to

"Big Passeron" <BigPa...@discussions.microsoft.com> wrote in message
news:58FE2067-3CFF-4A6F...@microsoft.com...

> Hello Pegasus and thanks for your feedback!
> The commnad gives me the expected output, i.e. one process running in
> "RDP-TCP#12" session.
> But like I said before, that happens beacuase if no instance are found
> running, a scehduled task throws a new instance but it fires it inside one
> remote desktop session (in this case RDP-TCP#12), instead of console
> session.
>
> i don't know how to correct this behavior...

I am unable to duplicate the behaviour you observe. When I run a scheduled
task then it is flagged as a Console session, not as an RDP session. I
tested this both on a WinXP PC and on an SBS installation, using the Task
Scheduler GUI and at.exe. Same result everywhere.


Al Dunbar

unread,
May 12, 2009, 7:17:06 PM5/12/09
to

"Pegasus [MVP]" <ne...@microsoft.com> wrote in message
news:OqvsOxx0...@TK2MSFTNGP02.phx.gbl...

Could it be that the OP is logged on using the account that runs the task in
the scheduler?

/Al


0 new messages