How to launch HTA from VBScript - vbscript

HTA calls external VBScript and after that it turns into suspend mode. At this point control is transferred to the VBScript. As a result of VBScript code execution it may happen that the machine would be rebooted. After the reboot HTA starts automatically and stays suspended; while the VBScript continues to work (let's assume they both start from Startup). Upon completion of VBScrip work I'd like control to be transferred back to the HTA and a HTA subroutine to be executed. Let's say this subroutine is Window_OnLoad. How can I do this? Is there an instruction to open HTA and after that execute a sub? If I launch to HTA from VBScript with Run method (or ShellExecute) I get only HTA window (you remember that HTA is still suspended) but my goal is to wake up HTA and make it running.
Some additional details
I didn't want to publish the code here as this is general question and the code might give more confusion... Primary task of this HTML Application is giving administrator of workgroup/domain a very smooth way for customization of just installed Windows 7 (change computer name, join to domain, set local computer description, set domain computer description, regional settings, etc.). HTA offers also opportunity to choose what steps to be done - this is realized as a list of checkboxes; so that administrator can change computer name but do not include computer into the domain and set up power settings for instance. Some steps requires computer reboot; but some steps are okay to pass control to the next step without reboot. Here is a general idea: I have HTA that allows user to enter some data; also there is XML file. XML is used to keep not only user data but also some instructions for steps to be done; e.g. for user data XML contains
<computername/>
<PCdescription/>
<DomainName/>
<OUName/>
whilst the step is described in this manner:
<step>
<description>Include PC into Domain<description/>
<filetorun>/scripts/domain.vbs</filetorun>
<arguments></arguments>
<completion>reboot</completion>
</step>
Here description is the step name which is shown in HTA window, filetorun gives the VBScript (or batch file) to be executed to complete the step, arguments are compiled from the user data and saved to XML, and complete shows whether reboot is required after the step is completed.
VBScript is executed by these instructions:
strFile = oNode.SelectSingleNode("filetorun").Text
strArgs = oNode.SelectSingleNode("arguments").Text
stringtorun = strFile & " " & strArgs
result = Createobject("WScript.Shell").Run(stringtorun,,true)
where oNode is XML node for the current step.
All instructions are nested to the HTA like this
<html>
<head>
'...........
<HTA:APPLICATION
APPLICATIONNAME="MyHTMLapplication"
VERSION="1.0"/>
'...............
</head>
<script language="VBScript">
Sub Window_OnLoad
'......................
' Populate form, save XML, other operations
'......................
'--------------execute step command---------------
strFile = oNode.SelectSingleNode("filetorun").Text
strArgs = oNode.SelectSingleNode("arguments").Text
stringtorun = strFile & " " & strArgs
result = oShell.Run(stringtorun,,true)
'-------------------------------------------------
If Reboot_is_not_required Then
'computer restart not required, proceeding with the next step...
Window_OnLoad
End If
End Sub
</script>
<body>
........................
</body>
</html>
Up to the present day completion was allowed to take two values: Reboot and NoReboot. The latter parameter causes recurrent call of Window_OnLoad when current step is completed and we are about to make next step.
Now there is a need to introduce parameter Delay. I'm going to use this parameter for such external scripts that require system reboot without passing control back to HTA.
HTA starts automatically after system reboot. So, if the current step is marked as Delay then HTA will only populate the forms. I want that external script which executes the current step in such model, would somehow pass control back to HTA. But this is not enough because at this stage HTA work is suspended. To wake HTA up and force to perform next step I need to call a subroutine. How to do this from VBScript?
Do not be too hard on me. This is my first steps in programming.
Thank you in advance.

Related

automatically logging in to SAP as part of a VBscript

I am working in SAP (PR2) and I have a large report that usually takes a long time (2 or more hours) to run. I have to take the output of this report and drop it into Excel to be manipulated and cleansed before bringing it into Access.
The ideal result would be a script that could launch automatically around 4am, login in to SAP, run the report, and have the results waiting for me when I come in. In short, I am missing parts 1 and 2, the automatic launch and automatic login to SAP.
I have pulled together a script that will start the report and then output the results as I want. The downside of this is that I don't get the results until about noon-ish each day, and that interrupts the workflow of those whom I support.
I have tried to run the necessary report in the background as suggested in other questions, but due to the size of the report and my limited access inside of SAP, it comes out in a way that is completely useless to me.
Thanks in advance for your help. Also, thanks for the help ya'll have given on prior questions :)
PS:As a bonus, if anyone knows how to encrypt a VBscript, that would be helpful as well.
Use the windows task scheduler to set a run daily at time task.
VBS cannot be encrypted but can be encoded. This will only stop the casual person fiddling with the code, decoding scripts are available online for anyone who really wants to get your code.
'ENCODE VBS TO VBE
Set oFilesToEncode = WScript.Arguments
Set oEncoder = CreateObject("Scripting.Encoder")
For i = 0 To oFilesToEncode.Count - 1
file = oFilesToEncode(i)
Set oFile = fso.GetFile(file)
Set oStream = oFile.OpenAsTextStream(1)
sSourceFile = oStream.ReadAll
oStream.Close
sDest = Encoder.EncodeScriptFile(".vbs",sSourceFile,0,"")
sFileOut = Left(file, Len(file) - 3) & "vbe"
Set oEncFile = fso.CreateTextFile(sFileOut)
oEncFile.Write sDest
oEncFile.Close
Next
WScript.quit
I use a software 'exescript' to convert to exe. Seems to work OK for me...

Share Excel.Application executable among multiple WSF processes?

I have a system that launches 50 or so VBS scripts via WSF, that need to stay there until another part of the system connects to them, then they act as servers for a bit until the peer disconnects, then they exit and get restarted.
For initialization purposes, they all use an EXCEL.EXE to read a large number of parameters from a spreadsheet, via
Set objExcel = CreateObject("Excel.Application")
We can't afford to have 50 EXCEL.EXEs running at once, so the restarts are sequentialized, so that there should never be more than one EXCEL.EXE running: usually zero, as they are only used for 15-20 seconds and then released.
However sometimes things go wrong, the WSF scripts exit, and the EXCEL.EXE that it starts stays there. So we do see up to a dozen EXCEL.EXE processes.
My question is about using GetObject() instead of CreateObject(). Would it be possible to use GetObject() so that if there already was an EXCEL.EXE running, it would use that one instead of starting a new one? And if so what other steps are necessary?
There is also a supplementary question here about why the EXCEL.EXEs persist after the VBS that started them has exited, but I can imagine ways in which the VBS could exit (or be killed) that would allow that.
Note that the question is also partly about the re-entrancy of EXCEL.EXE, which I have no information about.
I'm not the author of these scripts, and I'm not very strong in VBS as far as external objects go, so it is is entirely possible that I'm asking a trivial question here.
Usage of GetObject() is documented in this old KB article. Error handling is required to get the first instance created. Like this:
Dim excel
On Error Resume Next
Set excel = GetObject(, "Excel.Application")
If Err.number = 429 Then
Set excel = CreateObject("Excel.Application")
End If
If Err.number <> 0 Then
WScript.Echo "Could not start Excel: " & err.Description
End
End If
'' etc
However, seeing zombie Excel.exe processes surviving is a broad concern, it strongly suggests that the scripting runtime is not exiting normally. Perhaps error handling in your existing scripts is less than ideal, that's not likely to get better when you slam a single instance with multiple scripts. Excel does get pretty cranky when it cannot keep up. Using the OpenXML api or Excel Services are the better way to go about it.

How do I open multiple message boxes in vbs?

I know that if you input
Do
msgbox("This is a msg box")
loop
Then a msg box pops up that won't go away.
I want multiple message boxes that you ARE able to close.
How do I do this?
You want to look for non-modal dialogs. The msgbox that you pop-up here are modal, that's why they come one after the other (execution is suspended while the dialog is open).
You will find references for this on the web.
Func _NoHaltMsgBox($code=0, $title = "",$text = "" ,$timeout = 0)
Run (#AutoItExe & ' /AutoIt3ExecuteLine "MsgBox(' & $code & ', '''& $title & ''', '''& $text &''',' & $timeout & ')"')
EndFunc
WARNING: You're probably going to encounter severe lag and or crashing. I am not held responsible of any damages if you choose to continue.
You can make a batch file that opens the same VBS script many times.
Make a notepad with:
msgbox("YourTextHere")
Or if you want to loop it:
do
msgbox("YourTextHere")
loop
Replace YourTextHere with whatever you want.
Then save it as .vbs
then make another notepad:
start "MessageBox" "MessageBox.vbs"
Change "MessageBox" with the name of the message box VBS you made.
Copy and paste the same script multiple times to open it more times (Do this at your own risk, you may encounter severe lag).
Then save it as .bat
Or add the batch file itself multiple times so it can create a loop of opening batch files which can open more scripts out of them. (Do this at your own risk, you may encounter severe lag).
For example:
start "BatchFile" "Batchfile.bat"
Change "BatchFile" with the name of the Batchfile you made.
Copy and paste it multiple times to open it more times again (Do this at your own risk, you may encounter severe lag).
So far, you're okay since you did not open the .bat file. IF you try testing it, It'll open multiple instances of your .bat file and the message box, then open more instances off the new instances, then more instances off the even newer instances, and repeat enough to make your PC crash or lag.
If you don't want to use a batch file, try this:
Step 1 - the error message
Let's say you wanted a=msgbox("messageboxtext"). So, in Notepad, you would write a=msgbox("messageboxtext") and save it as a .vbs file.
Step 2 - the spammer
Infinitely
In a new Notepad document, paste this:
set shell = createobject("wscript.shell")
count = "hello world"
do until count = 1
shell.run("""C:\Users\user\Documents\error.vbs""")
loop
Replace C:\Users\user\Documents\error.vbs with the location of the file. Save it as a .vbs file.
Finitely
To open a finite number of windows, use this code:
set shell = createobject("wscript.shell")
count = 0
do until count = 5
shell.run("""C:\Users\user\Documents\error.vbs""")
loop
Replace the 5 with the number of times you would like the message to spawn. Enjoy!
You need a multiple button MsgBox, set it as a value then: if CANCEL is pressed, the process will stop.
Do
spam=MsgBox("SPAM",3)
If spam = 2 Then
WScript.Quit
End If
Loop
First make an File called "anything.vbs" replace anything with anything you want.
Then Edit it and Put in the Code
msgbox("LOL")
loop"
Replace LOL with anything you Like.
Then make a .bat File.
Put in the Code
start "LOL.bat"
loop"
Now you have a Spammer. :)

VBScript onTimeout then function

I have a VBScript I am working on that uses another object.
Sometimes that Object will get stuck. My VBScript code will hang on that line until it's "done". When it times out, I want to send the .Close command to the Object before the VBScript closes.
How can I tell when my VBScript times out?
I know that I can put WScript.Timeout = 60
Maybe something like..
WScript.Timeout = 5
do while true
loop
sub WScript_timeout()
msgbox("OK")
end sub
By setting the Timeout property you instruct the interpreter to automatically terminate the script when the timer expires. This is the same as running the interpreter with the option //T:xx and can't be caught/handled from within the script. What you want requires the ability to run code asynchronously, and VBScript doesn't really support that.
The real answer (to the question "How can I tell when my VBScript times out?") is that you can't. In common with almost all scripts, if VBScript stops running (because it's timed-out) the running thread ceases to run, so it can't report its status.
But there is a solution. However, it requires some cunning.
If you run a batch script instead, wherever you use that script to launch a new batch script (e.g. batch_1.bat includes this line: CALL batch_2.bat), the 2nd script will run, but the 1st script will wait.
Processing of the 1st script sits and waits (at the CALL) until script 2 stops running: at that point, control is returned to script 1, which continues with any code following the CALL, code which might be used to report the fact that script 2 has ended -
CALL batch_2.bat
ECHO The batch_2.bat script has stopped running && cmd /k
There are ways of launching batch_2.bat without causing batch_1.bat to pause until the 2nd script has finished, but they are not relevent here.
Theoretically, a batch script doesn't support parallel processing. VBScript certainly doesn't either. But the foregoing technique shows one method whereby parallel processing can be achieved, after a fashion, in a batch script -- which makes it one-up on vbScript!
.
One way to be certain that vbScript will time out, if the script hangs, so that the script must either complete successfully or fail (so you are never left with a frozen script due to it "hanging"), is to use a WScript function in your .vbs file and set the Windows Script Host settings to time out after (say) 30 seconds -
A. Open the "Windows Script Host Settings" dialog box:
Go to: Start > Run
In the "Open" box, type: WSCRIPT
Click "OK".
B. Set a timeout, to occur whenever WSH runs:
Select the option: "Stop script after specified
number of seconds".
In the "seconds" box, type the time limit to be
applied to all scripts (default is 10 seconds).
.
Here's a function to find and show what the current WSH/WScript timeout setting is (and if it shows that this setting hasn't been set yet, set it) -
WScript.Echo("WSH timeout: " + WScript.Timeout);
.
The option //T:xx can't be used, because it's a CScript function, which doesn't work in WScript, so can't be used in a .vbs vbScript file.
.

HTA - VBScript - Install program but wait for installation to complete

If you could give my a hand that would be great?
I have a HTA file nothing to fancy its to install a few programs one by one
I have been reading in a few places on how to wait for installation to complete
then install the next program but none make sense to me for what i want, also
they are saying to use wscript.sleep that would be great but it doesnt work in a HTA right ?
I have firefox, utorrent, symantec antivirus, adobe reader, office 2003 (packaged with KEY already)
and a few others.
i want to find switches to install silently but thats not important if this code someone is willing to show me works...
I hope I make sense ?
If you can help me it would be great ?
Cheers Pavle.
You might find something useful in my answer (https://stackoverflow.com/a/3742182/128427) to this question: How to get an HTA to restart itself?
It uses a VBScript helper to wait for a process to end (the HTA itself) then restarts the HTA. You could modify the vbscript instead to wait for a specific process to end (one of your installers), then return control to the HTA which starts the next installer and calls the wait script again.
I don't think an HTA can call the WScript.Sleep routine, but there are the setTimeout and setInterval methods in HTA that call a routine after X seconds, or repeatedly call a routine after every X seconds until cancelled. You can use these to check periodically if a process is still running (using WMI Win32_Process as I show in my other answer).
To process a list of items like this, instead of using a loop to go through a list and pause after each item, you have a central state-machine routine that calls itself every so often to advance the system.
'!! extremely "pseudo" pseudo-code follows
sub StartSystem()
state = "next program"
list = list of programs to install
AdvanceSystem()
end sub
sub AdvanceSystem()
if state = "next program"
if more items in list
start next installer
remove from list (or increment an index)
set state to "check program"
else
set state to "done"
if state = "check program"
use WMI to see if process is still running
if no
state = "next program"
if state <> "done"
setInterval(AdvanceSystem, 5000) ' call again in 5 seconds
end sub
' then somewhere in your HTA interface have a button to start things off
buttonClick = StartSystem()
Using an arrangement like this you may not even need to run a separate VBScript to check the process and sleep. Also, with this kind of incremental process, you can send output to a DIV somewhere so the user can see progress, whereas when processing things in a loop, output doesn't show up until the whole process has finished. After each pass through AdvanceSystem, the control returns to the HTA level and the system can update itself.
Let me know if you need a more specific example, I'll try to write something up.

Resources