Launching batch file from within HTA - windows

I'm trying to launch a batch file from within a HTA file. The launching of the batch file appears to start properly (or at least the associated CMD prompt), but the batch closes moments later, when it should take approximately 5 minutes. During the brief moment the CMD process is running, HTA window appears to pause, then closes as soon as the CMD process ends. Everything else about the HTA functions properly.
The goal is to have the HTA launch the batch file in the background (hidden) and while the batch file is processing, have no affect on the HTA. Once the batch file has completed and exited, the HTA will launch a new HTA with information for the user.
Here's the HTA I have that is not functioning properly...
<html>
<head>
<style>
body { background:#fff url('../_dependencies/welcome.jpg') no-repeat center center fixed; color:#000; margin:25px; padding:0; }
div#gap { height:306px; }
div#buttons { padding-right:12px; position:absolute; right:0; }
</style>
<title>Installer</title>
<script language="vbscript">
Sub Window_OnLoad
Set Shell = CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
sPath = Shell.ExpandEnvironmentStrings("%curdir%")
Continue = Chr(34) & sPath & "_install.cmd" & Chr(34)
Shell.Run Continue,0,True
CompName = Shell.ExpandEnvironmentStrings("%computername%")
Const ForAppending = 8
textFile = sPath & "_Logs\" & CompName & ".upgraded.txt"
If Not objFSO.FileExists(textFile) Then
Set objTextFile = objFSO.CreateTextFile(textFile, True)
objTextFile.Close
End If
Set objTextFile = objFSO.opentextfile(textFile,ForAppending)
objTextFile.WriteLine("Upgrade complete on this computer." & vbCrLf & Now())
objTextFile.Close
Set textFile = Nothing
self.close()
End Sub
</script>
<script language="javascript">
window.resizeTo(620,365);
window.moveTo((screen.width-620)/2,(screen.height-365)/2);
</script>
<hta:application applicationname="Installer" border="none" caption="no" id="objnotitlebar" innerborder="no" maximizebutton="no" minimizebutton="no" scroll="no" showintaskbar="no" singleinstance="yes" systemmenu="no">
</head>
<body>
<div id="gap"><img src="../_dependencies/waiting.gif" /></div>
<div id="buttons"></div>
</body>
</html>

Windows doesn't provide an environment variable %curdir%. Its expansion produces a literal string %curdir%, so the Command Prompt probably closes immediatly because a file %curdir%_install.cmd cannot be found. Did you perhaps mean %cd%? That variable is only available within CMD.
And do you actually want to run the script from the current working directory in the first place? I'd say it's more likely that you mean to run the batch file from the same directory as the HTA. That location can be determined like this:
dir = objFSO.GetParentFolderName(Replace(document.location.href, "file:///", ""))
sPath = objFSO.GetFolder(dir).Path
If that doesn't help change the line
Shell.Run Continue,0,True
into this:
Shell.Run "%COMSPEC% /k " & Continue, 1, True
Running a batch script with cmd /k keeps the Command Prompt open after the (attempted) script execution, so you can see if there were any errors.

So, after a bit of troubleshooting, the issue in the batch script was a misconfigured start statement.
The start statement was this:
#start /b /min /wait "upgradeinstaller.exe" /silent /noreboot
I changed it to this:
#start /b /min /wait "Upgrade Installer" "upgradeinstaller.exe" /silent /noreboot
I apparently needed to add the title to the start command, otherwise the start command thought the first quoted text was the title, then the switches were applied to start, which doesn't work.

Related

Use WScript.Sleep() or replacement in mshta.exe one-liner

I want to use WScript.Sleep() function with a mshta.exe one-liner from a batch (I don't want to write temporary files) but I receive a WScript undefined error.
As stated in this answer:
WScript is an object provided by the W|CScript.exe hosts; IExplorer or
MSHTA don't provide it (see here).
In Sleep routine for HTA scripts:
Stephen Quan's answer
uses window.setTimeOut and window.ResizeTo which just threw
errors (but maybe there is a way to do it that I don't find).
uk2015's is VBScript.
iRon's: error in
character 5 ';' expected; also, the select has single quotes (in
mshta, the parameter is double-quoted and you can use single quotes
inside, but this is third level of quotification, so to speak. Furthermore, you need admin rights.
TorATB's: uses a ping! Same problem with quotes too.
I don't know how to make a single answer of these work or if possible.
Inside a .js run by c/wscript it works perfectly. Is there a replacement or a way to reference this function for mshta.exe?
Example:
Save the following code as .js and run it.
new ActiveXObject('Internet.HHCtrl').TextPopup('Warning message', 'Tahoma, 16, , BOLD', 8, 4, 0x0000FF, 0x00FFFF );WScript.Sleep(5000);
But, as I said, I want to run it from a batch without any temporary .js (or .vbs). Try running this code from a Command Prompt:
mshta "javascript:new ActiveXObject('Internet.HHCtrl').TextPopup('Warning message', 'Tahoma, 16, , BOLD', 8, 4, 0x0000FF, 0x00FFFF );close()"
The text popup opens and closes immediately but you can manage to see it sometimes. How do you manage to hold the text during a given amount of time when you run this code using mshta?
Here is a complete example showing you how to make a sleep with a HTA
<html>
<head>
<HTA:APPLICATION
APPLICATIONNAME="Volume + - ON/OFF"
BORDER="THIN"
BORDERSTYLE="NORMAL"
ICON="SndVol.exe"
INNERBORDER="NO"
MAXIMIZEBUTTON="NO"
MINIMIZEBUTTON="NO"
SCROLL="NO"
SELECTION="NO"
SINGLEINSTANCE="YES"/>
<title>Volume + - ON/OFF </title>
<script language="vbscript">
'************************************************************************************
Sub window_onload()
CenterWindow 250,150
End Sub
'************************************************************************************
Sub Sleep(MSecs)' Function to pause because wscript.sleep does not work with HTA
Set fso = CreateObject("Scripting.FileSystemObject")
Dim tempFolder : Set tempFolder = fso.GetSpecialFolder(2)
Dim tempName : tempName = "Sleeper.vbs"
If Not Fso.FileExists(tempFolder&"\"&tempName) Then
Set objOutputFile = fso.CreateTextFile(tempFolder&"\"&tempName, True)
objOutputFile.Write "wscript.sleep WScript.Arguments(0)"
objOutputFile.Close
End If
CreateObject("WScript.Shell").Run tempFolder&"\"&tempName &" "& MSecs,1,True
End Sub
'************************************************************************************
Sub Volume(Param)
set oShell = CreateObject("WScript.Shell")
Select Case Param
Case "MAX"
oShell.run "%SystemRoot%\System32\SndVol.exe" 'Runs The Master Volume App.
Sleep 2000 'Waits For The Program To Open
oShell.SendKeys("{HOME}")' volume maximum 100%
Sleep 100
oShell.SendKeys"%{F4}" ' ALT + F4
Case "MIN"
oShell.run "%SystemRoot%\System32\SndVol.exe" 'Runs The Master Volume App.
Sleep 2000 'Waits For The Program To Open
oShell.SendKeys("{END}") 'volume minimum 0%
Sleep 1000
oShell.SendKeys"%{F4}" ' ALT + F4
Case "UP"
oShell.run "%SystemRoot%\System32\SndVol.exe" 'Runs The Master Volume App.
Sleep 2000 'Waits For The Program To Open
oShell.SendKeys("{PGUP}") 'volume +20%
Sleep 1000
oShell.SendKeys"%{F4}" ' ALT + F4
Case "DOWN"
oShell.run "%SystemRoot%\System32\SndVol.exe" 'Runs The Master Volume App.
Sleep 2000 'Waits For The Program To Open
oShell.SendKeys("{PGDN}") 'Turns Up The Volume 20, If It Is Muted Then It Will Unmute It
Sleep 1000
oShell.SendKeys"%{F4}" ' ALT + F4
Case "MUTE"
oShell.run "%SystemRoot%\System32\SndVol.exe" 'Runs The Master Volume App.
Sleep 1000 'Waits For The Program To Open
oShell.SendKeys(" " & chr(173)) 'permet de couper/remettre le son (bascule)
Sleep 1000
oShell.SendKeys"%{F4}" ' ALT + F4
End select
End Sub
'*************************************************************************************
Sub CenterWindow(x,y)
Dim iLeft,itop
window.resizeTo x,y
iLeft = window.screen.availWidth/2 - x/2
itop = window.screen.availHeight/2 - y/2
window.moveTo ileft,itop
End Sub
'************************************************************************************
</script>
</head>
<body>
<center>
<BUTTON style="background: Red; color: white;" onClick="Call Volume('MAX')" style="WIDTH: 85px; HEIGHT: 30px">Volume MAX</BUTTON>
<BUTTON style="background: Blue; color: white;" onClick="Call Volume('MIN')" style="WIDTH: 85px; HEIGHT: 30px">Volume MIN</BUTTON>
<BUTTON style="background: Green; color: white;" onClick="Call Volume('UP')" style="WIDTH: 85px; HEIGHT: 30px">Volume +20%</BUTTON>
<BUTTON style="background: Orange; color: white;" onClick="Call Volume('DOWN')" style="WIDTH: 85px; HEIGHT: 30px">Volume -20%</BUTTON>
<BUTTON style="background: DarkOrange; color: white;" onClick="Call Volume('MUTE')" style="WIDTH: 85px; HEIGHT: 30px">ON/OFF</BUTTON>
</center>
</body>
</html>
Based on your edit question, you can do something like this with a batch file :
#echo off
Title Execute a .JS and .VBS file in a batch script
echo Hello World !
Set "JS_Warning=%Temp%\Warning.js"
Set "VBS_Msg=%Temp%\Msg.vbs"
REM Create a .js temporary file
echo new ActiveXObject('Internet.HHCtrl'^).TextPopup('Warning message', 'Tahoma, 16, , BOLD', 8, 4, 0x0000FF, 0x00FFFF ^);WScript.Sleep(5000^);>"%JS_Warning%"
REM Create a .vbs temporary file
echo CreateObject("Internet.HHCtrl"^).TextPopup "Hello !" ^& vbCrLf ^& "How are you ?", "Verdana,8", 6, 6, 6, 6 : WScript.Sleep 5000>"%VBS_Msg%"
REM We execute the .js file
Wscript "%JS_Warning%"
REM We execute the .vbs file
Wscript "%VBS_Msg%"
Sub Sleep(lngDelay)
CreateObject("WScript.Shell").Run "Timeout /T " & lngDelay & " /nobreak", 0, True
End Sub
Sleep 1
Try WMI event notification query.
The following query example shows you how to generate events every second forever.
SELECT * FROM __InstanceModificationEvent WHERE TargetInstance ISA "Win32_LocalTime"
You could use SWbemServices.ExecNotificationQuery method to subscribe to events.
<html>
<head>
<title>Sleep</title>
<HTA:APPLICATION>
</head>
<body>
<script language="javascript">
window.resizeTo(640, 480);
var CIMv2 = GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\CIMv2")
function sleep(count) {
var event_gen = CIMv2.ExecNotificationQuery("SELECT * FROM __InstanceModificationEvent WHERE TargetInstance ISA \"Win32_LocalTime\"")
for(var i = 0; i < count; i++) {
event_gen.NextEvent();
}
}
for(var i=0; i<3; i++) {
sleep(3)
alert("3 seconds passed")
}
document.write("<h1>Goodbye</h1>");
</script>
</body>

Updating Text Area with Status in HTA [duplicate]

In several of my .HTA scripts that I created, I had the need for the VBScript WScript.Sleep command which simply waits for a number of milliseconds without utilizing the CPU.
And when I browse the web, it appears that I am not the only one looking for this:
https://www.google.nl/search?q=hta+sleep
(I bet that if you read this, you probably need(ed) this as well)
The best solution that I could find appears to be the one which uses the PING command.
But especially for a situation were just need to pause the script for a few 100ms, this solution is quiet odd as it uses an external command and triggers all kind of (network) processes that unlikely have anything to do with the concerned .HTA script.
So the first thing that came to my mind was to use the WMI Win32_PingStatus class to avoid the external command but then I started to question why not completely basing it on WMI.
It has taken me several hours to get the right WMI classes and methods in place, but finally I succeeded…
When writing HTA's you should be thinking asynchronously. Consider rewriting your code to use window.setTimeout. In the following example, I will use window.setTimeout to make a bell sound every 2 seconds:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=8">
<title>Bell Test</title>
<script language="VBScript">
Option Explicit
Dim objWShell
Set objWShell = CreateObject("WScript.Shell")
Sub DoPing
divText.innerText = Now
objWShell.Run "%COMSPEC% /c ECHO " & Chr(7), 0, False
window.setTimeOut "DoPing", 2000
End Sub
Sub window_OnLoad
window.ResizeTo 240,130
DoPing
End Sub
</script>
</head>
<body>
<div id="divText">TEST</div>
</body>
</html>
I had the same problem with HTA.
My solution with vbs ...
Sub sleep (Timesec)
Set objwsh = CreateObject("WScript.Shell")
objwsh.Run "Timeout /T " & Timesec & " /nobreak" ,0 ,true
Set objwsh = Nothing
End Sub
' example wait for 3 seconds
sleep 3
The routine will call a shell command, minimized and without a keyboard command.
Only ^C is permitted, but this will no user given in these situation.
Sub Sleep(iMilliSeconds)
With GetObject("winmgmts:\\.\root\cimv2")
With .Get("__IntervalTimerInstruction").SpawnInstance_()
.TimerId = "Sleep"
.IntervalBetweenEvents = iMilliSeconds
.Put_()
End With
.ExecNotificationQuery("SELECT * FROM __TimerEvent WHERE TimerId='Sleep'").NextEvent
End With
End Sub
Added 2015-02-11:
Unfortunately, this function doesn’t work when using Internet Explorer 10 (see comments below).
With Internet Explorer 11 installed, it appears to work if you run the HTA as administrator.
Wait(2000) 'pauses 2 seconds
Sub Wait(Time)
Dim wmiQuery, objWMIService, objPing, objStatus
wmiQuery = "Select * From Win32_PingStatus Where Address = '1.1.1.1' AND Timeout = " & Time
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set objPing = objWMIService.ExecQuery(wmiQuery)
For Each objStatus in objPing
Next
End Sub
Sub Sleep (ms)
Set fso = CreateObject("Scripting.FileSystemObject")
Dim sFilePath: sFilePath = fso.GetSpecialFolder(2) & "\WScriptSleeper.vbs"
If Not fso.FileExists(sFilePath) Then
Set oFile = fso.CreateTextFile(sFilePath, True)
oFile.Write "wscript.sleep WScript.Arguments(0)"
oFile.Close
End If
Dim oShell: Set oShell = CreateObject("WScript.Shell")
oShell.Run sFilePath & " " & ms, 1, True
End Sub

Giant image covering desktop? (Batch File)

Is it possible to have an image that covers the entire desktop?
Now when I say desktop, I am referring to the whole entire computer screen, not the background. It would stay on their screen for an amount of time before disappearing. Here is the image I want to be covered on the screen, click here.
Thanks!
This solution is based from #npocmaka
Just give a shout and tell me the result :
Prank.bat
<!-- :
#echo off
mshta.exe "%~f0" %*
exit /b
rem
-->
<html>
<hta:application id="oHTA"
<HTA:APPLICATION
BORDER="none"
INNERBORDER="no"
CAPTION="no"
SYSMENU="no"
MAXIMIZEBUTTON="no"
MINIMIZEBUTTON="no"
ICON="NO"
SCROLL="No"
SCROLLFLAT="yes"
SINGLEINSTANCE="yes"
WINDOWSTATE="maximize"
SHOWINTASKBAR="no"
CONTEXTMENU="no"
SELECTION="no"/>
<head>
<style>
body {
color:black;
background-color:black;
background-image:url(http://i.imgur.com/idG7OEJ.png);
background-position:center center;
}
</style>
</head>
<script language="VBScript">
Sub Window_OnLoad()
Call Kill("explorer.exe")
idTimer = window.setTimeout("vbscript:ExecuteMyScript()",5000)
end sub
'****************************************************
Sub ExecuteMyScript()
window.close
Call RunExplorer()
End Sub
'****************************************************
Sub Kill(Process)
Dim Ws,Command,Execution
Set Ws = CreateObject("Wscript.Shell")
Command = "cmd /c Taskkill /F /IM "& Process &""
Execution = Ws.Run(Command,0,True)
Set Ws = Nothing
End Sub
'****************************************************
Sub RunExplorer()
Dim Ws
Set Ws = CreateObject("Wscript.Shell")
ws.run "explorer.exe"
End Sub
'****************************************************
</script>
<body>
</body>
</html>
Here's an example. Decided to embed the picture as base64 string (you can encode a picture in base 64 and put in the source) . In this case it will close after 5 seconds but if you comment out this line idTimer = window.setTimeout("vbscript:window.close", 5000) it will stay until the mshta PID is killed. Though I don't know if it is possible to cover the taskbar too (with hta application.I know how to do it with .net/C# app).

HTA and VBS dynamic list and opening file in list

First off new here and programming in general. I am trying to build an hta that can load various vbs scripts from an outside folder to make it more modular. I am current getting stuck at trying to open the vbs from my dynamic list. How do I open the file in my dynamic list? And also how do I pass a variable to the file? This is what I currently have:
<html>
<head>
<title>My HTML application</title>
<HTA:APPLICATION
APPLICATIONNAME="My HTML application"
ID="MyHTMLapplication"
VERSION="1.0"/>
</head>
<script language="VBScript">
Sub Window_OnLoad
Dim FolderPath
'folder to be searched for files
Dim objFSO
Dim objFolder
Dim colFiles
Dim objFile
Dim objOption
FolderPath = "%PathToScripts%"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objFSO.GetFolder(FolderPath)
Set colFiles = objFolder.Files
For Each objFile in colFiles
Set objOption = Document.createElement("OPTION")
objOption.Text = objFile.Name
objOption.Value = objFile.Name
mylistbox.Add(objOption)
Next
End Sub
Sub RunProgram
Set objShell = CreateObject("Wscript.Shell")
objShell.Run objOption
End Sub
</script>
<body bgcolor="white">
<!--Add your controls here-->
<select name="mylistbox" size=10>
</select>
<input type="button" value="SingleSelect" onclick="RunProgram" name="RunScript">
<!--{{InsertControlsHere}}-Do not remove this line-->
</body>
</html>
Question 1: How do I open the file in my dynamic list?
First, you need to retrieve the selected value from your list. For single-selection lists, you can just query the Value property of the <select> element:
strFile = mylistbox.Value
Since nothing may be selected, it's always a good idea to test the result to make sure you got something:
If Len(strFile) > 0 Then
Also, it looks like you're just showing the file name in the list, not the file path, which is fine, but you'll need the full file path if you want to run the file later. So you have a couple of options, here. Option 1: Make FolderPath a global constant instead of a local variable so that you can access it from your RunProgram() routine. Option 2: Take advantage of the Value property of <option> elements to store the full path for each list item while still just displaying the file name. Here's how to do the latter:
Set objOption = Document.createElement("OPTION")
objOption.Text = objFile.Name
objOption.Value = objFile.Path ' Changed from objFile.Name to objFile.Path
mylistbox.Add(objOption)
Next
Now that you have the full path to your script, you can run it. This is what your RunProgram() routine could look like:
Sub RunProgram()
' Get the selected value. This will be a full file path.
strFile = mylistbox.Value
' Make sure something was selected.
If Len(strFile) > 0 Then
' Run the script file.
Set objShell = CreateObject("WScript.Shell")
objShell.Run Chr(34) & strFile & Chr(34)
End If
End Sub
Note: Chr(34) is used to add double quotes around the file name in case it contains spaces.
Question 2: How do I pass a variable to the file?
This is where things get a little trickier. Though you can run a VBScript directly using the Shell.Run command (as we did above), if you want to pass an argument to the script, you need to run it explicitly using one of the scripting engine executables.
objShell.Run "wscript.exe " & Chr(34) & strFile & Chr(34) & " " & Chr(34) & strParam & Chr(34)
Here, we're using wscript.exe (the "GUI" version of the Windows Scripting Host) to explicitly run our script file. We're surrounding our file with double quotes, as we did above. And, finally, we're adding a space to separate the "command" from the parameter. For completeness, we're also adding double quotes around the parameter in case it contains spaces as well.

Visual Basic Script - KeyPress Detection?

I want to terminate the program once the key F1 is pressed.
Not sure sure how to write the do while loop.
Any Ideas?
Set WshShell = WScript.CreateObject("WScript.Shell")
Do While {F1} is not pressed
'...
Loop
This isn't possible in plain VBScript, but you may be able to get it to work with an HTA:
<head>
<title>Test</title>
<HTA:APPLICATION ID="oHTA"
APPLICATIONNAME="Test"
>
</head>
<script language="VBScript">
Sub CheckKey
If window.event.keyCode = 112 Then self.close()
End Sub
</script>
<body onKeyUp="CheckKey">
...
</body>
I use a hybrid VBS script with a small C# program embedded in it using adodb.stream.
This example updates the clipboard with each step (e.g. for logins), but it can be easily modified to trigger other events.
You can remove the clean-up line, and the .exe can be placed in the temp directory.
For brevity the hex_ section has been truncated but the whole file is available at http://excelxll.com/VBS/keypress.txt
Dim wsh, exe, HexKeyCode
Set wsh = CreateObject("Wscript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")
HexKeyCode = "70" 'F1=70 F12=7B ALT-GR=A5 ESC=1B
exe = "Press F1 to step script until I disappear.exe"
if not fso.FileExists(exe) then call create_binary_file_
'EACH TIME F1 IS PRESSED UPDATE THE CLIPBOARD
'############################################
wsh.Run "cmd.exe /c """ & exe & """ " & HexKeyCode, 0, TRUE
wsh.Run "cmd.exe /c echo 1| clip", 0, TRUE
wsh.Run "cmd.exe /c """ & exe & """ " & HexKeyCode, 0, TRUE
wsh.Run "cmd.exe /c echo 2| clip", 0, TRUE
'OPTIONAL TIDY-UP
'################
fso.DeleteFile exe
sub create_binary_file_()
'########################
hex_="4D5A90...0000"
'FOR THE BINARY FILE WRITE
'#########################
dim str
set str = WScript.CreateObject("adodb.stream")
str.type = 2
str.charset = "iso-8859-1"
str.open
for x = 1 to len(hex_) step 2
high_ = asc(mid(hex_,x,1))
if high_ < 58 then
high_ = (high_-48)*16
else
high_ = (high_-55)*16
end if
low_ = asc(mid(hex_,x+1,1))
if low_ < 58 then
low_ = (low_-48)
else
low_ = (low_-55)
end if
str.writeText(chrW(high_ + low_))
next
str.saveToFile exe, 2
str.close
end sub

Resources