<?xml version="1.0" encoding="ISO-8859-1" ?>
<package><component id="main">
<?component error="true" debug="true"?>
<registration progid="WshArgument.Extensions" classid="{790E104C-7A48-499F-8EDA-
6D5CD0A56D93}" description="A WSF argument extension component, focusing on validation."
remotable="no" version="1.0">
<script language="VBScript">
<![CDATA[
Function Register()
With CreateObject("Scriptlet.TypeLib")
.MajorVersion = 1: .MinorVersion = 0
.AddURL "wshargex.wsc"
.Path = "wshargex.tlb": .Name = .Path
.Doc = "A WSF argument extension component, focusing on validation."
.GUID = "{C920CF60-675F-4D7E-87E7-D9076F58BB20}"
.Write: .Reset
End With
End Function
Function Unregister(): End Function
]]></script>
</registration>
<public>
<property get name="IsValid" description="Whether or not the last invocation of ValidateArguments()
returned a valid parse."/>
<property put name="Wsh" description="Object reference to the script host to pass in to the
component."/>
<property get put name="TraceExecution" description=""/>
<property name="JobId" description=""/>
<property get put name="RequireCScript" description=""/>
<property get put name="AllowLooseTyping" description=""/>
<property get put name="ContinueOnFailure" description=""/>
<property get put name="ExitErrorLevel" description=""/>
<property get name="wshArgTypeSimple" description=""/>
<property get name="wshArgTypeBoolean" description=""/>
<property get name="wshArgTypeString" description=""/>
<method name="Simple" description="" internalname="get_Simple">
<parameter name="argName"/>
</method>
<method name="String" description="" internalname="get_String">
<parameter name="argName"/>
<parameter name="defaultValue"/>
</method>
<method name="Boolean" description="" internalname="get_Boolean">
<parameter name="argName"/>
</method>
<method name="ValidateArguments" description=""/>
</public>
<object id="fso" progid="Scripting.FileSystemObject"/>
<object id="xml" progid="MSXML2.DOMDocument"/>
<script language="VBScript"><![CDATA[
Option Explicit
'
' Initialization of global/public variables
'
Const wshArgTypeSimple = 0
Const wshArgTypeBoolean = 11
Const wshArgTypeString = 8
Dim AllowLooseTyping, ContinueOnFailure, ExitErrorLevel
Dim IsValid, JobId, RequireCScript, TraceExecution, Wsh
Initialize()
Sub Initialize()
xml.async = False
AllowLooseTyping = False
ContinueOnFailure = False
ExitErrorLevel = 2
IsValid = vbNull
JobId = vbNullString
RequireCScript = False
Set Wsh = Nothing
TraceExecution = 0
End Sub
function put_Wsh(value)
Set Wsh = value
end function
function get_TraceExecution()
get_TraceExecution = TraceExecution
end function
function put_TraceExecution(value)
TraceExecution = CBool(value)
end function
function get_RequireCScript()
get_RequireCScript = RequireCScript
end function
function put_RequireCScript(value)
RequireCScript = CBool(value)
end function
function get_AllowLooseTyping()
get_AllowLooseTyping = AllowLooseTyping
end function
function put_AllowLooseTyping(value)
AllowLooseTyping = CBool(value)
end function
function get_ContinueOnFailure()
get_ContinueOnFailure = ContinueOnFailure
end function
function put_ContinueOnFailure(value)
ContinueOnFailure = CBool(value)
end function
function get_ExitErrorLevel()
get_ExitErrorLevel = ExitErrorLevel
end function
function put_ExitErrorLevel(value)
ExitErrorLevel = CLng(value)
end Function
function get_IsValid()
get_IsValid = IsValid
end function
function ValidateArguments()
Trace "Entering ValidateArguments()"
' takes a ref to WScript as an argument.
' Proceeds to do full parse and assembly of argument data.
' To make checking IsValid unnecessary if we are NOT using
' the default exit on failure, this function returns True if the
' validation succeeded, false otherwise.
ValidateArguments = False
' We try to die on failures; this ensures that if errors and
' interaction are suppressed, we don't try to validate anyway.
' The fact that this is a function instead of a sub ensures that
' the user can actually TEST the return value without even looking
' at ValidationFailed as described above.
Trace "Checking Whether host is valid."
If Not ValidScriptHost(Wsh) Then Exit Function
Trace "Host is valid."
Trace "Loading script from " & Wsh.ScriptFullName
If Not xml.Load(Wsh.ScriptFullName) Then Exit Function
Trace "Loaded script successfully"
Dim root
if JobId = vbNullString Then
Trace "No job specified, checking all named/unnamed elements."
set root = xml
Else
Trace "job specified: " & JobId
set root = xml.selectSingleNode("//job[@id='" & JobId & "']")
end if
Dim node
Trace "starting named node validation."
For Each node in root.selectNodes("//named")
validateNamed node
Next
Trace "starting unnamed node validation."
validateUnNamed root.selectNodes("//unnamed")
ValidateArguments = IsValid
Trace "Exiting ValidateArguments() at end"
end function
private sub validateNamed(node)
' Look for required named arguments find or Die.
' takes collection of "named" nodes as an argument
dim name, value, nameType
name = NodeAttribValue(node, "name")
Trace "checking named argument node with name " & name
If Wsh.Arguments.Named.Exists(name) Then
Trace "This argument was found on the command line as well"
If Not AllowLooseTyping Then
Trace "We require strict argument types."
' We need to validate argument types.
value = Wsh.Arguments.Named(name)
Trace "The command-line argument's vartype and value: " _
& VarType(value) & " " & value
nameType = tovbVarType( NodeAttribValue(node, "type") )
Trace "The argument spec is for an argument of type: " _
& nameType
If Not VarType(value) = nameType Then Die()
End If
ElseIf CBool( NodeAttribValue(node, "required") ) <> 0 then
Trace "This is a required argument, but it wasn't supplied."
' if required="true", confirm user supplied it or Die.
Die()
' Argument "Typechecking"
end if
end sub
private sub ValidateUnNamed(unnamedNodes)
dim MaxIsMin, required, node
required = 0: MaxIsMin = true
' count required arguments, determine whether this is open number
for each node in unnamedNodes
' see if argument count is unbounded
if toLong(NodeAttribValue(node, "many")) = 1 then MaxIsMin = false
' add the count of required arguments from the unnamed
required = required + toLong(NodeAttribValue( node, "required"))
next
Trace "We require " & required & " unnamed arguments."
Trace "Is the maximum unnamed count the same as minimum? " _
& CStr(MaxIsMin)
'now we test to see if we have enough
dim count: count = Wsh.Arguments.UnNamed.Count
If count < required then
Die()
ElseIf count = required Then
' we're fine - required = count
ElseIf MaxisMin Then
' We have more than the count and shouldn't. Die!
Die()
End If
end sub
private function NodeAttribValue(node, attributeName)
dim Attribute
set Attribute = node.attributes.getNamedItem(attributeName)
if typename(Attribute) = "Nothing" then
NodeAttribValue = Empty
else
NodeAttribValue = Attribute.nodeValue
end if
end function
private function tovbVarType(typeString)
' Casts a named argument type attribute value to a vb VarType value.
' If the type value is not recognized, this returns null.
select case lcase(typeString)
case "boolean" tovbVarType = vbBoolean
case "string" tovbVarType = vbString
case "simple" tovbVarType = vbEmpty
case else tovbVarType = vbNull
end select
end function
private function toLong(value)
' takes any normal numeric or boolean string and coerces to long;
' treats true as +1
if StrComp(value, "false", vbTextCompare) = 0 then
toLong = 0
elseif StrComp(value, "true", vbTextCompare) = 0 then
toLong = 1
else
toLong = CLng( value )
end if
end function
private function ValidScriptHost(host)
' This routine first confirms that the hosting class actually IS
' the WSH host - a necessity for using the WScript.Arguments
' collection at this point, and for throwing a usable error in
' another host. Strictly speaking, this is an ugly hack though.
' Someone could create a class with the name "IHost_Class", and
' a REALLY cool argument parser would take parsed arguments from
' anywhere. All of the validation checks here other than testing
' whether CScript is required as a host are designed to guard
' against accidental misuse by a scripter, not an end-user.
' I don't want to do the work that being cool would require, though.
If RequireCScript And Not HostIsCscript() Then
ValidScriptHost = False
' We're going to abort processing anyway, but let's try to
' Die() first. Trying to Die() will call the help, and then
' the user can see the note that the scripter (hopefully) put
' into the help text about needing cscript for some reason.
Die()
ElseIf Not (TypeName(host) = "IHost_Class") Then
' MsgBox. Ugly again...this is the only way to get the point
' across if an erstwhile user has his or her error display suppressed
' in Internet Explorer.
MsgBox "This class MUST be used from WSH. Currently hosted by:" _
& vbCrLf & TypeName(host)
ValidScriptHost = False
ElseIf host.Version < 5.6 Then
' We aren't going to be able to work on a lesser version of WSH.
' Just to be courteous, we will use WScript.Echo in case this is
' a console session...
Wsh.Echo "This code must be used within a WSF file hosted", _
"in WSH 5.6 or higher with VBScript 5 or higher installed."
Wsh.Echo "The correct version of WSH can be downloaded", _
"from http://msdn.microsoft.com/scripting."
Die()
Else
' We don't require cscript and we are indeed in WSH, so
' we're valid!
ValidScriptHost = True
End If
end function
private sub Die()
Trace "Entering Die()."
Trace "Value of ContinueOnFailure is: " & CStr(ContinueOnFailure)
IsValid = False
if Not ContinueOnFailure then
Trace "We are exiting on failures; you should see help text."
Wsh.Arguments.ShowUsage()
Wsh.Quit(ExitErrorLevel)
End If
end sub
private sub Trace(s)
If TraceExecution Then fso.GetStandardStream(2).WriteLine s
end sub
public function HostIsCscript()
HostIsCscript = _
LCase(Right(Wsh.FullName, 11)) = "cscript.exe"
Trace "Is the host is cscript? " & HostIsCscript
end function
function get_Simple(ByVal argName)
' Returns true/false for whether a simple argument ArgName was specified.
get_Simple = Wsh.Arguments.Named.Exists(argName)
end function
function get_Boolean(ByVal argName)
' Get an optional boolean named argument if it exists;
' if it does not exist, return the default value.
If Wsh.Arguments.Named.Exists(argName) Then
get_Boolean = CBool(argName)
Else
get_Boolean = CBool(defaultValue)
End If
end function
function get_String(ByVal argName, ByVal defaultValue)
' If a string named argument was specified on the script's
' command line, return it. If it wasn't, return a default value.
If Wsh.Arguments.Named.Exists(argName) Then
get_String = WScript.Arguments.Named(argName)
Else
get_String = defaultValue
End If
end function
function get_wshArgTypeSimple
get_wshArgTypeSimple = wshArgTypeSimple
end function
function get_wshArgTypeBoolean
get_wshArgTypeBoolean = wshArgTypeBoolean
end function
function get_wshArgTypeString
get_wshArgTypeString = wshArgTypeString
end function
]]></script>
</component>
</package>