VBScript

Information is available at TOOGAM's Software Archive: Page About Programming Languages (section about VBScript) and a tad of information at Job Paths.

Common language use

VBScript has commonly been used in the following environments and/or for the following sorts of purposes:

[#vbsinwsh]: VBScript in WSH

VBScript may work with Windows Scripting Host (a.k.a. Windows Script Host).

Blogs on Microsoft TechNet: “Hey, Scripting Guy!” blog about migrating VBScript to Windows PowerShell shows someone mentioning, “We spent all this time and energy creating all these VBScripts over the last nine years. We have several hundred VBScripts that we use in production”... After mentioning a week of work, the asker noted, “I would rather get a root canal than go through that again.”

The provided response noted, among many other details, “VBScript is going to be in Windows 7, and it is also in Windows Server 2008 R2. If you have a perfectly working VBScript that does everything you want it to do, there is absolutely no reason to get rid of it. I do believe you should be learning Windows PowerShell, however, because it is extremely powerful and is central to our management story moving forward.”

(For more information about Microsoft PowerShell, see the section about Pash/“Monad Shell” (“MSH”)/PowerShell.)

Web

Perhaps being called from ASP pages

Note: JavaScript may often be a more compatible solution

Similarity to Visual BASIC

VBScript is quite similar to Visual BASIC. One major difference is that VBScript supports a data type called “variant”, and does not support other data types for variables. Therefore, VBScript does not define the types of variables, while Visual BASIC typially does.

While Visual BASIC can output using a function called MsgBox (for both the command line interface, or graphical interfaces, as noted by MSDN documentation on MsgBox) or Console.WriteLine (for the command line: MSDN documetnation on Console.WriteLine). VBScript uses WScript.Echo to output (for both the command line via WSH, and the graphical interface via WSH). Keeping in mind many of these key rules, many of the other basic rules, such as conditional statements and looping and defining functions and having a value returned by a function, can work identically as Visual BASIC code or VBScript code. Some differences may still exist, such as the fact that VBScript does not support optional parameters in functions. (This limitation could effectively be worked around functionally, by creating wrapper functions. However, the resulting code would be less concise.)

Language specifications

Information is available at TOOGAM's Software Archive: Page About Programming Languages (section about VBScript)

The following may also be helpful to pick this language up quickly.

Functions in VBScript
(The following may need formatting and/or CSS adjustments.)

Functions:
	Functions start with:
	Function fcnName(optional-comma-separated-list-of-variables
	Then they end with:
	End Function
	The return value involves using a variable that is named after the
	function.  This variable needs no declaration other than the line that
	starts defining the function.  So, if a function is named fcnName, then
	one may return a value by using:
	fcnName = retValue
	It can be nice to declare a value called retValue to store whatever gets
		returned.  Then, at the end of the function, set the real return
		value, using the above line of example code.  By doing this, if
		there becomes a cause to rename the function, this can be done
		by changing the name of the function, and the assignment at the
		end.  If there are multiple lines during the function that affect
		the return value, they won't all need to be changed as well.

		Perhaps an Execute statement could allow
sSelfFcnName to be defined at the top?

MSDN
page discussing VBScript's ability to execute code from memory (comparing to
JavaScript).

This guide doesn't have a strong indication of when to use parenthesis for
calling a function.  In some cases they are required, and in some cases they
need to not exist.  A factor may be whether a function is simply being called
on a line by itself, or whether a variable (in the code that calls the function)
is having its value set to whatever gets returned by the function call.

Optional parameters are not supported by VBScript.  There may be some different
approaches to dealing with that.
	http://www.4guysfromrolla.com/webtech/100301-1.shtml

Loops

Some guides, including W3Schools.com guide to VBScript looping, have been known to suggest using DO...WHILE instead of WHILE...WEND. In fact, the quoted guide's commentary about “While...Wend” is “Do not use it - use the Do...Loop statement instead”.

It seems there may have been some official guidance from Microsoft to recommend doing things the new way.

Well, the WHILE...WEND code from BASIC works just as well, and can be more appropriate in many/most cases, so don't be afraid to use it. Don't be afraid to use it when it is more appropriate.

In addition, a version of BASIC's traditional For...Next loop exists, and a new For Each...Next statement allows running code on each element of an object (including an array which is sometimes, including in this example, able to be treated similar to an object).

(This guide currently does not provide more extensive details.)

The following is some further information which was figured out through experience, and which might not be part of the documentation that provides the official language specification.

Using explicit variables

It is recommended to place the following at the top of each file:

Option Explicit

Doing so can cause some problems, particularly when dealing with pre-existing code that did not follow this guideline. However, it can help help tremendously with some other problems that are more difficult to deal with, and so it is an especially great idea to use this for any new code. One such problem could be accidental code re-use. Another is thinking that a variable has one scope, when it really has another. That thinking could cause a fresh new variable to be used, when it is expected that the value of another variable is used.

This code might be able to executed within a function, but experience with WSH seems to indicate that an error occurs from setting the “Option” to “explicit” when the “Option” was already set to “Explicit”. This error does not seem to occur if one library file sets the option to explicit even if the option was already set in another file. So, once per file may be safer. (This has the side effect of also meaning that this option ends up being set for all of the functions in the file, which may often be good programming practice.)

Variable initializing

A variable cannot be given an initial value during initialization. However, declarations do not need to happen before executable code. Therefore, it may be a somewhat common practice to use a compound statement, which means a single line of text with multiple statements separated by a colon. e.g.:

Dim simpleCounter : simpleCounter = 0
File handling

This may differ for web browsing. The following guide is meant for WSH.

See the Windows Scripting Host guide for example code.

Better techniques

There's a lot of bad code out there. There are some problems that, because they are so frequently being violated by a bunch of example code, are worth pointing out.

One is that a lot of code provides very minimal, and even non-existent, error-handling.

The other is leaving things unwrapped up. Much of the code may just leave files open, or objects set. That might function okay due to some garbage collection, but there is a case to be made to the benefits of old-school manual handling (which was more common when such manual handling was often more required). An explicit statement to free up an object's resources can free an object's resources and also help to clearly show that the object is no longer needed. That sort of coding style may improve readability, by being a bit self-documenting in nature. In the case of a tiny program, leaving a file opened may have no immediately noticed impact, but just leaving a file opened forever until the program exits can be unnecessarily inconsiderate. For instance, if a file is opened on a network share, it may be nice to stop using the remote fileserver when there is no longer any need for the file to be opened.

(Perhaps files are closed automatically when a filesystem object is set to Nothing? If so, that may help to explain why it seems that many files are not closed in many pieces of example code.)

Example code here could be nice. e.g., dealing with a file: error handling, and freeing up resources

Using a main function

Another great idea is to make a main (which might have a name like main or, to reduce the unlikely chance of a conflict with a function from another language, perhaps use a name like VBSmainFcn (which stands for VBScript main function).

In the C language, this was required, as the C compiler would run whatever code was in the main function. In VBScript, this is often not needed, as code may just be run globally when the file's code is being loaded. That may be great for small code run within a web browser, and less great for larger programs that involve structured code being loaded from a file. One bit of code that may make sense to run at a global value is a statement that helps to initialize a global variable. However, even that code may often be able to go into an initialization function which gets called from a main function. (In some cases, though, immediate initialization may just seem more sensible, perhaps so that people viewing the code can immediately see what value is intended.)

By placing code in a main function, the main function can easily be commented out. Or, its name may be changed to a new function name, if the initially intended program ends up later becoming code that is just a subset (a.k.a. a part of) a larger program. If manual indenting is needed, then causing this to be a function won't require manual indentation.

Then, somewhere (perhaps just after the main function), include a statement to call the main function. This globally executed code should probably do very little: perhaps just call the main function, get any return value, and quit. Or, instead of just quitting, pass the return value back to the operating system.

Libraries

Using libraries may be beneficial. (That statement could be expanded on, by describing some of the benefits.)

The method to load a library might vary based on how VBScript is being used: i.e. whether VBScript is used from WSH, or from Microsoft Internet Explorer (or perhaps some other method?). These different approaches are needed mainly for the simple reason that files may be accessed differently in a web browser compared to using VBScript in an environment such as WSH.

Libraries with WSH

For WSH, the following may work:

The language can be finessed into supporting external libraries using ExecuteGlobal.

Perhaps see: MSDN page discussing VBScript's ability to execute code from memory (comparing to JavaScript).

Thanks to Mark Alexander Bain's guide which helped show the basic concepts.

If you, as the reader, are looking for information about how to re-use code, then you might appreciate a simple re-usable example. Consider placing the following at the top of your main code file.

Note: This file has not currently been tested. A similar file had been known to work, but if there are typos/syntax errors/etc. in this file, they may still need to be corrected.
' Each file should have a comment describing what it does

Option Explicit
Function stdInitThisFile()
' Definining variable names (and setting values for constants)
const sSelfFcnName="stdInitThisFile"
const ForReading=1
const defStdLibFileName = "stdlib.vbs"
Dim firstFSO
Dim firstFileObj
Dim firstImportedCode
Dim stdLibFileName
Dim retValue

' Setting any additional initial values
stdLibFileName = defStdLibFileName

' Load the standard library
Set firstFSO = CreateObject("Scripting.FileSystemObject")
On Error Resume Next ' e.g. file might not exist
firstFileObj = firstFSO.OpenTextFile(stdLibFileName, ForReading, false)
firstImportedCode = firstFileObj.ReadAll
firstFileObj.Close
Set firstFileFSO = Nothing
ExecuteGlobal firstImportedCode

' Run a standard initialization function that exists in that library
stdIniSeq()

' Exit this function
retValue = 0
Execute "" & sSelfFcnName & " = " retValue
End Function

Function mainFcn()
' This comment should explain what this function does

' Definining variable names (and setting values for constants)
const sSelfFcnName="mainFcn"
Dim retValue

' Load the standard library
stdInitThisFile()

' Check for arguments from the command line.
' (WScript.Arguments.Count definitely
' does equal WScript.Arguments.Length)
If ( WScript.Arguments.Count > 0 ) Then
' The first argument is WScript.Arguments.Item(0)
' The second argument is WScript.Arguments.Item(1)
End If

' Additional code goes here!



' Exit this function
retValue = 0
Execute "" & sSelfFcnName & " = " retValue
End Function

WScript.Quit mainFcn()

One thing to customize in all that is the referenced filename. The point of naming this function after the file is so that other files don't have duplicate function names.

Make a file called stdlib.vbs (or some other customized filename). Naturally, that file should start with a comment. Also, either make sure that file has a function called stdIniSeq or else change the relevant part of the example. Obviously, things may be more interesting if additional code is added to mainFcn().

That process of loading a file may be trimmed down further, as shown by Mark Alexander Bain's guide which does even less error checking, and fewer variables, simply using ExecuteGlobal on a line right after the FSO object is created.

Better yet may be to include some additional error checking, like checking that VarType(firstImportedCode) is set to vbString, and has a non-zero length, and that it contains an expected marker (which may be tested by using InStr). If any of those things are not true, then it may be better to exit gracefully than to try running the ExecuteGlobal command, nor the stdIniSeq function (that is custom, and which apparently wasn't successfully imported).

Another great idea to be performed by the function that loads libraries is to store a marker (like the base filename) for each library that gets loaded (perhaps by calling a dedicated global function, which may use a global variable). Then add support for checking for that global marker before the ExecuteGlobal command is run. This may prevent “Duplicate variable” errors.

Then, it would make sense if the standard library had code to be able to load another file. This way, other files can easily load more libraries with just a single line of text. The calling code can simply check for one simple return value, instead of needing to perform multiple checks.

Another thing, that may make sense to put into a standard library, are commonly used global variables, such as “ const ForReading=1 ” (to match MSDN guide to Visual Basic 6: section on the OpenTextFile Method). Then that constant could even be used by the script that loads other text files.

Another thing may be declaring the definition variables like a global verbosity value. Using such a value is discussed in the section about including (debugging) output. Setting such a value, based on some sort of regularly used parsing of command line parameters and/or environment variables, could be easily used by every program that calls a standard centralized function.