Introduction
Overview
Windows Script Host (WSH) provides a powerful environment for hosting scripting languages. It is Microsoft's replacement for MS-DOS batch files, and it provides a modern, 32-bit environment for developing Windows scripts.
MS-DOS batch files have long been available to perform repetitive task automation, such as file manipulation, but they are limited in performing complex conditional logic evaluation and repetitive loops. Batch files are not very extendible; they do not provide any access to Windows internal operations. The only way to access these operations from a batch file is to have a command-line program to perform the operation.
WSH provides programmatic enhancements such as looping, conditional expressions, and the ability to create subroutines and functions, as well as the ability to perform complex operations through external objects. Using these objects, WSH scripts can automate almost any task that can otherwise be performed through a Windows user interface. These tasks include (but are not limited to) user administration, database access, e-mail operations, and Windows server administrative tasks, such as Internet Information Server (IIS) and Exchange server.
WSH is installed with Windows 98, ME, 2000, and XP. It is available as a separate installation for Windows 95 and NT 4.0.
What Is WSH?
WSH provides a hosted environment for scripting engines. WSH is not a language, and it doesn't rely on any particular language to implement scripts. The default WSH installation provides Visual Basic Scripting Edition (VBScript) and JScript scripting engines.
On their own, these scripting engines can't do anything—they require a host such as WSH to execute scripts. These scripting engines are used by Internet Explorer (IE) for client-side scripts and Active Server Pages (ASP) for server-side scripts.
In WSH, the scripting engines are manipulated by wscript.exe and cscript.exe applications. Scripts executed using cscript.exe send output to the console. Scripts executed using wscript.exe send output to the Windows graphical user interface.
COM Automation
The WSH scripting languages provide a huge improvement over the old MS-DOS batch scripts by providing conditional expression evaluation, loops, and the ability to create subroutines. However, the scripting engines do not provide any access to Windows operations.
For example, the VBScript and JScript engines do not have any built-in methods to copy a file or modify a registry value. Because the scripting engines are used by IE and ASP, you wouldn't want to be able to do this, as there wouldn't be anything stopping somebody from creating a Web page to delete all your files. This wouldn't make IE very popular.
Fortunately, scripting engines hosted by WSH allow you to create COM automation objects. COM objects are "black box"-like libraries that can manipulate data, call other executables, or manipulate the operating system on your behalf. COM objects are themselves typically written in languages such as Visual Basic, Delphi, or C++, though they can also be written in VBScript or JScript using the Windows Script Component technology (described later in this section).
Using WSH, you can create instances of these objects. For example, you could create an instance of a File object that represents the file d:data eport.doc (specific details on how to do this are covered in Chapter 5). You can have multiple instances of an object, so you could have a File object that represents the file d:data eport.doc and another that represents d:dataudget.xls. Each object instance is independent of other instances.
COM objects tasks are performed by calling methods. A method is a procedure that performs a specific operation, similar to a subroutine that can be created in VBScript or JScript. An example of a method for the File object is Delete, which deletes the file represented by the object instance.
Information about the objects is stored in properties. Information about the file size represented by a File object can be read from the Size property. Properties can be read-only or read/write. In the case of the File object, the Size property is read-only. The File object's Name property is read/write, which allows you to read the filename as well as write to it, which would rename the file.
WSH includes a number of objects, which are listed in Table 1-1.
OBJECT |
TASKS |
CHAPTER |
---|---|---|
WScript.Shell |
Run applications and manipulate environment variables and the Windows registry |
Chapter 2 and Chapter 6 |
WScript.Network |
Manipulate network resources, such as shares and printers |
Chapter 4 |
Scripting.FileSystemObject |
Perform file operations |
Chapter 5 |
These objects allow you to perform basic Windows operations. If you want to perform more complex operations, you must rely on other COM objects. Microsoft provides many objects to perform more complicated tasks. Table 1-2 lists tasks and the appropriate objects to perform the tasks.
TASK |
OBJECT |
CHAPTER |
---|---|---|
System administration |
Windows Management Instrumentation (WMI) |
Chapter 10 |
Network administration |
Active Directory Services Interface (ADSI) |
Chapter 14 |
Exchange administration |
ADSI |
Chapter 16 |
IIS administration |
ADSI |
Chapter 15 |
Database support |
ActiveX Data Objects (ADO) |
Chapter 13 |
Mail operations |
Collaborative Data Objects (CDO) |
Chapter 12 |
Security operations |
ADSI/WMI |
Chapter 17 |
Using these objects, you can build sophisticated administrative scripts. You could have a script that creates a new user account, Exchange mailbox, and user share, and applies appropriate security, all in one step.
You could also create a script that monitors event logs and disk space and sends an e-mail to the appropriate user when a certain condition occurs, such as a locked-out account or a user directory exceeding a space limit. The possibilities are endless.
If you are using Windows 2000 or XP, the objects listed in Table 1-2 are installed by default (except CDO). Windows 98 and ME include older versions of WMI and ADO. All of the components are available as (free) separate installations for Windows 9x/ME and NT 4.0.
In addition to these components, you can automate common Windows applications. All Office applications can be automated, so you can use WSH to build Word documents, Excel spreadsheets, or Visio diagrams. Internet Explorer is also a COM component, and WSH can use it to build user interfaces or manipulate Web pages. Microsoft Messenger can be automated to perform instant messaging operations.
If all of this is not enough, there are thousands of third-party components that perform all ranges of operations. Examples in this book include the ping and FTP components (discussed in Chapter 11).
And if you can't find an object to perform a particular operation, you can write your own objects using a programming language such as Visual Basic or C++.
Version 2 0 Features
By nature, the WSH environment is very extensible as a result of its capability to create COM components. There are a large number of free and third-party components to perform various operations. Furthermore, any new capabilities can be added by writing a component.
However, there are a number of scripting environment features that cannot be implemented using COM components and that require changes to the internal workings of the WSH hosting engine.
The main problem stems from the fact that WSH doesn't depend on any given scripting language. There have been improvements in the VBScript and JScript scripting engines, and new WSH functionality has been added. Because the scripting engines are used by other applications, such as IIS and especially IE, there are many considerations that have to be taken into account when making changes to the engines. For example, JScript conforms to the ECMAScript language specification, an international standard for Web scripting, and making major changes to the engine might render Web pages noncompliant to these standards. The main feature missing from WSH version 1.0 is reusability. There was no way of reusing code libraries in WSH scripts. While kludges could be implemented, they never promoted easy and effective code reuse.
WSH version 2.0 introduces code reusability features in Windows Script Files (WSF) and Windows Script Components (WSC). These features provide language-independent code reusability enhancements. WSF implements include files, which allow for script libraries to be included in other files, while WSC allows COM components to be created using scripting languages.
WSF Files
WSH version 2.0 introduces the Windows Script File (WSF) file format, which adds many enhancements, such as including files and the ability to interface COM object type libraries without losing the language-independent nature of WSH.
WSF files "encapsulate" script logic in Extensible Markup Language (XML). XML is a markup language that resembles HTML.
XML is built up of elements. Each element requires an opening and closing tag. An opening tag is the name of the element surrounded in angle brackets (< and >). A closing tag is the same as the opening tag except the element name is prefixed with a forward slash (/). Information stored between the tags is called the body of the element. An example of an XML element is Hello, where is the opening tag, Hello is the body and is the closing tag.
A WSF script is composed of a number of elements. The minimum requirements for a successful WSF script are a element and a
You can execute WSF scripts by double-clicking them from Explorer or entering the script name from the command line.
The
If a directory path is omitted, the include file must reside in the same directory as the WSF script. Directory paths can be either a local path or a UNC path.
If you want to use multiple include files within a job, add an additional
The HelloWorld2 subroutine is stored in the include1.vbs file. Note the first tag, but rather is terminated with a forward slash (/). This is a valid method of representing an XML element, but it only applies if there is no element body.
A job can contain multiple
Variables declared in
While variables and constants can be shared through different script blocks, they are only available in the order they are declared, so a variable declared in the second script block would not be available in the first.
As mentioned earlier, there can be multiple jobs in a WSF file. Jobs can be used to group related scripts into one file. For example, you could have a backup script and a restore script in one file. If there are multiple jobs in a script, the element must be included in the script. The body of the element contains all of the jobs in the script. When you include more than one job, each job must be given a unique ID to identify the job within the package. The ID is assigned by setting an id attribute in each element, as demonstrated by the following script, 2job.wsf:
To execute a specific job, use the //job switch with either cscript or wscript:
wscript | cscript //job:jobname scriptfile.wsf
where jobname is the name of the job and scriptfile.wsf is the .wsf script file where the job is located. For example:
cscript //job:display2 2job.wsf
would execute the job named display2 from the job2 script. If the job ID contains spaces, the //job parameter and job name must be enclosed by double quotes:
cscript "//job: Display Job 1" 2job.wsf
WSF jobs can contain a number of optional XML elements. While the ability to use include files makes the creation and use of constant files easier, it still can be tedious to build and maintain include files. The element provides support for referencing COM object type libraries. A type library contains information on all methods, properties, and constants exposed by an object. Referencing a type library in a WSF file makes all constants available to the script. The syntax is as follows:
Specify either the ProgID or guid for the object type library you want to reference. The ProgID is a "friendly" alias for a COM object. The version attribute is optional and specifies the version number of the type library. The default value is 1.0.
In the following example, a reference to the type library for the File System Object (FSO) component object is made, using the ProgID Scripting.FileSystemObject:
All constants exposed through the object's type libraries are made available to the script. See Solution 9.1 for information on using the Word automation object.
Many type libraries do not have a ProgID and must be referenced by a globally unique identifier (GUID), which uniquely identifies the object and is also known as a class ID (CLSID):
Reference the Excel type library
Another WSF element is . The element creates an instance of a COM object, similar to the VBScript CreateObject methods or the JScript new ActiveXObject methods:
The objID parameter is used to identify the object in the script.
Use either ProgID or GUID to identify the COM object you want to create. These parameters are the same as those used by the element:
Create FSO object and show temp file name
The optional events attribute allows object events to be "sinked." If this attribute is set to Yes or True, the script will receive any events fired by the object. See the "Events" section of this chapter for more information.
WSF files support a element that can be used as an alternative to script constants. The information stored by the element is available to all The advantage of using the resource element is that resource text can span multiple lines, so you can avoid multi-line statements.
The XML version of the script file is determined by version argument, and it should be set to 1.0. The optional DTDflag parameter identifies if a reference to a Document Type Definition (DTD) is made in the script. This does not apply to WSF scripts and should not be set.
If used, the element must appear in the first line of your WSF script:
Adding the element instructs the script interpreter to check all elements for XML syntax, including the body of the
Including the angle brackets in the "Hello World" message will generate an error because the element is parsed for valid XML syntax. Use the ![CDATA[ section element to encapsulate any script code:
Using CDATA ensures that the XML parser ignores any text that appears in the body of the
You can add comments to WSF jobs and packages using the XML comment tag sequence or a element. Anything that appears between the tags or element is ignored by the interpreter:
Scripting Components
COM components have traditionally been developed using languages such as Visual Basic, Visual C++, and Delphi. WSH 2.0 introduced Windows Script Components (WSC), which allows COM components to be implemented using scripting languages.
Window Script Components use the scripting engines included with WSH, such as VBScript or JScript, as well as third-party scripting engines, such as ActivePerl. The components do not use the WSH commands cscript or wscript to execute the scripts. Script components do not have access to the WScript object exposed by the WSH environment.
Script components can be used by any programming environment that supports the creation of COM objects. This pretty much covers any Windows programming language that is available, and includes Visual Basic, C++, Delphi, and the Microsoft Office Visual Basic programming environment.
Script components require the scrobj.dll file as well as the script engines the component was developed in to be used. As long as the component was developed using VBScript or JScript, all you require is a recent version (2.0 or later) of WSH. Script components also don't require any development environment to be installed to maintain them; all you need is a simple text editor such as Notepad.
It's important to note that script components are not suitable for all purposes. Because they're not compiled, there is a performance hit when using them, and the lack of an integrated development environment makes creating and debugging large components tedious.
Script Wizard
Before you create a component, you should determine what the component is going to do. You should plan what properties, methods, and events the component will expose.
Windows Script Components encapsulate the component logic using XML, similar to WSF files. WSC uses XML elements to expose the operations performed and information about the component, such as properties and methods.
Components can be built using a text editor, as with any WSH script. A WSC "wizard" is included with the WSH installation that simplifies the construction of a component by asking a number of questions about the component, such as the name, description, properties, and methods, and then generates the "skeleton" code that you can populate with the support script logic.
To use the wizard, start the Windows Script Component Wizard (see Figure 1-1), which you can find by clicking the Start button and selecting Programs > Microsoft Windows Script.
Figure 1-1: The Windows Script Component Wizard
The Name is the name or description of the component.
The Filename is the name of the file that contains the component and is created with a WSC extension.
The Prog ID (henceforth "ProgID") is used to identify the object when creating instances of it. There are no technical restrictions on naming ProgIDs-they can be any string that you like that does not contain any spaces. However, there are some commonly used conventions. Usually a ProgID is a description of the company or class of functionality, followed by a period, followed by the name of the object, which is optionally followed by a period and then a version number. For instance, Word.Document.8. This convention helps guarantee uniqueness. Version is a number associated with the component, and it defaults to 1.0.
Location is the directory where the Windows Script Component will be created.
The next screen (see Figure 1-2) displays options related to the scripting language and additional options.
Figure 1-2: Options related to the scripting language
Select the scripting language the component will be implemented in. The DHTML and ASP options should not be set if you do not intend to use the component within a Web page or an Active Server Pages page. Set the "Error checking" and/or "Debugging" check boxes if you want to debug your component (see the "Advanced Script Component Topics" section for more information).
The next dialog box (see Figure 1-3) allows you to specify component properties.
Figure 1-3: Specifying component properties
Property names cannot contain spaces. For each property, you must select if it can be read from and/or written to, and optionally you can assign a default value, which determines the initial value the property will contain when an instance of the object is first created.
After the properties have been determined, you can set the methods that are exposed by the object, as shown in Figure 1-4.
Figure 1-4: Setting the methods that are exposed by the object
Enter the name of each method (if there are any), and if the methods require parameters list them in the Parameters text box. Separate each method parameter by a comma.
Finally, you are prompted to specify any events exposed by the component. This doesn't seem to work in the current version of the WSC Wizard. See the "Events" section later in the chapter for more details on events and how to add them.
The last screen (see Figure 1-5) lists the information that you have specified for the component. When you click the Finished button, the component file is created.
Figure 1-5: Listing of the information that you specified for the component
Note |
A component created using the WSC Wizard can be modified and extended at any time using a text editor; however, you cannot use the wizard to modify existing components. |
You now have a "skeleton" to add program logic to:
You can use the code generated by the wizard to look at what script components are composed of.
A WSC file consists of XML elements. A WSC file must have at least one element. The body of the element contains the component logic.
The element contains information used to register the component:
The description attribute corresponds to the Name field in the first WSC Wizard dialog box. The ProgID and version attributes correspond to the fields with the same names in the first WSC Wizard dialog box. The classid attribute is generated by the WSC Wizard and is a unique identifier used to identify the component. Do not change the value of classid unless you are familiar with how it is used. The element contains the public interface, which lists all properties and methods exposed by the component.
Each property is contained in a element. The name of the property is set using a name attribute. The element's body contains if the property can be written to and/or if the property can be read:
Any methods exposed by the component are defined by the element. The name of the method is identified by the name attribute. Any method parameters are identified by elements in the body of the element. The parameter names are specified by a name attribute. Each method parameter requires a parameter attribute:
The actual code is contained in a
The preceding element contains Register and Unregister functions that are executed when the component is registered/unregistered.
Using Script Components
To use a script component you must create an instance of it by using either the CreateObject or GetObject methods.
There are two CreateObject methods available to WSH scripts: One is exposed through the WScript WSH object and the other is part of the VBScript environment. They are functionally identical for the creation of general objects, but they vary in relation to event sinking and remote object creation. The WScript CreateObject method allows for sinking of events (see the "Events" section for more information) and the VBScript method can create remote instances of COM objects (see the "Remote Automation" section for more information).
To create an object, call the CreateObject method (either the WScript or VBScript one) and pass the ProgID as a parameter:
Set objWSC = CreateObject(strProgID)
If successful, the methods will return an instance of the object; otherwise, a runtime error will be generated.
To create an instance of a script component using the GetObject method instead of the CreateObject method, call GetObject and pass the path to the component prefixed with script::
Set obj = GetObject("script:strPath")
strPath identifies the path to the component and can be a local path, UNC, or URL. The advantage of using GetObject over CreateObject is the Windows Script Component does not need to be registered. The following snippet creates an instance of the ENTWSH.Widget component using the script: prefix:
Set objWidget = GetObject("script:\odinwsc$ENTWSHWidget.wsc")
This method cannot be used with compiled COM components written in languages such as VB or C++.
Events
A component can be considered a "black box" that exposes predefined operations and information through properties and methods. An event allows an instance of a component to perform a "call back" to the code that created it. This allows the component to call functions in the host script based on operations that occur in the component.
To create an event, add an element to the body of the element in your script component. An event can contain parameters passed from the component. For each parameter, add a element to the body of each element:
In this sample, an event called FoundFile is defined. The FoundFile event has one parameter called filepath.
No additional code is required in the component itself to support the event-the actual processing of the event operation occurs in the host script.
The following script component, ENTWSH.ListFiles, provides a simple demonstration of events:
The component searches a specified directory and "fires" an event for each file found. A Path property is exposed that identifies the path to search. To perform the search, call the Search method.
The Search method enumerates each file in the specified directory and fires the FoundFile event, which executes a function in the host script. Events are fired using the fireEvent subroutine:
fireEvent strEventName[, parameter1, parameter2, parameterx]
strEventName is the name of the event to fire. The event must be defined in the component's element. If an event requires parameters, they are passed through the parameters parameter1, parameter2, and so on.
To use events in a script, which is known as sinking, use the WScript object's CreateObject method. The term "sinking" refers to the relationship between the object and host script and is analogous to real-world plumbing, where a source supplies water and the sink sucks it away. The object acts as the source, and the host acts as a sink, processing the events from the object. The WScript.CreateObject method takes a second parameter that is used to prefix sinked event function names in the host script.
You want to sink the FoundFile event from the ENTWSH.ListFiles component. If you specify the event prefix to be lf_, you need to create a function called lf_FoundFile in the host script:
'create an instance of the ListFiles component Dim objListFiles Set objListFiles = Wscript.CreateObject ("ENTWSH.ListFiles"," lf_") objListFiles.Path = "d:data" 'set the path to search 'call the search method Call objListFiles.Search Set objListFiles = Nothing 'FoundFile event, this is called for each file found in the search 'directory Sub lf_FoundFile(strPath) Wscript.Echo strPath End Sub
The sample script creates an instance of the ListFiles object. Any event sub-routines are prefixed with _lf. The directory d:data is searched, and for each file found the FoundFile event is fired. This calls the lf_FoundFile routine in the host script, which displays the name of the file.
Event-driven environments can add a layer of complexity to scripts because events may execute segments of code in any given order. An event may call a sub-routine that sets a termination flag, signaling the script to terminate, but it's possible another event may fire after that, changing the termination state.
To stop events from being fired through a specific component, use the WScript.DisconnectObject method:
WScript.DisconnectObject object
The object parameter identifies the object you want to disconnect events from.
Disconnecting an object does not terminate the operation of the component. All properties and methods are still available, but events fired from the object will not be handled in the host script. You can find another event script in Chapter 5, Solution 5.10. It's a more powerful version of the ListFiles object that allows file criteria to be passed as well as performing subdirectory searches.
WSH is not limited to event sinking from script components. Many application objects expose events that WSH can sink. This is demonstrated in Chapter 11, using Internet Explorer events.
Remote Automation
Remote instances of script components (or any other COM component) can be created using WSH, so an instance of script component that resides on computer X can be created from computer Y. This functionality is performed through Distributed COM (DCOM), which is installed with Windows NT, Windows 2000, and Windows 98. Windows 95 requires a separate installation for DCOM.
Creating remote instances does not require any local support objects the component requires. For example, a component may require database support objects or other components not installed on all computers, or a component may require a great deal of processing ability not available on all machines.
To make a component accessible from remote computers, add a remoteable attribute to the element of your script component:
The remotable attribute is a Boolean attribute, and if it is set to True it indicates that remote instances of the component can be created. No special method is required to register the component.
Once registered, the component becomes available through DCOM. A DCOM-enabled object acts like a normal COM component locally, but instances can also be created remotely. There are a number of steps required to create an object on a remote computer. First you need to ensure the component is configured to work correctly under DCOM.
To configure DCOM components, run the DCOM configuration utility dcomcnfg.exe. Dcomcnfg allows different levels of permissions to be assigned to components. Dcomcnfg is included with all recent Windows operating systems except Windows 95, where it is available as a separate download from http://www.microsoft.com/com/dcom/dcom95/dcom1_3.asp.
Dcomcnfg is located under the System32 directory for Windows NT, Windows 2000, and Windows XP, or System for Windows 9x. When run, the program lists all components that are available through DCOM, as shown in Figure 1-6.
Figure 1-6: Listing all components that are available through DCOM
Script components are stored by their description. You can set permissions to determine who can create remote instances.
Note |
Windows 9x/ME machines have limited security settings compared to Windows NT/2000/XP. |
Remote clients require a scripting engine or programming language that supports the creation of remote objects. The latest versions of VBScript (5.0 or later) and JScript support this functionality, which is included with WSH 2.0. If you are using WSH 1.0, either upgrade the scripting engine or install WSH 5.6. If you are creating remote instances using another programming environment, such as VB or C++, you do not need WSH installed on the local client.
Local computers require component registration information. This might seem like a catch-22, because in order to register a component it must be installed locally, which defeats the purpose of DCOM. When a component is registered, information about the component is stored in the registry. This information can be copied to any remote clients that need to create remote instances of the component in question.
The Windows registry editing tool, RegEdit.exe, allows for registry information to be exported to a file, which can then be imported to any remote computers. Component registration information is stored under the HKEY_CLASS_ROOT registry key. The component registration information is stored under the key with the same name as the ProgID for that component, as shown in Figure 1-7.
Figure 1-7: Component registration information
To create a registry text file with component registration information, follow these steps:
- Start RegEdit.
- Select the key you want to export and select File >Export Registry File
- Specify the file to which you want to export the entries. This creates a text file with a .reg extension.
To import the registration information from the .reg file on the client computer, double-click the file from Explorer. You can also run RegEdit from the command prompt by specifying the .reg file as a parameter. Remote instances can be created once the component registration information is stored on the local computer.
Remote instances can only be created using the VBScript CreateObject method. If you require events to be fired, use the WScript.ConnectObject method to sink to the remote object. When you create an instance, specify the name of the remote computer as the second parameter:
'create remote instance of Widget object on computer Odin Set objRem = CreateObject("ENTWSH.Widget", "\Odin") 'set property and display value objRem.Color = "Red" Wscript.Echo objRem.Color Set objRem = Nothing
The component functions exactly like a locally created instance. There can be performance issues as a result of the additional overhead of network traffic and authentication, but if the remote computer is a more powerful machine than the remote client it might run quicker as a result of the increased processing power available on the remote computer.
Advanced Script Component Topics
The WSC Wizard is capable of creating a functional script component quickly, but you may want to tweak the contents of the component logic or bypass the WSC Wizard altogether and manually create script components.
For component properties, you may want to change the name of functions associated with the property. By default, the name is the property name prefixed with either get_ or put_. Setting the internalName attribute for either the or element will change the associated function name:
In this sample, the name of the property exposed through the component is Color, while the internal function associated with the read (get) operation becomes ReadColor, and the write (put) function becomes WriteColor. If the internalName attributes had been omitted, a get_Color and put_Color function would have been used.
If you want to expose a variable as a property for read/write access through the component without any corresponding get_ or put_ function, add a element with a name attribute but no body:
This line would expose a property called Age that would make a script variable of the same name accessible. This needs less code, because it doesn't require any get or put functions, but you cannot perform any of the validation or calculations you could if you used the corresponding get and put functions.
You can assign a different internal variable to the property using the internalName attribute:
Components often return a "default" property or method. If you create a default property, you do not have to specify the property name when retrieving the property value from code.
If you want to make a property or method the default item for a component, assign a dispid attribute to the or element:
The dispid attribute must be set to 0, and it can only be assigned to one property or method per component.
When an error occurs in a script component, a general runtime error is generated from the host script the component was created in. This doesn't give any detailed information about the cause or location of the error. An XML ?component declaration can be added to the component to allow debugging:
The declaration enables/disables error and debug functionality. The element can take optional error and debug attributes. Both attributes accept Boolean values. If the error attribute is set to True, detailed error checking is enabled, and when an error occurs in a component, error information is displayed together with the line number on which the error occurred, which is very useful in tracking down the error.
Setting the debug attribute to True enables debugging. Using the component debugging options is useful during development, but they should be removed when the component is deployed for production use. Window Script Components can use many of the same elements as WSF, such as the reference, resource, comment, package, and object elements.
The "package" element performs similarly in WSF files, allowing multiple components to be stored in a single WSC file.
When storing multiple components in a single WSC file, each component element must include an id attribute identifying the component. This id attribute is not used when creating instances of the component using CreateObject.
WSC can use other XML elements, such as reference, resource, comment, and object, and these elements function the same way they do in WSF files. The following sample component demonstrates the use of these elements:
Set debugging on, reference the FSO type library, create an instance of the FSO object and create a resource. This is a message to write to the file to test a few additional XML elements that can be used
The elements must be outside the script element(s). See the "WSF Files" section for details on the syntax and use of these elements.
Creating Type Libraries
If you intend to use script components in other programming environments, such as Visual Basic or Microsoft Office, it can be useful to create a type library. A type library contains information about a component's properties, methods, and events. The information contained in the type library can be accessed through development environments using object browsers. Some development environments, such as Visual Basic and VBA, provide IntelliSense programming features that allow autocompletion of statements for objects, methods, and properties.
While type libraries make your life easier when you view an object's methods and properties, in some cases type libraries are required in order to implement certain features-for example, if you want to sink component events in Visual Basic.
A type library is easy to create for a script component. From Explorer, right-click the WSC file you want to create a type library for and select the Generate Type Library option.
This action generates a scriptlet.tlb file in the same directory that the WSC file resides. The file should be renamed because it will be overwritten the next time a type library is generated, and this can be a problem as you might overwrite the type library for one component with the contents for another component.
To use the type library from VB, select Project > References. From the VBA development environment, such as recent versions of Microsoft Office applications, select Tools > References (see Figure 1-8).
Figure 1-8: Using the type library
If you look at the References dialog box in Figure 1-8, you will see a problem. If you create a type library for more than one component, multiple instances of the Scriptlet Type Library appear in the References dialog box for each component.
While you can use the file path to determine what object the type library is associated with, it is more convenient to be able to assign a specific name with the type library. Script component type libraries can be created programmatically using methods exposed through the Scriptlet.TypeLib component.
The programming interface allows more control over information associated with the type library, such as description and version information.
To create a type library, create an instance of the object using the ProgID Scriptlet.TypeLib.
Add each component you want to include in the type library using the AddURL method:
objTypeLib.AddURL strURL
The strURL parameter specifies the path to the script component file. It can be a local path, UNC, or URL. Call the method for each script component you want to include. AddURL will not generate any errors if an invalid file path is added, but an error will occur when the type library is generated.
Table 1-3 lists the properties that can be set for the type library.
PROPERTY |
DESCRIPTION |
---|---|
Path |
File path for the type library to create. |
Doc |
Component description. Appears in the References dialog box in VB and VBA development environments. |
GUID |
Assigns a unique GUID to the type library. Not related to the GUID assigned to the component(s) the type library is exposing. If not set, this property will be generated by the component. |
Name |
Component name. Appears in the object browser in the VB and VBA development environments. |
MajorVersion, MinorVersion |
Numeric value that identifies the component's major and minor versions. |
Once the properties have been set, invoke the Write method. The Write method attempts to create the type library entry in the registry. If any properties have been set incorrectly (or not set), errors will occur:
Set objTypeLib = CreateObject("Scriptlet.TypeLib") objTypeLib.AddURL "d:datawshENTWSHWidget.wsc" objTypeLib.Path = "d:datawshENTWSHWidget.tlb" 'set path to type library objTypeLib.Guid = "{fb50eb50-7032-11d4-bce3-00104b164591}" 'the Doc property sets description that appears in References dialog objTypeLib.Doc = "ENTWSH Widget Sample Type library Registry" 'Name sets property that appears in application object browser objTypeLib.Name = "ENTWSHWidget" ' Create the type library objTypeLib.Write
This sample code generates a type library for the WSH Widget component. Adding type library generation code to the Register function of a component's element can automatically create type library information when a component is registered on a computer (see the "Component Registration" section).
It's wise to prefix the Doc and Name properties with a simple, consistent identifier, such as company or component information, because this can make it easier to identify groups of components in the object browser and References dialog box. All WSC components created in this book are prefixed with ENTWSH (Enterprise WSH).
Type libraries can be generated for the same component(s) as many times as you want, and this is often required if additions have been made to the component(s), such as new methods or events that need to be reflected in the object browser.
If you intend to regenerate type libraries, it is wise to set a GUID, even though this is optional. If a GUID is not specified, one is generated by the component, and this will occur each time you regenerate the type library. Every time a type library is added, it adds a new entry to the registry. Even though the old type library registry entries are ignored, they clutter the registry.
If you assign a GUID to a type library, any updates will update the existing type library registry entries. To generate a GUID (never try to guess!) use the WSC Wizard to generate a "dummy" component and copy and paste the GUID into the code.
Streams, Standard Input and Output, and Piping
The ability to manipulate streams is a new feature introduced in WSH 2.0. It is not promoted to the same degree as the WSF files or script components, but it is quite a useful feature that in many ways is as important in providing script reusability.
A stream allows access to file contents and the input or output generated by a physical device, such as a keyboard, or a program. Streams have always been a part of Windows and DOS operating systems, but very few command-line applications use streams. The ability to work with streams has always been an important part of the UNIX environment, where data can be manipulated by stringing together commands such as grep and sed.
Streams are available through the command-line DOS console interface, and they allow data to be passed between files, physical devices, scripts, and other console applications.
To demonstrate how streams work, you will look at how an application would handle streams in WSH 1.0 (which also will work in WSH 2.0) and how it would function if implemented using streams.
You may create a command-line script to perform a specific task. For example, you may want to extract or filter information from a file. In WSH 1.0, you would create a script that would open a file specified by a command-line parameter and send the results to an output file, also specified by a command-line parameter. An example of this could be as follows:
Filter.vbs inputfile outputfile
In the preceding sample, the first parameter represents the input file and the second parameter represents the output file to store the results.
In WSH 2.0, you can send the results to the standard output (StdOut), which is the output stream. Instead of sending the results to an output file, it is written to the standard output instead, which is very similar to writing to a file.
The previous sample program would require no output file as a second parameter—the processed results would be sent to standard output instead. By default, the standard output appears on the standard output device, which is the screen.
If you wanted to send the results to a file, you would redirect them. Redirection is performed by using the redirection symbol, the greater-than sign (>), from the command line:
Filter.vbs inputfile > outputfile
Using ">>" instead of ">" would append the results to a file.
You can pipe standard output results to another command-line application for further processing. Piping allows streams to be passed from one program to another. To pipe information, separate each command with a vertical bar (|). The DOS command-line environment includes a few commands, such as the more and sort programs:
Dir *.* | sort | more
In this example, the results of the dir command are piped to the DOS sort program. The sort program reads the results from the dir command through the standard input stream and sends the sorted results to the more command through standard output. The more command pauses at each full screen of information.
In the filter sample, instead of specifying the contents to filter as a file, you could pipe the results to the filter script:
type inputfile | cscript Filter.vbs inputfile > outputfile
The contents of the input file are piped to the filter.vbs script. The results of the script are then redirected to an output file.
Using pipes, you can string together a number of programs that perform specific tasks to perform sophisticated operations. Pipes are used throughout this book as a method of passing information between scripts. Chapter 6 provides more detailed information on how to work with streams.
Additional Resources
No one book or publication can cover all topics. There are a large number of resources available on the Internet that can complement the information provided in this book. Book errata will be available at the Apress Web site (http://www.apress.com/) as well as http://www.EnterpriseWSH.com/.
Newsgroups are probably the most important source of up-to-date information. The microsoft.public.scripting.wsh newsgroup is your best bet for WSH-related postings. This newsgroup is commonly hosted by ISP news servers, but you can also access it directly by pointing your newsreader at news://msnews.microsoft.com, which guarantees the speediest replies to any queries posted.
Chances are any question you may have has been answered before. Use the newsgroup search engines at http://groups.google.com/ to search newsgroup archives.
The Microsoft Developers Network (MSDN) is an enormous resource for Microsoft-related development material. There's a never-ending supply of articles on the latest technologies, including a scripting-specific site at http://msdn.microsoft.com/scripting.
Finally, there are a number of excellent Web sites that contain large amounts of additional information and scripting samples. The two standouts are Ian Morrish's site http://communities.msn.com/windowsscript and Clarence Washington's Win32Scripting site at http://cwashington.netreach.net/.