external VBScript in a HTA - vbscript

I am trying to get my HTA to load a script from an external location to save me releasing new HTA files, some of it can be loaded dynamically as I continue to add new functions to it. I can get it to work when I am using IIS to host the script file locally on my PC. But when I am trying to host it externally (I have only tried GitHub so far) I get the following error:
Line: 1
Char: 1
Error: "Type mismatch: 'Hello'"
Code: 0
URL:
I have something like:
<html>
<HEAD>
<title>HTA Test</title>
<HTA:APPLICATION
SCROLL="yes"
SINGLEINSTANCE="yes"
WINDOWSTATE="maximize"
>
<script language="VBScript" src="http://localhost/HtaUpdates/script.txt"></script>
<SCRIPT Language=vbscript>
Sub Window_OnLoad
setTimeout "Hello", 100, "VBScript"
End Sub
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</html>
and in the script.txt on the server:
Sub Hello
MsgBox("Hello.")
End Sub

I have two recommendations for you.
Firstly, the reason why the script isn't loading is because you're specifying the script as type 'txt'. This means when you serve the script over your local/remote web server, the MIME type for the script will be 'text/plain' which won't be accepted. If you rename it to be a proper 'vbs' extension, IIS will serve the file with the MIME type 'text/vbscript' which is what the HTA is expecting.
Additionally, using setTimeout in this way is fragile because it requires that your script contents are loaded successfully within 100ms. If the network is slow, the call will fail. It's better to simply make the call to Hello at the end of the script that you are requesting over the network. You could repurpose the setTimeout call to check if the script has loaded successfully within e.g. 10 seconds (by looking for a variable, maybe?) and show an error message if it hasn't. Note that in my solution below, I have put the main code before the script tag, so that the global variable loaded is visible to the remote script.
One final warning: While testing this, I found that the HTA was caching the VBS file so when I made changes to script.vbs, they weren't taking effect when I reloaded the application. You'd need to either...
configure the web server to set an Expires header so that these files don't get cached
write some code in your HTA file to request the script with a 'nonce' value after it, to override the cache. For example requesting http://localhost/script.vbs?nonce=[RANDOM NUMBER], using VBScript's Randomize and Rnd functions. Requesting a static file with a nonce like this will still work on IIS because the parameters are ignored - it only cares that the file exists.
test.hta:
<html>
<HEAD>
<title>HTA Test</title>
<HTA:APPLICATION SCROLL="yes" SINGLEINSTANCE="yes" WINDOWSTATE="maximize">
<SCRIPT Language=vbscript>
Dim loaded : loaded = False
Sub CheckLoaded()
If loaded Then
MsgBox("Yes, the script loaded.")
Else
MsgBox("Oh dear! The script hasn't loaded.")
End If
End Sub
Sub Window_OnLoad
setTimeout "CheckLoaded", 1000, "VBScript"
End Sub
</SCRIPT>
<script language="VBScript" src="http://localhost/script.vbs"></script>
</HEAD>
<BODY>
</BODY>
</html>
script.vbs:
loaded = True
MsgBox("Hello.")

Related

Custom browser protocol to open IE with params

I need to implement something similar to this answer
https://stackoverflow.com/a/41749105/1004374
but I have several issues.
I changed it slightly so be able to pass arguments into the url:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>openie</title>
</head>
<body>
<h1>Hello world!</h1>
Google1
Google2
</body>
</html>
and changed reg script:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\openie]
"URL Protocol"="\"\""
#="\"URL:OPENIE Protocol\""
[HKEY_CURRENT_USER\Software\Classes\openie\DefaultIcon]
#="\"explorer.exe,1\""
[HKEY_CURRENT_USER\Software\Classes\openie\shell]
[HKEY_CURRENT_USER\Software\Classes\openie\shell\open]
[HKEY_CURRENT_USER\Software\Classes\openie\shell\open\command]
#="cmd /k set myvar= & call set myvar=\"%1\" & call set myvar=%%myvar:openie:=%% & call \"C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe\" %%myvar%% & exit /B"
The only update is shielding of %1 argument:
myvar=\"%1\
This is needed to pass arguments with &. Otherwise will be copied url until first ampersand:
openie:https://www.google.com/?word=abc&word2=abc2
All is fine when you click the link first time. When IE is already opened url is copied incorrectly with encoded quotes inside it and automatically added http in the begining:
http://%22https//www.google.com/?word=abc&word2=abc2"
I realize that issue with cmd script inside but cannot guess what should be changed to be able to pass arguments and click links many times.
Not found a good way to modify the script to accept the '&'. but as a workaround, I suggest you could encode the url, and change the '&' to '%26', the link as below:
Google2
Then, in the destination page, you could decode the url and change '%26' to '&', then, split the string and get the parameters.
More details, please refer to the HTML URL Encoding.

Include some kind of "header"-file to VBScript [duplicate]

VBScript doesn't appear to have a way to include a common file of functions.
Is there a way to achieve this?
You can create a (relatively) small function in each file that you want to include other files into, as follows:
sub includeFile (fSpec)
dim fileSys, file, fileData
set fileSys = createObject ("Scripting.FileSystemObject")
set file = fileSys.openTextFile (fSpec)
fileData = file.readAll ()
file.close
executeGlobal fileData
set file = nothing
set fileSys = nothing
end sub
and then use it to include specific files - these are executed as if they were inline.
includeFile "commonapi.vbi"
includeFile "dbcalls.vbi"
It basically opens the file, reads the entire contents into a string, then executes that string. There's no error handling on the I/O calls since this sort of stuff is usually done once on program start, and you want to fail if there's a problem including it.
Note that the includeFile function can be compressed to:
Sub includeFile(fSpec)
With CreateObject("Scripting.FileSystemObject")
executeGlobal .openTextFile(fSpec).readAll()
End With
End Sub
Or even to (if you're not adverse to long lines):
Sub includeFile(fSpec)
executeGlobal CreateObject("Scripting.FileSystemObject").openTextFile(fSpec).readAll()
End Sub
The "Windows Script Host" framework (if ya want to call it that), offers an XML wrapper document that adds functionality over regular vbs files. One of which is the ability to include external script files of both the VBscript and Jscript flavors. I never got very deep into it, but I think it would do what you're wanting to do.
http://msdn.microsoft.com/en-us/library/15x4407c(VS.85).aspx
You can include JavaScript, VBScript, or modules of other WScript script languages.
Example WSF file:
<job id="IncludeExample">
<script language="JavaScript" src="sprintf.js"/>
<script language="VBScript" src="logging.vbs"/>
<script language="VBScript" src="iis-queryScriptMaps.vbs"/>
</job>
If the above file is called "iis-scriptmaps.wsf", run it this way with cscript.exe:
cscript.exe iis-scriptmaps.wsf
I know this is an old thread but I post my answer anyway so others can learn what I have learnt about VBS and WSF files by "trial and error" :
So to have the same functionality as in other languages you can create one WSF file and include all of your VBS libs there, including the main program.
Something like this :
<job id="MainProg">
<script language="VBScript" src="Constants.vbs"/>
<script language="VBScript" src="FileFunctions.vbs"/>
<script language="VBScript" src="SendMail.vbs"/>
<script language="VBScript" src="LoggingFunctions.vbs"/>
<script language="VBScript" src="MainProgram.vbs"/>
<script language="VBScript">
' Here we call the main program
MainProgram()
</script>
</job>
In Constants.vbs collect all constants you want to use later and in the other VBS files define your functions. In your main program file MainProgram.vbs, create a sub called MainProgram() and write your program there.
In this subroutine, you can use all of the constants and functions defined in the other VBS files.
For example :
sub MainProgram()
' Local variables
Dim strMessage, strSendTo, strSubject
' OpenFile is a function from FileFunctions.vbs
strMessage = OpenFile("C:\Msg\message.html")
strSendTo = "email.address#yourdomain.com"
strSubject = "Daily report - " & date
' SendMessage is a function from SendMail.vbs
' cFrom and cServer are constants from Constants.vbs
SendMessage(cFrom, strSendTo, strSubject, strMessage, cServer)
' Logger is a function from LoggingFunctions.vbs
Logger("Daily report sent - " & now())
end sub
Hope you get the idea and I could help some people write better VBS apps :)
Building on the accepted answer, here's an include sub procedure which takes a path relative to the script location instead of the working directory:
Sub include( relativeFilePath )
Set fso = CreateObject("Scripting.FileSystemObject")
thisFolder = fso.GetParentFolderName( WScript.ScriptFullName )
absFilePath = fso.BuildPath( thisFolder, relativeFilePath )
executeGlobal fso.openTextFile( absFilePath ).readAll()
End Sub
Note the you can additionally use . and .. parts in your path to include files in parent folders, etc. and it will not matter where you launch the script from. Example:
include "..\Lib\StringUtilities.vbs"
Is this VBScript being used locally, or served classic ASP style?
If its classic ASP, you can use SSI todo it:
<!-- #include virtual="/PathTo/MyFile.vbs" -->
You can use the ExecuteGlobal function to run arbitrary VBS code in the global namespace. An example can be found here : http://www.source-code.biz/snippets/vbscript/5.htm
IIS 5 and up also allow a script tag for including other files from an ASP file. (Is your VBScript an ASP page or a Windows script?) Here's an example:
<script language="VBScript" runat="server" src="include.asp"></script>
The behavior and rules are a bit different from server-side includes. Note: I have never actually tried using this syntax from classic ASP.
you can definately use the WSF script tag in cscript:
<script language="VBScript" src="ADOVBS.INC"/>
If you use ADOVBS.inc for an ADODB access make sure to remove the
<% %>
tags from ADOVBS.INC.

VBScript (Classic ASP): Trying to output Absolute Path of Current Dir to Browser, but getting Error

I'm trying to print to the browser screen the Absolute Path of the current directory using Classic ASP. (equivalent to PHP's echo command).
I'm getting this error on the last line of the code below:
"Microsoft VBScript runtime error '800a01a8'
Object required: 'Document'
/Research/ro.asp, line 17"
I've tried a couple different methods to print to the screen (Like WScript.StdOut.Write) and they return the same error as well.
I suspect that my error has something to do with the fact that it is an object, and objects require a different method of printing to the screen.
Any thoughts on this from anyone?
samplefile.asp=
<%
Dim szCurrentRoot: szCurrentRoot= ""
'Create the File System Ojbect
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
'Get the Absolute Path of the current directory
szCurrentRoot = objFSO.GetParentFolderName(Server.MapPath(Request.ServerVariables("URL")))
'Print to the screen. The following line is line 17 which causes the error
Document.Write(szCurrentRoot)
%>
After some more research, I found the answer to my question:
Response.Write(szCurrentRoot)
This way of writing to the browser screen was successful.
<%
Dim szCurrentRoot: szCurrentRoot= ""
'Create the File System Ojbect
Set objFSO = Server.CreateObject("Scripting.FileSystemObject")
'Get the Absolute Path of the current directory
szCurrentRoot = objFSO.GetParentFolderName(Server.MapPath(Request.ServerVariables("URL")))
'Print to the screen.
Response.Write szCurrentRoot
%>
Response.Write is the way to send text data back to the client. Use <% %> is a shortcut to this method.
You can't print to the screen from ASP, you can only write a response back to the browser, using Response.Write Server.EncodeHTML(szCurrentRoot) or the shorthand <%=Server.EncodeHTML(szCurrentRoot) %> if you are not inside a code block.
Yea Document is not implicitly defined if you are running this from the command line
eg.
cscript whatever.vbs
If you were to run this script inside of IE in a you would have access to "document"
Try doing this
Set ie = CreateObject(“InternetExplorer.Application”)
ie.document.write(szCurrentRoot)

Enumerated Types in VBScript

I want to script creating a scheduled task with VBScript.
I need to use the Enumerated Types of the Task Scheduler object to set the task to run with "Highest Privileges".
Anyone know how I set this?
Thanks,
Ben
I guess you're using the Task Scheduler 2.0 Scripting API, right?
The easiest solution is to manually define any constants needed in your script:
Const TASK_RUNLEVEL_LUA = 0
Const TASK_RUNLEVEL_HIGHEST = 1
Alternatively, you can try the following: wrap your VBScript code in a Windows Script (.wsf) file and use the <reference> tag to import the Task Scheduler type library, so that your script has access to constants defined in that type library. Your .wsf script would look something like this:
<job>
<reference object="Schedule.Service" />
<script language="VBScript">
WScript.Echo TASK_RUNLEVEL_HIGHEST
</script>
</job>
You can find more info on Windows script files here: Using Windows Script Files (.wsf).

How do I include a common file in VBScript (similar to C #include)?

VBScript doesn't appear to have a way to include a common file of functions.
Is there a way to achieve this?
You can create a (relatively) small function in each file that you want to include other files into, as follows:
sub includeFile (fSpec)
dim fileSys, file, fileData
set fileSys = createObject ("Scripting.FileSystemObject")
set file = fileSys.openTextFile (fSpec)
fileData = file.readAll ()
file.close
executeGlobal fileData
set file = nothing
set fileSys = nothing
end sub
and then use it to include specific files - these are executed as if they were inline.
includeFile "commonapi.vbi"
includeFile "dbcalls.vbi"
It basically opens the file, reads the entire contents into a string, then executes that string. There's no error handling on the I/O calls since this sort of stuff is usually done once on program start, and you want to fail if there's a problem including it.
Note that the includeFile function can be compressed to:
Sub includeFile(fSpec)
With CreateObject("Scripting.FileSystemObject")
executeGlobal .openTextFile(fSpec).readAll()
End With
End Sub
Or even to (if you're not adverse to long lines):
Sub includeFile(fSpec)
executeGlobal CreateObject("Scripting.FileSystemObject").openTextFile(fSpec).readAll()
End Sub
The "Windows Script Host" framework (if ya want to call it that), offers an XML wrapper document that adds functionality over regular vbs files. One of which is the ability to include external script files of both the VBscript and Jscript flavors. I never got very deep into it, but I think it would do what you're wanting to do.
http://msdn.microsoft.com/en-us/library/15x4407c(VS.85).aspx
You can include JavaScript, VBScript, or modules of other WScript script languages.
Example WSF file:
<job id="IncludeExample">
<script language="JavaScript" src="sprintf.js"/>
<script language="VBScript" src="logging.vbs"/>
<script language="VBScript" src="iis-queryScriptMaps.vbs"/>
</job>
If the above file is called "iis-scriptmaps.wsf", run it this way with cscript.exe:
cscript.exe iis-scriptmaps.wsf
I know this is an old thread but I post my answer anyway so others can learn what I have learnt about VBS and WSF files by "trial and error" :
So to have the same functionality as in other languages you can create one WSF file and include all of your VBS libs there, including the main program.
Something like this :
<job id="MainProg">
<script language="VBScript" src="Constants.vbs"/>
<script language="VBScript" src="FileFunctions.vbs"/>
<script language="VBScript" src="SendMail.vbs"/>
<script language="VBScript" src="LoggingFunctions.vbs"/>
<script language="VBScript" src="MainProgram.vbs"/>
<script language="VBScript">
' Here we call the main program
MainProgram()
</script>
</job>
In Constants.vbs collect all constants you want to use later and in the other VBS files define your functions. In your main program file MainProgram.vbs, create a sub called MainProgram() and write your program there.
In this subroutine, you can use all of the constants and functions defined in the other VBS files.
For example :
sub MainProgram()
' Local variables
Dim strMessage, strSendTo, strSubject
' OpenFile is a function from FileFunctions.vbs
strMessage = OpenFile("C:\Msg\message.html")
strSendTo = "email.address#yourdomain.com"
strSubject = "Daily report - " & date
' SendMessage is a function from SendMail.vbs
' cFrom and cServer are constants from Constants.vbs
SendMessage(cFrom, strSendTo, strSubject, strMessage, cServer)
' Logger is a function from LoggingFunctions.vbs
Logger("Daily report sent - " & now())
end sub
Hope you get the idea and I could help some people write better VBS apps :)
Building on the accepted answer, here's an include sub procedure which takes a path relative to the script location instead of the working directory:
Sub include( relativeFilePath )
Set fso = CreateObject("Scripting.FileSystemObject")
thisFolder = fso.GetParentFolderName( WScript.ScriptFullName )
absFilePath = fso.BuildPath( thisFolder, relativeFilePath )
executeGlobal fso.openTextFile( absFilePath ).readAll()
End Sub
Note the you can additionally use . and .. parts in your path to include files in parent folders, etc. and it will not matter where you launch the script from. Example:
include "..\Lib\StringUtilities.vbs"
Is this VBScript being used locally, or served classic ASP style?
If its classic ASP, you can use SSI todo it:
<!-- #include virtual="/PathTo/MyFile.vbs" -->
You can use the ExecuteGlobal function to run arbitrary VBS code in the global namespace. An example can be found here : http://www.source-code.biz/snippets/vbscript/5.htm
IIS 5 and up also allow a script tag for including other files from an ASP file. (Is your VBScript an ASP page or a Windows script?) Here's an example:
<script language="VBScript" runat="server" src="include.asp"></script>
The behavior and rules are a bit different from server-side includes. Note: I have never actually tried using this syntax from classic ASP.
you can definately use the WSF script tag in cscript:
<script language="VBScript" src="ADOVBS.INC"/>
If you use ADOVBS.inc for an ADODB access make sure to remove the
<% %>
tags from ADOVBS.INC.

Resources