有C:/Document1和C:/Document2这样两个文件夹,里面分别有一个相同的Exe文件E1和E2,它的作用是一定被执行就处理该文件夹下的文件。
需求:不可以修改Exe文件,通过一个程序P1来完成:
定时运行(Exe文件中没有定时功能)。P1运行,保证E1和E2都要运行,即如果运行了就要保持,如果没有运行的话就要启动Exe。写入日志。需要写入如下内容:
------------------------------------------------
Process ID: 3036
Process Path:
Time Created: 2/14/2007 11:04:53 AM
Time Deleted: 2/14/2007 11:05:23 AM
Duration: 30 seconds
------------------------------------------------
启动了几个就要写入几个。
Note: 进程名称相同,路径不同,不能修改Exe文件。
方案:通过一个将一个VBS程序添加到Task Schedule中来定时地执行。通过VBS可以实现对Process的查询,以及对Process的create和delete的情况进行记录。
实现代码如下:
On
error
resume
next
'
The path of the executable.
'
The first path is as usual.
'
The second path is on the C disk.(You can copy the notepad.exe from system32 and run it.)
Dim
strPath1
Dim
strPath2
'
The name of the process.
Dim
strNameOfProcess
'
The interval string between different log data.
Dim
strInterval
'
An Integer
'
0 The process don't exists in the Windows Task Manager
'
1 Exist one of two.
'
2 Both exist.
Dim
intWhetherExist
'
The path of the process need to be fun.
Dim
strExePath
'
The ID of the process need to be fun.
Dim
intExeID
'
Save the match relationship between ProcessID and ExecutablePath in this array.
Dim
arrayProcessIDandExecutablePath(
1
,
1
)
'
The path of the log file.
Dim
strLogPath
'
--------------------------------------------------------------------------------
'
Take notepad.exe for example. Open just one notepad.
strPath1
=
"
C:WINNTSystem32 otepad.exe
"
strPath2
=
"
C: otepad.exe
"
strNameOfProcess
=
"
notepad.exe
"
strInterval
=
"
------------------------------------------------
"
strLogPath
=
"
c: estfile.txt
"
'
--------------------------------------------------------------------------------
'
Default is zero.
intWhetherExist
=
0
'
Create an array contains the name of all processes need to be found.
strComputer
=
"
.
"
arrTargetProcs
=
Array
(strNameOfProcess)
'
---------------------------------------------------------------
'
1. Find the process we want.
'
---------------------------------------------------------------
'
Find the process in the name list.
Set
objWMIService
=
GetObject
(
"
winmgmts:
"
_
&
"
{impersonationLevel=impersonate}!/
"
&
strComputer
&
"
ootcimv2
"
)
Set
colProcesses
=
objWMIService.ExecQuery(
"
SELECT * FROM Win32_Process
"
)
For
Each
objProcess in colProcesses
For
Each
strTargetProc In arrTargetProcs
If
LCase
(objProcess.Name)
=
LCase
(strTargetProc)
Then
'
Exist.
intWhetherExist
=
intWhetherExist
+
1
'
msgbox objProcess.ExecutablePath
strExePath
=
objProcess.ExecutablePath intExeID
=
objProcess.ProcessId
If
Err
<>
0
Then
WScript.Echo
"
Error on associators query=
"
_
&
Err.number _
&
"
"
&
Err.Description WScript.Quit
End
If
End
If
Next
Next
Dim
WshShell
Set
WshShell
=
Wscript.CreateObject(
"
Wscript.Shell
"
)
'
Confirm whether exists.
Select
Case
intWhetherExist
Case
0
'
If not exist, run them.
'
-----------------------------------------
'
I use constant addresses.
'
-----------------------------------------
WshShell.Run(strPath1) WshShell.Run(strPath2)
'
msgbox strExePath2
Case
1
'
-----------------------------------------
'
Make sure which executable had been run.
'
-----------------------------------------
select
case
LCase
(strExePath)
case
LCase
(strPath1) WshShell.Run strPath2
case
LCase
(strPath2) WshShell.Run strPath1
end
select
Case
Else
'
Do nothing
End
Select
'
---------------------------------------------------------------
'
2. Save the match relationship in the array.
'
---------------------------------------------------------------
'
Find the process in the name list.
Set
objWMIService
=
GetObject
(
"
winmgmts:
"
_
&
"
{impersonationLevel=impersonate}!/
"
&
strComputer
&
"
ootcimv2
"
)
Set
colProcesses
=
objWMIService.ExecQuery(
"
SELECT * FROM Win32_Process
"
)
Dim
intI1, intI2, intI3intI1
=
0
intI2
=
0
intI3
=
0
For
Each
objProcess in colProcesses
For
Each
strTargetProc In arrTargetProcs
'
Select
Case
intWhetherExist
Case
0
If
LCase
(objProcess.Name)
=
LCase
(strTargetProc)
Then
'
Exist.
arrayProcessIDandExecutablePath(intI1,
0
)
=
objProcess.ProcessId arrayProcessIDandExecutablePath(intI1,
1
)
=
objProcess.ExecutablePath intI1
=
intI1
+
1
End
If
Case
1
arrayProcessIDandExecutablePath(
0
,
0
)
=
intExeID arrayProcessIDandExecutablePath(
0
,
1
)
=
strExePath intI1
=
intI1
+
1
Case
Else
'
Do nothing
End
Select
Next
Next
intI1
=
0
'
-------------------------------------------------------
'
3. Track the process and write log
'
-------------------------------------------------------
Set
objWMIService
=
GetObject
(
"
winmgmts:/
"
&
strComputer
&
"
ootcimv2
"
)
Set
colMonitorProcess
=
objWMIService.ExecNotificationQuery _ (
"
SELECT * FROM __InstanceDeletionEvent
"
_
&
"
Within 1 WHERE TargetInstance ISA 'Win32_Process'
"
)
Do
while
intI3
<
2
Set
objLatestEvent
=
colMonitorProcess.NextEvent
For
Each
strTargetProc In arrTargetProcs
'
Check the process name.
If
LCase
(objLatestEvent.TargetInstance.Name)
=
LCase
(strTargetProc)
Then
'
Get the executablePath through the processID and the match relationship
'
between processID and executablePath.
Do
While
intI2
<
2
If
objLatestEvent.TargetInstance.ProcessId
=
arrayProcessIDandExecutablePath(intI2,
0
)
Then
strProcDeleted
=
Now
strProcCreated
=
_ WMIDateToString(objLatestEvent.TargetInstance.CreationDate) WriteToFile(
"
Process Name:
"
&
objLatestEvent.TargetInstance.Name) WriteToFile(
"
Process ID:
"
&
objLatestEvent.TargetInstance.ProcessId) WriteToFile(
"
Process Path:
"
&
arrayProcessIDandExecutablePath(intI2,
1
)) WriteToFile(
"
Time Created:
"
&
strProcCreated) WriteToFile(
"
Time Deleted:
"
&
strProcDeleted) intSecs
=
DateDiff
(
"
s
"
, strProcCreated, strProcDeleted) WriteToFile(
"
Duration:
"
&
intSecs
&
"
seconds
"
) WriteToFile(strInterval)
End
If
intI2
=
intI2
+
1
Loop
intI2
=
0
intI3
=
intI3
+
1
End
If
Next
Loop
intI3
=
0
'
msgbox arrayProcessIDandExecutablePath(0, 0)
'
msgbox arrayProcessIDandExecutablePath(0, 1)
'
msgbox arrayProcessIDandExecutablePath(1, 0)
'
msgbox arrayProcessIDandExecutablePath(1, 1)
'
----------------------------------------------------------------
'
Convert WMI DATETIME format to US-style date string.
'
----------------------------------------------------------------
Function
WMIDateToString(dtmDate)WMIDateToString
=
CDate
(
Mid
(dtmDate,
5
,
2
)
&
"
/
"
&
_
Mid
(dtmDate,
7
,
2
)
&
"
/
"
&
_
Left
(dtmDate,
4
)
&
"
"
&
_
Mid
(dtmDate,
9
,
2
)
&
"
:
"
&
_
Mid
(dtmDate,
11
,
2
)
&
"
:
"
&
_
Mid
(dtmDate,
13
,
2
))
End Function
'
----------------------------------------------------------
'
Write log
'
----------------------------------------------------------
Function
WriteToFile(strInfo)
Const
ForReading
=
1
, ForWriting
=
2
, ForAppending
=
8
Dim
fso, f, strOriginal
Set
fso
=
CreateObject
(
"
Scripting.FileSystemObject
"
)
'
-----------------------------------------------------
'
1. Whether the file has existed.
'
-----------------------------------------------------
If
Not
(fso.FileExists(strLogPath))
Then
Set
f
=
fso.CreateTextFile(strLogPath,
True
)
End
If
'
Use ForWriting style of OpenTextFile, so we need to rewrite the log in this file.
'
We also can use ForAppending style.
Set
f
=
fso.OpenTextFile(strLogPath, ForAppending,
True
) f.Write VbCrLf
&
strInfo
End Function
现在的问题是:
语句
Set
objLatestEvent
=
colMonitorProcess.NextEvent
执行的时候会等待来监测到Exe
文件的Process被Delete时的时间,所以进程中会多一个Wscript.exe的进程。如果执行很多次的话,那么就会出现很多个相同的进程。一个大约占用7M内存。为了解决这个问题,我定义了
while
intI3
<
2
因为我需要考虑运行两个Exe文件。但是当我运行了VBS程序一次(我叫它VBS1),会出现两个Notepad(如果你没有打开过代码中提到路径的Notepad的话),然后你关掉一个,这个时候VBS1仍然存在,等待另外一个Notepad被关掉以后才结束。(到目前为止了解我所提到的么?)
OK, go on. 因为我们是Task Schedule来定时执行,如果这个时候又执行了一个VBS程序(我叫它VBS2),我希望是它启动一个Notepad,并且只监测这一个Notepad的情况。但是实际情况是,如果我关闭了VBS1所产生的剩余的那个Notepad的话,日志中会写入相同的两条信息,而VBS2产生的那个Notepad的变化将不会被记录(因为VBS2产生的Wscript已经结束了)。
我怎么能让他们分工明确??非常感谢。
自己第一次用VBScript,因为工作的需要。请大家不吝赐教。
Email: dutguoyi@hotmail.com