VBScript takes significantly longer when run using Windows Scheduler - windows

I have a VBScript (.vbs) file which runs a SAS project. The program executes successfully when I run it manually by double-clicking the VBScript file and it takes about a minute and a half to finish.
However, when I schedule the VBScript file in the Windows Task Scheduler, it takes ridiculously long to run - the last time I tried I let it go for two hours before manually ending the task. I know the task is starting because when I refresh the task in Task Scheduler it says it is currently running.
I have several other VBScripts that I use to schedule other SAS projects, none of which have given me this issue. What gives?

Use this alias to force your script to execute with CSCRIPT interpreter. To debug timming, you can use the Timer() function, here is a example:
Set oWSH = CreateObject("WScript.Shell")
Call ForceConsole()
tmpTimer = Timer()
For i = 0 to 10000
a = a + 1
b = Int(Rnd * 500)
If b mod 2 = 0 Then b = 9
WScript.StdOut.WriteLine a
WScript.StdOut.WriteLine b
Next
WScript.StdOut.WriteLine "This loop took " & (Timer()-tmpTimer) & " miliseconds"
WScript.StdIn.ReadLine
Function ForceConsole()
If InStr(LCase(WScript.FullName), "cscript.exe") = 0 Then
oWSH.Run "cscript " & Chr(34) & WScript.ScriptFullName & Chr(34)
WScript.Quit
End If
End Function

Related

VBScript watchdog [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am trying to create a script that will look at a specific .txt file on the local computer, get it's DateLastModified attribute, and compare it to the last/previous value when it was last checked (in a loop, every 1-2 seconds).
The loop (running every second) would increment a counter, and if the counter reaches a limit (say 10 seconds), a section of code would perform a task of "kill/terminate" a specific process/.exe that is likely hung up, and restart it.
I've found some pretty good samples of .vbs online that use subscription events, I don't think this is the route I want/need to go, as the script actually needs to be continuously running and not asynchronously only when the specific file is modified.
Edit: I am looking for a VBScript that provides a "watchdog" function, by monitoring a .txt file for modifications. The script should run a loop every second that checks for modifications, and if no modifications, increments a counter. Once the counter reaches a limit (10 seconds?) it would terminate a fixed process (hardcoded as a parameter in the VBScript), and then relaunch the process (path to the process as a parameter in the VBScript).
I haven't found a good example to share thus far. I've been playing with other examples that utilize the objWMIService.ExecNotificationQuery(Query) which seems cool in that little overhead is used (asynchronous in nature) -- it does not appear to fit my needs as described above.
If I must share what I've found and been toying with... OK... here it is:
intInterval = "1"
strDrive = "C:"
strFolder = "\\Project\\"
strComputer = "."
intTmrVal = 0
Set objWMIService = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2" )
strQuery = "Select * From __InstanceOperationEvent" _
& " Within " & intInterval _
& " Where Targetinstance Isa 'CIM_DataFile'" _
& " And TargetInstance.Name='C:\\Project\\test.txt'"
Set colEvents = objWMIService.ExecNotificationQuery(strQuery)
Do
Set objEvent = colEvents.NextEvent()
Set objTargetInst = objEvent.TargetInstance
Select Case objEvent.Path_.Class
Case "__InstanceCreationEvent"
WScript.Echo "Created: " & objTargetInst.Name
Case "__InstanceDeletionEvent"
WScript.Echo "Deleted: " & objTargetInst.Name
Case "__InstanceModificationEvent"
Set objPrevInst = objEvent.PreviousInstance
For Each objProperty In objTargetInst.Properties_
If objProperty.Value <> objPrevInst.Properties_(objProperty.Name) Then
WScript.Echo "Changed: " & objTargetInst.Name
WScript.Echo "Property: " & objProperty.Name
WScript.Echo "Previous value: " & objPrevInst.Properties_(objProperty.Name)
WScript.Echo "New value: " & objProperty.Value
End If
Next
End Select
'Count how many times it has been modified // just playing with a counter
If objEvent.TargetInstance.LastModified <> objEvent.PreviousInstance.LastModified Then
intTmrVal = intTmrVal+1
WScript.Echo "Changed: " & intTmrVal & " times"
WScript.Echo
End If
Loop
An easy way is to directly set the timeout in the WMI request for the next event
Option Explicit
Const MONITOR_FILE = "c:\temp\test.txt"
Const MONITOR_LIMIT = 10
Dim wmi
Set wmi = GetObject( "winmgmts:" & "{impersonationLevel=impersonate}!\\.\root\cimv2" )
Dim query
query = "SELECT * FROM __InstanceOperationEvent WITHIN 1 " _
& " WHERE TargetInstance ISA 'CIM_DataFile' " _
& " AND TargetInstance.Name='" & Replace(MONITOR_FILE, "\", "\\") & "'"
Dim colEvents
Set colEvents = wmi.ExecNotificationQuery( query )
Dim currentEvent
Do
' Flag value
Set currentEvent = Nothing
' Try to get the next event with a timeout limit
' If a timeout happens we need to catch raised error
On Error Resume Next
Set currentEvent = colEvents.NextEvent( MONITOR_LIMIT * 1000 )
On Error GoTo 0
' If there is not an event there was a timeout
If currentEvent Is Nothing Then
Exit Do
End If
Loop
WScript.Echo "File has not been changed for " & MONITOR_LIMIT & " seconds."
Event watchers react to events when they occur. You, however, want to react to events that are not occurring (namely a file not getting modified). You cannot use an event watcher for that for obvious reasons.
What you need is code that checks the file's last modified date
path = "C:\Project\test.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
ts = fso.GetFile(path).DateLastModified
and then kills a given process if that timestamp is more than x seconds/minutes
pname = "foo.exe"
wmi = GetObject("winmgmts://./root/cimv2")
qry = "SELECT * FROM Win32_Process WHERE Name='" & pname & "'"
If DateDiff("s", ts, Now) > 10 Then
For Each p In wmi.ExecQuery(qry)
p.Terminate
Next
End If
However, the Windows Task Scheduler doesn't support your desired granularity of running the task every second (or every 2 seconds). And even if it did, spawning a new process every second wouldn't be very good for system performance in the first place. You can set a daily schedule and then instruct Task Scheduler to re-run the task every 5 minutes for the duration of a day. The rest you need to account for in your script.
Define a 5 minute timeout and re-run your check in a loop until that timeout expires:
interval = 2 'seconds
timeout = 5 'minutes
endtime = DateAdd("n", timeout, Now)
sleeptime = interval * 1000 'milliseconds
Do
'check and process handling go here
WScript.Sleep sleeptime
Loop Until Now >= endtime
Since fso and wmi can be re-used don't waste resources by re-defining them over and over again inside the loop. Define them just once at the beginning of the script.

VBScript not working when PC is locked

I'm running a VBScript that communicates to an exe file in Windows 7.
The VBScript works great!
The issues I have, is that once the PC has been in locked, goes to sleep or hiberation the VBScript doesn't communicate with the exe application.
The VBScript is running (I have a log that tells me every time a loop is complete, but its not communicating to the exe.
Below is code that is not working when the PC is locked.
Set WSHShell = WScript.CreateObject("WScript.Shell")
' info for exporting data
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0
Dim fso, MyFile, FileName, TextLine, cycles
Dim I
I = 0
Dim n
n = .1 'how often the program saves the data (in minutes)
cycles = 2 'how many times it will save
FileName = "C:\Users\Desktop\new.txt" 'location where the log file will save
Dim sl
sl = n * 60000 'change from seconds to ms for the sleep function
Set fso = CreateObject("Scripting.FileSystemObject")
' Open the file for output
Set MyFile = fso.OpenTextFile(FileName, ForAppending, True, TristateTrue)
' Write to the file.
MyFile.WriteLine "Log file for recording data from Yokogawa MX100 (" & cycles
& " cycles)"
WSHShell.Run "MXStandardE.exe"
WScript.Sleep 1000
WSHShell.AppActivate "MXStandardE.exe"
WScript.Sleep 1000
Do while I < cycles
a = Now()
WScript.Sleep 1000
WSHShell.Run "MXStandardE.exe"
WScript.Sleep 1000
WSHShell.AppActivate "MXStandardE.exe"
WScript.Sleep 1000
WSHShell.SendKeys "%A"
WScript.Sleep 1000
WSHShell.SendKeys "{DOWN}"
WScript.Sleep 1000
WSHShell.SendKeys "{ENTER}"
I = I + 1
MyFile.Writeline I & " of " & cycles & " at " & a & " --time of each cycle is
" & n & " minutes"
WScript.Sleep sl 'when sl is used loop time is in minutes
Loop
MyFile.Close
MsgBox ("Script has completed")
As Ansgar already said, it's pretty obvious that nothing will work while the PC sleeps or hibernates. In the case where the PC is locked, techniques that rely on window management or direct input such as SendKeys won't work as expected, because the user's session, along with user-level applications, is essentially shelved to make way for the login screen or another user.
You might want to do some research into the SendMessage/PostMessage API, or you can stop using VBScript and replace it with a Scheduled Task or system service that runs using a local service account, assuming you just want to execute an exe without any UI interaction.
The question is: do you need to go under hibernation or pc suspension? If not, you should simply configure or turn off those settings. By only locking the session, the vbscript should be run and generate an outpout without any trouble. By checking and configuring advanced windows energy settings it might help you solving this.

Open multiple .vbs one by one

i want .vbs script, to open multiple large files .vbs [i want to Open .vbs one by one] that do not make me, lag in PC.
0001.vbs, 0002.vbs, 0003.vbs, 0004.vbs
is can be different names like:
Anna.vbs, Diana.vbs, Antony.vbs, Andy.vbs
Example:
run C:\0001.vbs
MsgBox "0001.vbs IS END"
Next Open run C:\0002.vbs
MsgBox YES NO
MsgBox "0002.vbs IS END"
Next Open run C:\0003.vbs
MsgBox YES NO
MsgBox "0003.vbs IS END"
Next Open run C:\0004.vbs
MsgBox YES NO
MsgBox "0004.vbs IS END"
Thank you for you help.
Set Shell = CreateObject("WScript.Shell")
For i = 1 To 4
strFile = Right("0000" & i, 4) & ".vbs"
If MsgBox("Would you like to run " & strFile & "?", vbYesNo Or vbQuestion) = vbYes Then
Shell.Run "c:\" & strFile, 1, True
MsgBox strFile & " IS END"
End If
Next
Just make sure you pass True as the last parameter to Shell.Run so that this script waits until the others are done before reporting that they've ended.
Edit: To answer your comment about using names, you can loop through an array created on-the-fly.
For Each strName In Array("Anna", "Diana", "Antony", "Andy")
Next
To not make you wait for each sub process/.vbs before you start the next, don't use the 3rd/wait/true parameter to the .Run method:
a.vbs
Option Explicit
Dim oWSH : Set oWSH = CreateObject("WScript.Shell")
Dim v
For v = 0 To 1
oWSH.Run "cscript.exe " & v & ".vbs", 0, False
Next
MsgBox WScript.ScriptName & " done. " & Now()
0.vbs, 1.vbs
Option Explicit
Randomize
WScript.Sleep Rnd() * 1000
MsgBox WScript.ScriptName & " done. " & Now()
Evidence:
As you can see, a.vbs is finished first and 0.vbs and 1.vbs terminate in random/not in call order.
We have
0001.vbs, 0002.vbs, 0003.vbs, 0004.vbs
Assuming that you have this script file with the after mentioned files in the same directory.
If not, just modify the full path of your vbs files you want to run.
Instead of
WshShell.Run ".\0001.vbs"
You use for example:
WshShell.Run "c:\indel\0001.vbs"
This is the script:
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run ".\0001.vbs"
WshShell.Run ".\0002.vbs"
WshShell.Run ".\0003.vbs"
WshShell.Run ".\0004.vbs"
What you need to do is make this code
do
msgbox("haha you cant close this")
CreateObject ("WScript.Shell").Run(".\Duplicate.vbs")
loop

Run script in background

I want to run following script as scheduled task on Windows 7 in background. Now, script displays cmd window and, can I run script without visible cmd window?
Option Explicit
Dim WshShell, oExec
Dim RegexParse
Dim hasError : hasError = 0
Set WshShell = WScript.CreateObject("WScript.Shell")
Set RegexParse = New RegExp
Set oExec = WshShell.Exec("%comspec% /c echo list volume | diskpart.exe")
RegexParse.Pattern = "\s\s(Volume\s\d)\s+([A-Z])\s+(.*)\s\s(NTFS|FAT)\s+(Mirror|RAID-5)\s+(\d+)\s+(..)\s\s([A-Za-z]*\s?[A-Za-z]*)(\s\s)*.*"
While Not oExec.StdOut.AtEndOfStream
Dim regexMatches
Dim Volume, Drive, Description, Redundancy, RaidStatus
Dim CurrentLine : CurrentLine = oExec.StdOut.ReadLine
Set regexMatches = RegexParse.Execute(CurrentLine)
If (regexMatches.Count > 0) Then
Dim match
Set match = regexMatches(0)
If match.SubMatches.Count >= 8 Then
Volume = match.SubMatches(0)
Drive = match.SubMatches(1)
Description = Trim(match.SubMatches(2))
Redundancy = match.SubMatches(4)
RaidStatus = Trim(match.SubMatches(7))
End If
If RaidStatus <> "Healthy" Then
hasError = 1
'WScript.StdOut.Write "WARNING "
MsgBox "Status of " & Redundancy & " " & Drive & ": (" & Description & ") is """ & RaidStatus & """", 16, "RAID error"
End If
End If
Wend
WScript.Quit(hasError)
Thanks a lot
Option 1 - If the task is running under your user credentials (if not, msgbox will not be visible)
There are two possible sources for the cmd window.
a) The script itself. If the task is executing cscript, the console window will be visible, avoid it calling wscript instead
b) The Shell.exec call. The only way to hide this window is to start the calling script hidden. On start of your script test for the presence of certain argument. If not present, make the script call itself with the argument, using Run method of the WshShell object, and indicating to run the script with hidden window. Second instance of the script will start with the special parameter, so it will run, but this time windows will be hidden.
Option 2 - Running the task under system credentials.
In this case, no window will be visible. All will be running in a separate session. BUT msgbox will not be seen. Change MsgBox call with a call to msg.exe and send a message to current console user.

For each loop syntax error

There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor
Hey I wrote this script delete shares of a computer but when I run my script it repeats the same wscript.echo statating the share being deleted. Why does my code never end when run How do I fix that.
My fumction:
'The function that is called to run the command Line that deletes a specific share from a pc
Function DeleteThisShare(Share)
Dim objShell
'Logging The deleted Approved Shares
objDeletedFile.WriteLine (Now & " - Removed share " & Trim(Share))
DeleteThisShare = "net share " & chr(34) & Share & chr(34) &" /DELETE"
Wscript.echo DeleteThisShare
Set objShell = CreateObject("Wscript.Shell")
objShell.Run DeleteThisShare
End Function
My loops:
'Compares The UnApproved Shares to the Current Shares
For Each objItem In colItems
Dim StrNonUnapprovedShares, Item
StrCurrentShares = objItem.name
if instr(AdminShares,lcase(objitem.name)) > 0 or mid(objitem.name,2,1) = "$" or left(lcase(objitem.name),10) = "pkgsvrhost" then
'Skipping known admin share
Else
For each Item in arrUnApprovedLines
If Lcase(Item) = Lcase(strCurrentShares) Then
StrNonUnapprovedShares = (StrNonUnapprovedShares & strCurrentShares & vbCrLf)
End If
Next
End If
Next
Dim notUnapprovedShares, notUnapprovedLines
notUnapprovedLines = StrNonUnapprovedShares
notUnapprovedLines = Split(notUnapprovedLines, vbCrLf)
Dim y, Line2
For y = 0 to uBound(notUnapprovedLines)
Line2 = Trim(notUnapprovedLines(y))
If len(Line2) > 0 Then
DeleteThisShare(Line2)
End If
Next
I think the problem is caused by using the function name as a variable. That's okay with VB that you're compiling, but I don't think VBScript recognizes it in the same way. Use a separate variable name in place of DeleteThisShare, e.g. strDeleteThisShare.
If I had to guess it's because you're creating a recursive loop by having your script echo the DeleteThisShare function. The function gets to that line and is called again before it's able to carry on.
Try to only assign values to the result of the function and use local variables to store any other debugging / temporary values.

Resources