Scripting


Windows Script Host

Download Examples

Why am I telling you about Windows Script? Well, the biggest effect may be it would discourage you from writing C++ programs for simple little tasks. If you knew it takes only 3 lines of code to get a value from an XML file, it would seem to be too much work to download an XML library or write your own.

var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.load("data.xml");
var type  = xmlDoc.selectSingleNode("/Objects/Chair").getAttribute("Type");

If you prefer Python, actually I'm with you. I love the simple syntax and rich libraries of Python. One of the few advantage of Windows Scripting over Python is that you don't need to install anything. It's like the old .bat files. Start up your text editor, write a few lines and it will just work. It's handy for a task like renaming a number of files using regular expressions.

Pros

  • Pre-installed on virtually all Windows systems
  • Decent syntax with JScript
  • Debugging in Visual Studio
  • Exec and Run methods to call external programs
  • Activating other windows and simulating key inputs
  • Regular expressions
  • XML parser
  • In addition to the "Process" environment variables, "User" and "System" variables (as in Control Panel>System>Environment Variables>User/System) can be modified
  • File/Folder operations
  • Math library built-in
Cons
  • Lack of resources
    The Microsoft site and the downloadable Script56.CHM file are good resources. However, to go beyond that, you have to go search on the Web. The effective Google keywords are "WSF" and "ActiveXObject" (for JScript), "FileSystemObject" and "WshShell". Also, running CScript.exe without any argument will display the command-line usage of CScript.
  • Outlook will block .wsf file attachments
    Just like .exe and .bat, many email programs will block the email or strip the attachment since it can contain malicious code.

Introduction

Create a text file with the lines below and name it Test_Hello.wsf (or extract "Test_Hello.wsf" from WSHExamples.zip). If you place it anywhere in the PATH, you can just type "Test_Hello" to the command prompt to run this script.

<job>
<script>

WScript.Echo("hello, world");
WScript.Echo("You are " + (4 / 3 * Math.PI * Math.pow(6371, 3)) + " cubic kilometers.");

</script>
</job>

By default, the extension ".wsf" is bound to WScript.exe, the window-based interpreter. You will get a dialog window pop up for every WScript.Echo() call, which can be annoying. To bind ".wsf" to CScript.exe, the console-type interpreter, open Command Prompt as Administrator and run this command.

cscript //H:CScript

It is also handy to run this command to make "No banner" (//nologo) saved as default (//S).

cscript //nologo //S

Each .wsf file needs to start and end with the <job> tags. The section for each language (JScript, VBScript, etc.) needs to be enclosed in the <script> tags. In the following examples, I will omit the <script> and <job> tags unless the script includes non-JScript code.

Examples

All the examples in this page are downloadable in WSHExamples.zip. The ZIP also contains a simple Visual Studio project for creating an ActiveX object that can be called from the script.

Debugging with Visual Studio

Running the script with the "//X" Type this line to debug hello.wsf in Visual Studio.

	cscript Test_XML.wsf //X
	or
	Test_XML //X

As can be seen in the screenshot (click on the image to see in full scale), you can set breakpoints, step through the code, and examine variables.

Processing Another Program's Output

JScript has much better structure than the .bat file and it is easier to write a script that runs a series of Windows programs conditionally. The WScript.Shell object has two methods to run an external program: Exec and Run. The Exec method returns a process object that allows access to its standard I/O, which makes it easy to process the output from a program. (See this TechNet article for details.) This sample script "Test_Exec.wsf" takes the output from a "dir" and replaces each space with the caret character.

var shell = WScript.CreateObject("WScript.Shell");
var process = shell.Exec("cmd /c dir");
while (process.Status == 0)
{
	WScript.Sleep(100);
}
var result = process.StdOut.ReadAll();
var modified = result.replace(/ /g, "^");
WScript.Echo(modified);

Output looks like this:

^Volume^in^drive^C^is^WD15EARS
^Volume^Serial^Number^is^14FA-8E39

^Directory^of^C:\Projects\WSH\Examples

02/05/2011^^07:46^PM^^^^<DIR>^^^^^^^^^^.
02/05/2011^^07:46^PM^^^^<DIR>^^^^^^^^^^..
09/20/2005^^08:14^PM^^^^^^^^^^^^^^^261^Test_Activate.wsf
02/05/2011^^06:03^PM^^^^<DIR>^^^^^^^^^^Test_ActiveX_CS
    :
    :

Running Programs, Activating Windows and Sending Keys

The "WScript.Shell" (WshShell) object has two methods to run an external process: Exec and Run. Exec returns a WshScriptExec object that has ExitCode, ProcessID, Status, StdIn, StdOut and StdErr properties and Terminate method. The Run method has the window style and wait-on-return parameters. WshShell also has the SendKey method. Activating another window (Internet Explorer for instance) can be achieved like this.

var shell = WScript.CreateObject("WScript.Shell");
shell.AppActivate("Microsoft Internet Explorer");

This sample script "Test_RunCalc.wsf" runs the Calc.exe and types 1 + 2 ENTER * 3 ENTER.

var shell = WScript.CreateObject("WScript.Shell");
shell.Run("calc");
WScript.Sleep(1000);

shell.AppActivate("Calculator");
WScript.Sleep(1000);

shell.SendKeys("1{+}");
WScript.Sleep(1000);

shell.SendKeys("2");
WScript.Sleep(1000);

shell.SendKeys("~"); // ~ is ENTER
WScript.Sleep(1000);

shell.SendKeys("*3");
WScript.Sleep(1000);

shell.SendKeys("~");

Similarly, "Test_RunNotepad.wsf" runs Notepad.exe, type some text and saves it as a file. This kind of input simulation is handy, for instance, when a third-party program allows you to export an item from its database one by one but not as a multi-selection batch command. There is no error checking or exit condition so make sure you script wouldn't go berserk.

File Processing and Regular Expressions

This script "Test_FindFiles.wsf" shows how to enumerate the files in a folder and its subfolders recursively.

var g_fso = new ActiveXObject("Scripting.FileSystemObject");

ScanFolder(".");

function ScanFolder(folderName)
{
	var folder = g_fso.GetFolder(folderName);

	// Scan files
	var enumerator = new Enumerator(folder.Files);
	while (!enumerator.atEnd())
	{
		var pathName = enumerator.item();
		WScript.Echo(pathName);
		enumerator.moveNext();
	}

	// Scan folders
	enumerator = new Enumerator(folder.SubFolders);
	while (!enumerator.atEnd())
	{
		var folderName = enumerator.item();
		ScanFolder(folderName);
		enumerator.moveNext();
	}
}

This script "Test_Rename.wsf" renames the files in the current folder by channging every letter "u" into "_I_DONT_LIKE_THAT_LETTER_" and vice versa. The "if" and "else if" blocks demonstrate different methods of string replacement.

var pathName = enumerator.item();
var file = fso.GetFile(pathName);
var fileName = file.Name;

// Same as: var re = new RegExp("(.*)u(.*)", "i"); 
// "i" = ignore case
var re = /(.*)u(.*)/i;

if (re.exec(fileName))
{
	var newName = RegExp.$1 + "_I_DONT_LIKE_THAT_LETTER_" + RegExp.$2;
	WScript.Echo(fileName + " -> " + newName);
	fso.MoveFile(fileName, newName); // Rename file
}
else if (/_I_DONT_LIKE_THAT_LETTER_/.exec(fileName))
{
	var newName = fileName.replace(/_I_DONT_LIKE_THAT_LETTER_/g, "u");
	WScript.Echo(fileName + " -> " + newName);
	fso.MoveFile(fileName, newName); // Rename file
}

This block of code from "Test_FileFilter.wsf" reads from the input one line at a time and swaps the substrings before and after the "=" character if there is one.

	var input = g_fso.OpenTextFile(inputPath, kForReading);
	var output = g_fso.CreateTextFile(outputPath, true);
	while (!input.AtEndOfStream)
	{
		var line = input.ReadLine();
		var re = /(.*)=(.*)/i; // RegExp for substring "=" substring
		if (re.exec(line))
		{
			line = RegExp.$2 + "=" + RegExp.$1; // RegExp.$1 and RegExp.$2 match the first and second (.*), respectively.
		}
		output.Write(line + "\n");
	}
	output.Close();
	input.Close();

Windows Registry

Windows Script Host has full access to the Windows Registry. The bulk of the "Test_ReadRegistry.wsf" looks like below. Writing the registry uses a similar construct and it will require Administrator Privilege to run. (On Windows 7, right-click on Accessories > Command Prompt in the Start Menu and select "Run as administrator".)

var g_shell = new ActiveXObject("WScript.shell");
var key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0\\Registration\\UserName";
var result = g_shell.RegRead(key);

Environment Variables

The script "Test_EnvVar.wsf" will print:

WINDIR is C:\Windows
Z_SYSTEM is %Z_SYSTEM%
Z_USER is %Z_USER%
Z_PROCESS is Windows Script Host
Note: Values of Z_SYSTEM and Z_USER won't appear to be set until you start another instance of Command Prompt

"processEnv" is the environment of the current cscript.exe itself that can be changed by the script. If you open Control Panel>System, you can verify that "Z_SYSTEM" has been added to the SYSTEM variables. Since cmd.exe will only read the environment variables when it starts up, the script cannot change its environment variables.

var shell = WScript.CreateObject("WScript.Shell");
var systemEnv = shell.Environment("SYSTEM");
var userEnv = shell.Environment("USER");
var processEnv = shell.Environment("PROCESS");

processEnv("Z_PROCESS") = "Windows Script Host";
userEnv("Z_USER") = "Windows Script Host";
systemEnv("Z_SYSTEM") = "Windows Script Host"; // This requires Administrator privilege.

WScript.Echo(shell.ExpandEnvironmentStrings("WINDIR is %WINDIR%"));
WScript.Echo(shell.ExpandEnvironmentStrings("Z_SYSTEM is %Z_SYSTEM%"));
WScript.Echo(shell.ExpandEnvironmentStrings("Z_USER is %Z_USER%"));
WScript.Echo(shell.ExpandEnvironmentStrings("Z_PROCESS is %Z_PROCESS%"));
WScript.Echo("Note: Values of Z_SYSTEM and Z_USER won't appear to be set until you start another instance of Command Prompt");

XML Processing

As mentioned at the top of this page, XML processing is very easy with the help of available ActiveX objects. "Test_XML.wsf" shows the usages of two ActiveX objects: Microsoft.XMLDOM" and "msxml2.DOMDocument.6.0".

var inputPath = "Test_Data.xml";

var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
xmlDoc.load(inputPath);
var node = xmlDoc.selectSingleNode("/Game/Level/Object[1]");
WScript.Echo(node.getAttribute("Color"));

var dom = new ActiveXObject("msxml2.DOMDocument.6.0");
dom.async = false;
dom.resolveExternals = false;
dom.validateOnParse = false;
dom.load(inputPath);

var elements = dom.getElementsByTagName("Level");
for (var i = 0; i < elements.length; ++i)
{
	var e = elements[i];
//		:
//		:
}

Input Dialog

Windows Script can be written in JScript or VBScript. The WScript.shell object provides the Popup method, but a few VisualBasic functions such as InputBox and MsgBox are missing from JScript. To use those functions from JScript, you can have multiple <script> elements in a single .wsf file. This example "Test_InputDialog.wsf" also shows how to include an external script file ("Test_Include.wsf").

<job>
<script language='VBScript'>

function VB_InputBox(prompt)
	VB_InputBox = InputBox(prompt)
end function

function VB_MsgBox(message)
	MsgBox(message)
end function

</script>

<script language='JScript' src="Test_Include.wsf"/>

<script language='JScript'>
// Use VBScript InputBox and MsgBox
//
var input = VB_InputBox("Enter a string");
VB_MsgBox("You entered \"" + input + "\"");

// Use JScript Popup method
//
var g_shell = new ActiveXObject("WScript.shell");
g_shell.Popup("Hello");

var text = "Yes or No?";
var secondsToWait = 10;
var title = "Test_InputDialog";
var type = kYesNo | kExclamationMark;
var response = g_shell.Popup(text, secondsToWait, title, type);
WScript.Echo(response);

</script>
</job>

Clipboard

By finding the right ActiveX objects, you can take advantage of Microsoft Office and other programs. Actually, for many features of Windows Scripting, you have to rely on ActiveX objects. Finding the documentation turns out to be not trivial, however. Here is the code "Test_Clipboard.wsf" that copies the argument to the clipboard using Internet Explorer. It may pop up a "Allow access" / "Don't allow" dialog depending on the security settings.

var ie = new ActiveXObject('InternetExplorer.Application');
ie.Navigate('about:blank');
while (ie.ReadyState != 4)
{
	WScript.Sleep(10);
}
var clipboard = ie.Document.parentWindow.clipboardData;

if (1 <= WScript.Arguments.Unnamed.length)
{
	clipboard.setData("text", WScript.Arguments.Unnamed.Item(0));
}
ie.Quit();

If you create a shortcut to this script like this in your SendTo folder, then you can right-click on a file or folder and select it from the "Send To" menu to copy its full path to the clipboard.

Downloading from a URL

This script downloads the data from the specified URL and saves it into a file.

var xmlHttp = new ActiveXObject("MSXML2.XMLHTTP");
var asyncRequest = false;
var url = "http://www.komeiharada.com/Computing/Programming/Scripting.html";
xmlHttp.Open("GET", url, asyncRequest);
xmlHttp.Send();

var outputStream = new ActiveXObject("ADODB.Stream");
outputStream.Type = 1; //  BINARY_STREAM_TYPE;
outputStream.Open();
outputStream.Write(xmlHttp.responseBody);
var filePath = "Test_DownloadURL.txt";
outputStream.SaveToFile(filePath); // Fails if the file already exists
outputStream.Close();

Speech API

This example uses Microsoft Speech API to generate speech output.

var sapi = new ActiveXObject("SAPI.SpVoice");
var message = "This is the test of the emergency broadcast system.";
sapi.Speak(message);

ActiveX Object

Being able to call C++ and C# functions from Windows Script would be great but the task of creating ActiveX objects sounded like too much work for me ... until I found this article: Writing an ActiveX control in C#. Below is the example I created based on the article. "Test_ActiveX.wsf" is the JScript code:

var cs = new ActiveXObject("Test_ActiveX_CS.CS");

WScript.Echo("Result = " + cs.GetInt());
cs.SetInt(1337);
WScript.Echo("Result = " + cs.IntProperty);

WScript.Echo("Result = " + cs.StringProperty());
cs.SetString("Foo");
WScript.Echo("Result = " + cs.GetString());

"Test_ActiveX.cs" is the C# code:

using System;
using System.Runtime.InteropServices;

namespace Test_ActiveX_CS
{
	public interface CSInterface
	{
		int GetInt();
		void SetInt(int value);
		int IntProperty { get; set; }
		string GetString();
		void SetString(string value);
		string StringProperty { get; set; }
	}

	[ClassInterface(ClassInterfaceType.AutoDual)]

	[ComVisible(true)]
	public class CS : CSInterface
	{
		private Test_ActiveX_CPP.Managed m_managed;

		public CS()
		{
			System.Console.WriteLine("CS.CS()");
			m_managed = new Test_ActiveX_CPP.Managed();
		}
		public int GetInt()
		{
			System.Console.WriteLine("CS.GetInt()");
			return m_managed.GetInt();
		}
		public void SetInt(int value)
		{
			System.Console.WriteLine("CS.SetInt()");
			m_managed.SetInt(value);
		}
		public int IntProperty
		{
			get
			{
				System.Console.WriteLine("CS.IntProperty get");
				return m_managed.GetInt();
			}
			set
			{
				System.Console.WriteLine("CS.IntProperty set");
				m_managed.SetInt(value);
			}
		}
		public void SetString(string value)
		{
			System.Console.WriteLine("CS.SetString()");
			m_managed.SetString(value);
		}
		public string GetString()
		{
			System.Console.WriteLine("CS.GetString()");
			return m_managed.GetString();
		}
		public string StringProperty
		{
			get
			{
				System.Console.WriteLine("CS.StringProperty get");
				return m_managed.GetString();
			}
			set
			{
				System.Console.WriteLine("CS.StringProperty set");
				m_managed.SetString(value);
			}
		}
	}
}

The C# project (Test_ActiveX_CS.csproj) and the C++ project (Test_ActiveX_CPP.vcproj) including the managed and unmanaged C++ code are all included in WSHExamples.zip. After building the DLL's, RegAsm.exe of the .NET Framework needs to be run in the Administrator mode to register the ActiveX object.

set regasm=C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe
%regasm% Test_ActiveX_CS.dll /tlb /codebase

References

Google keywords: WSF, ActiveXObject, FileSystemObject, WshShell, ADOdb (ActiveX Data Objects Database) Links

Javascript

Be sure not to confuse Javascript with Java. Javascript is a loosely-typed language like Perl or Python and only resembles Java in the syntax. It is also known as ECMAScript. JScript is Microsoft's version of Javascript.

Windows Script Host

As mentioned above, JScript and VBScript are the languages for Windows Script.

Web page

Javascript is often used to add interactivity to web pages. These days, a new technique called AJAX (Asynchronous JavaScript and XML) is used to implement advanced features as seen in Google Map.

Adobe Photoshop

If you download Photoshop Script Plug-in from the Adobe website, then you can write Javascript to automate routine processes. Below is a code sniplet that rotates and resizes an images and copies it to a newly-created image.

var originalRulerUnits = preferences.rulerUnits; // Save the unit
preferences.rulerUnits = Units.PIXELS;

var doc = documents[0]; // Select first image
var width = g_height * doc.height / doc.width;
activeDocument = doc;
doc.rotateCanvas(-90); // rotate
doc.resizeImage(width, g_height); // resize
doc.selection.selectAll();
doc.selection.copy();
doc.close(SaveOptions.DONOTSAVECHANGES); // discard

var newDoc = documents.add(g_width, g_height); // Create a new document

newDoc.selection.select(new Array(new Array(g_width - width, 0), new Array(g_width, 0), 
	new Array(g_width, g_height), new Array(g_width - width, g_height)), 
	SelectionType.REPLACE); // Select destination area
newDoc.paste(true); // copy from the first image

preferences.rulerUnits = originalRulerUnits; // Restore the unit

More Reading:

  • volley obsession

  • Marque De Vetement Boutique

  • programma retis

  • flavia fenaroli

  • biker