Home > Archive > WSH > September 2004 > Multithreading scripts
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Multithreading scripts
|
|
| Jeff Giroux 2004-07-12, 8:55 pm |
| Is there a way to have a script multithread? For example, I would like to ping multiple computers at the same time rather than wait one by one. See below:
On Error Resume Next
Const ForAppending = 8
Set objShell = WScript.CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set PingFile = objFSO.OpenTextFile("C:\temp\track_sheet.txt")
Set objTextFile = objFSO.OpenTextFile _
("C:\temp\PowerOn_log.txt", ForAppending, True)
Do Until PingFile.AtEndofStream
strComputer = PingFile.Readline
Set objExecObject = objShell.Exec("cmd /c ping -n 1 -w 300 " & strComputer)
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadLine()
If Instr(strText, "Reply") > 0 Then
objTextFile.WriteLine(strComputer)
Exit Do
End If
Loop
Loop
Any suggestions please.
Thanks,
Jeff
| |
| Justin Piper 2004-07-13, 3:55 pm |
| Jeff Giroux wrote:
> Is there a way to have a script multithread? For example, I would like
> to ping multiple computers at the same time rather than wait one by one.
Well, the simple answer for this specific situation would be to use nmap
(http://www.insecure.org/nmap/) instead of rolling your own utility. But
in general I think there are two options for parallel script execution.
Neither is truly a threading solution, as the individual scripts are not
able to communicate with eachother. It is also likely that they will not
be able to simulteniously write to the same file, so in your example you
would need to try to open the file, wait for a random period if the file
is locked by another process, and try again until successful. I suspect
that this will not be faster than just sticking to a single script, but
I have not actually tried it.
The first and simplest method would be to write a seperate script that
both pings the host and writes the result to the file, and then invoke
it from the main script. Your loop might look similar to this:
Do Until PingFile.AtEndofStream
strComputer = PingFile.Readline
objShell.Exec( "wscript.exe ping.vbs " _
& strComputer _
& " C:\temp\PowerOn_log.txt")
Loop
The second method is to abuse the WSHController object to simulate
threads. This does have an advantage in that you can terminate any
remaining threads before the main script exits, however it requires
enabling remote scripting, which may have security implications of which
I am unaware. Perhaps someone more familair with the concept than I can
chime in.
To use WSHController, you will need to create a string value named
"Remote" under the registry key "HKLM\SOFTWARE\Microsoft\Windows Script
Host\Settings", and you will need to set it to "1". Once that is done,
you can modify the example files, controller.vbs and thread.vbs, to suit
your needs. The examples demonstrate starting new threads, passing
arguments, error handling and tracking execution status.
' controller.vbs
Option Explicit
Dim controller, threads, done, i
' Create the controller object.
Set controller = CreateObject("WSHController")
' Start two remote scripts. Note that arguments can be passed to the
' remote scripts in a manner similar to that which WSHShell.Exec
' uses.
threads = Array( _
controller.CreateScript("thread.vbs 10", "localhost"), _
controller.CreateScript("thread.vbs 5", "localhost"), _
controller.CreateScript("thread.vbs", "localhost"), _
controller.CreateScript("thread.vbs foo", "localhost"))
done = False
For i = 0 To UBound(threads)
WScript.ConnectObject threads(i), "Thread_"
threads(i).Execute
Next
Do Until done
WScript.StdOut.WriteLine "controller.vbs: tick"
WScript.Sleep 2000
Loop
Sub Thread_Start()
WScript.Echo "Thread_Start"
done = False
End Sub
Sub Thread_End()
Dim alldone, i
WScript.Echo "Thread_End"
alldone = True
' Since there is no way to know which thread terminated, check the
' status of each. If any are still executing, continue to wait.
For i = 0 To UBound(threads)
If (threads(i).Status = 0) Then
alldone = False
Exit For
End If
Next
done = alldone
End Sub
Sub Thread_Error()
Dim i
WScript.Echo "Thread_Error"
For i = 0 To UBound(threads)
WScript.Echo "threads(" & i & "): " _
& threads(i).Error.Description
Next
End Sub
' thread.vbs
Option Explicit
Dim i
If WScript.Arguments.Count = 1 Then
If IsNumeric(WScript.Arguments(0)) Then
For i = 1 To CLng(WScript.Arguments(0))
WScript.Sleep 1000
Next
Else
Err.Raise vbObjectError + 2, _
"thread.vbs", _
"Expected numeric value: " + WScript.Arguments(0)
End If
Else
Err.Raise vbObjectError + 1, _
"thread.vbs", _
"Insufficient arguments"
End If
--
Justin Piper
Bizco Technologies
http://www.bizco.com/
| |
| Skippy 2004-07-29, 3:55 pm |
| I have a logic that works as follows.
Master script:
1. Create a temp directory off the folder the script was excuted from
(VBSTEMP)
2. Read a list of computer names from the domain or a text file into an
array
3. For each computer in that array, create a slave script named
<computer.vbs> that writes it's output to <computername.txt> and then
deletes itself
4. Execute every slave script with the shell.run method. (done by
looping through the array) (I use a counter that will stop and pause every
300 machines or so depending on my system)
5. Wait until every slave script has been deleted by using a do loop
that searches the vbstemp directory for any files named *.vbs
6. Read the output of all the computer.txt files and then parse it into
a CSV file
7. Delete the vbstemp directory
Example Slave script1:
1. Ping every machine using shell.run "cmd /c ping -n1 computerName >
computername.txt"
2. Delete computername.vbs (yes a running vbs file can delete itself)
Example Salve script2:
1. Using the Filesystem object, open a file named <computername.txt>
2. using the Filesytem object, determine the dll version of
MSJETOLEDB.DLL located in \\computername\c$\winnt\system32
3. Write the version to the computername.txt file
4. Delete computername.vbs
Make sure your slave scripts can account for errors so that they will write
a .txt and delete the .vbs no matter what.
Using this method, I can determine whether or not 360 servers are up in
under a minute. I can also determine the dll version of 5500 computers in
around 10 minutes. (Subject to my PC being COMPLETELY horked up)
I have also used this method to read backup exec logs on 360+ server and
then parse into an Excel file what the backup status of 360 server is, and
highlight those that need attention. The backup script takes about 2 minutes
to run and saves me HUGE amounts of time over execview. It also lets me see
status of over 77 servers that are running NT backup.. .its a management
tool for NTBACKUP! (Please keep the men for Veritas for bumping me off for
writing that!!!!)
| |
| roopak 2004-08-24, 5:32 pm |
| I have a solution that I recently used, seems to be working:
The WScript lets you define COM objects from script, as a .wsc file.
See the example below:
<?xml version="1.0"?>
<component>
<registration
description="TestHelloWorld"
progid="TestHelloWorld.WSC"
version="1.00"
classid="{B76005C7-A9E5-47b5-916A-38DD17060107}"
>
</registration>
<public>
<property name="stdOut">
<put/>
</property>
<method name="startTest">
</method>
</public>
<script language="JScript">
<![CDATA[
var description = new TestHelloWorld;
function TestHelloWorld()
{
this.put_stdOut = put_stdOut;
this.startTest = startTest;
}
function put_stdOut(newValue){
stdOut= newValue;
}
function startTest()
{
stdOut.WriteLine(" Hello world ");
return "Temporary Value";
}
]]>
</script>
</component>
Now you can write a program in C++ that simply takes a AppId name and a function name and will invoke n number of threads using that, you can be real fancy with that and create that program itself as a COM control which takes a function name and the appid name as argument and create thread.
I hope that help u.
Roopak
quote: Originally posted by Jeff Giroux
Is there a way to have a script multithread? For example, I would like to ping multiple computers at the same time rather than wait one by one. See below:
On Error Resume Next
Const ForAppending = 8
Set objShell = WScript.CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set PingFile = objFSO.OpenTextFile("C:\temp\track_sheet.txt")
Set objTextFile = objFSO.OpenTextFile _
("C:\temp\PowerOn_log.txt", ForAppending, True)
Do Until PingFile.AtEndofStream
strComputer = PingFile.Readline
Set objExecObject = objShell.Exec("cmd /c ping -n 1 -w 300 " & strComputer)
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadLine()
If Instr(strText, "Reply") > 0 Then
objTextFile.WriteLine(strComputer)
Exit Do
End If
Loop
Loop
Any suggestions please.
Thanks,
Jeff
| |
|
| "I have a solution "
Sure, and you can't even get a wsf file done.
"roopak" <roopak.1biudq@mail.codecomments.com> wrote in message
news:roopak.1biudq@mail.codecomments.com...
>
> I have a solution that I recently used, seems to be working:
>
> The WScript lets you define COM objects from script, as a .wsc file.
> See the example below:
>
>
> <?xml version="1.0"?>
> <component>
>
> <registration
> description="TestHelloWorld"
> progid="TestHelloWorld.WSC"
> version="1.00"
> classid="{B76005C7-A9E5-47b5-916A-38DD17060107}"
> </registration>
>
> <public>
>
> <property name="stdOut">
> <put/>
> </property>
> <method name="startTest">
> </method>
> </public>
>
> <script language="JScript">
> <![CDATA[
>
> var description = new TestHelloWorld;
>
> function TestHelloWorld()
> {
> this.put_stdOut = put_stdOut;
> this.startTest = startTest;
> }
>
>
> function put_stdOut(newValue){
> stdOut= newValue;
> }
>
> function startTest()
> {
> stdOut.WriteLine(" Hello world ");
> return "Temporary Value";
> }
>
>
>
> ]]>
> </script>
>
> </component>
>
>
> Now you can write a program in C++ that simply takes a AppId name and a
> function name and will invoke n number of threads using that, you can be
> real fancy with that and create that program itself as a COM control
> which takes a function name and the appid name as argument and create
> thread.
>
> I hope that help u.
> Roopak
>
> Jeff Giroux wrote:
>
>
>
> --
> roopak
> ------------------------------------------------------------------------
> Posted via http://www.codecomments.com
> ------------------------------------------------------------------------
>
|
|
|
|
|