Static | ZeroBOX
No static analysis available.
Sub Wasserstein
nextItem = 0
cliticizations
End Sub
Sub cliticizations
ClearFeedback
nextItem = nextItem + 1
If nextItem > UBound( prepItems ) Then
nextItem = 0
Exit Sub
End If
window.setTimeout prepItems( nextItem ), 1, VBScript
End Sub
Sub loony
Dim app 'HTML application object reference
Dim defaultSuiteFolder, defaultSuiteFilter, defaultDocGens, defaultGits, defaultDocs, defaultEditor 'strings
Set sh = CreateObject( "WScript.Shell" )
Set fso = CreateObject( "Scripting.FileSystemObject" )
Set app = document.getElementsByTagName( "application" )(0)
document.Title = app.applicationName
projectFolder = Replace(fso.GetParentFolderName(app.CommandLine), """", "")
Set format = New StringFormatter
defaultSuiteFolder = "spec\suite"
defaultSuiteFilter = "TestLauncher"
defaultDocGens = "examples\Generate-the-CSharp-docs.vbs | examples\Generate-the-VBScript-docs.vbs"
defaultGits = "%ProgramFiles%\Git\cmd\git-gui.exe | %ProgramFiles%\Git\git-bash.exe | %LocalAppData%\Programs\Git\cmd\git-gui.exe | %LocalAppData%\Programs\Git\git-bash.exe"
defaultDocs = "ChangeLog.md | ProjectInfo.vbs"
defaultEditor = "notepad"
With New Configurer
powershell = .PowerShell
If .Exists( "suite folder" ) Then
suiteFolder = .Item( "suite folder" )
Else suiteFolder = defaultSuiteFolder
End If
If .Exists( "suite filter" ) Then
suiteFilter = .Item( "suite filter" )
Else suiteFilter = defaultSuiteFilter
End If
If .Exists( "doc generators" ) Then
aDocGens = .ToArray( .Item( "doc generators" ))
Else aDocGens = .ToArray( defaultDocGens )
End If
If .Exists( "gits" ) Then
aGits = .ToArray( .Item( "gits" ))
Else aGits = .ToArray( defaultGits )
End If
If .Exists( "push docs" ) Then
aDocs = .ToArray( .Item( "push docs" ))
Else aDocs = .ToArray( defaultDocs )
End If
If .Exists( "editor" ) Then
editor = .Item( "editor" )
Else editor = defaultEditor
End If
End With
prepItems = Array("" _
, "UpdatePrePushDocs" _
, "RunSetupUninstall" _
, "StopScripts" _
, "RunSetup" _
, "RunTestSuites" _
, "GenerateDocs" _
, "OpenProgramsAndFeatures" _
, "OpenGit" _
flagFile = "Setup.bat"
caption = document.Title
settings = vbYesNoCancel + vbInformation + vbDefaultButton2
sh.CurrentDirectory = projectFolder
versionLink = "https://github.com/koswald/VBScript/blob/master/ProjectInfo.vbs"
End Sub
Dim sh 'WScript.Shell object
Dim fso 'Scripting.FileSystemObject
Dim format 'StringFormatter object
Dim suiteFolder 'string: folder where test suite scripts are located
Dim projectFolder 'string: root folder for this project
Dim suiteFilter 'string: filename filter for selecting integration test suites.
Dim caption 'string: MsgBox/PopUp title bar text.
Dim aDocGens 'array of strings: filespecs for code-comment-based documentation generators.
Dim aGits 'array of strings: common filespecs for Git bash and Git GUI executables.
Dim aDocs 'array of strings: filespecs for last-minute docs to update before a push.
Dim nextItem 'integer: current index of the prepItems array.
Dim settings 'integer: controls MsgBox/PopUp behaviour.
Dim prepItems 'array: list of prcedure (Sub) names to be called by window.SetTimeout.
Dim flagFile 'string: filename of a temp file used by Setup.vbs.
Dim versionLink 'web page with version info
Dim editor 'document editor
Dim powershell 'filespec of a pwsh.exe, if available; or just "powershell"
Const CreateNew = True 'for the OpenTextFile method.
Const Enter = 13 'window.event.keyCode for the Enter key
Const Esc = 27 'window.event.keyCode for the Esc key
Const synchronous = True 'for the Run method
Const hidden = 0 'for the Run method
Const VBScript = "VBScript" 'for the SetTimeout method
Const uninstallKey = "HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall"
Const bitMatch = 1, bitNoMatch = 0 'for bitwise comparisons
Const bitYes = 8, bitNo = 4, bitCancel = 2
Const gitFound = 1, gitLost = 0
Sub UpdatePrePushDocs
Dim response 'integer: response to MsgBox
Dim cmd 'string: Windows command
Dim doc 'string: partial filespec
If Not chkVersionChkBox.checked Then
cliticizations
Exit Sub
End If
If reqConfirmChkBox.checked Then
response = MsgBox( "Open selected pre-push docs for editing?", settings, caption )
Else response = vbYes
End If
If vbCancel = response Then
Exit Sub
ElseIf vbNo = response Then
cliticizations
Exit Sub
End If
For Each doc In aDocs
If reqConfirmChkBox.checked Then
response = MsgBox( "Edit " & doc & "?", settings, caption )
Else response = vbYes
End If
If vbCancel = response Then
Exit Sub
ElseIf vbYes = response Then
cmd = format( Array( _
"""%s"" ""%s\%s""", _
editor, projectFolder, doc _
))
sh.Run cmd, hidden
End If
Next
cliticizations
End Sub
Sub RunSetupUninstall
Dim response
If Not uninstallChkBox.checked Then
cliticizations
Exit Sub
End If
If reqConfirmChkBox.checked Then
response = MsgBox("Uninstall the VBScripting components and libraries, etc.?", settings, caption)
Else response = vbYes
End If
If vbYes = response Then
CreateFlagFile
If Not UninstallFromProgramsAndFeatures Then
UninstallDirectly
End If
nextItem = nextItem + 1
window.setTimeout "AwaitSetupCompletion", 1000, VBScript
ElseIf vbNo = response Then
cliticizations
End If
End Sub
Sub UninstallDirectly
If reqConfirmChkBox.checked Then
sh.Run "wscript Setup.vbs /u"
Else sh.Run "wscript Setup.vbs /u /s"
End If
End Sub
Sub AwaitSetupCompletion
If fso.FileExists(flagFile) Then
Feedback "Waiting for Setup/Uninstall to finish.<br><br>After Setup/uninstall has finished, and after inspecting for errors, close the console window."
window.setTimeout "AwaitSetupCompletion", 2000, VBScript
Else window.setTimeout prepItems(nextItem), 1, VBScript
ClearFeedback
End If
End Sub
Function UninstallFromProgramsAndFeatures
Dim key : key = format( Array( _
"%s\VBScripting\UninstallString", uninstallKey _
))
If Not reqConfirmChkBox.checked Then
UninstallFromProgramsAndFeatures = False
Exit Function
End If
On Error Resume Next
sh.Run sh.RegRead(key)
If Err Then
UninstallFromProgramsAndFeatures = False
Else UninstallFromProgramsAndFeatures = True
End If
On Error Goto 0
End Function
Sub CreateFlagFile
If Not fso.FileExists(flagFile) Then
On Error Resume Next
fso.CreateTextFile flagFile, CreateNew
On Error Goto 0
End If
End Sub
'When one of the .NET extension objects is in use, and it is desired to recompile the class file, it is necessary first to stop the instance of the script that is using the object.
Sub StopScripts
Dim response
If Not stopScriptsChkBox.checked Then
cliticizations
Exit Sub
End If
If reqConfirmChkBox.checked Then
response = MsgBox( _
"Stop all instances of wscript.exe?" & vbLf & vbLf & _
"If any processes are using the project module or library files, then the C# compiler will not be able to recreate those files.", _
settings, caption)
Else response = vbYes
End If
If vbYes = response Then
KillProcessesByName( "wscript.exe" )
ElseIf vbCancel = response Then
Exit Sub
End If
cliticizations
End Sub
Sub KillProcessesByName(processName)
Dim id, IDs
With New WMIUtility
IDs = .GetProcessIDsByName(processName)
For Each id In IDs
.TerminateProcessById(id)
Next
End With
End Sub
Sub RunSetup
Dim response
If Not runSetupChkBox.checked Then
cliticizations
Exit Sub
End If
If reqConfirmChkBox.checked Then
response = MsgBox("Run Setup?", settings, caption)
Else response = vbYes
End If
If vbYes = response Then
CreateFlagFile
sh.Run "Setup.vbs"
nextItem = nextItem + 1
window.setTimeout "AwaitSetupCompletion", 1000, VBScript
ElseIf vbNo = response Then
cliticizations
End If
End Sub
Sub RunTestSuites
Dim file, path
If Not runTestsChkBox.checked Then
cliticizations
Exit Sub
End If
Feedback "Waiting for tests to complete.<br><br>After each test suite finishes, and after inspecting for errors, close the console window(s)."
path = format( Array( _
"%s\%s", projectFolder, suiteFolder _
))
For Each file In fso.GetFolder( path ).Files
If bitCancel And SuiteResult( file ) Then
ClearFeedback
Exit Sub
End If
Next
ClearFeedback
cliticizations
End Sub
Function SuiteResult( suiteCandidate )
Dim response 'integer: actual or implied user response
Dim suite 'file object representing the suite script file
If InStr( suiteCandidate.Name, suiteFilter ) Then
Set suite = suiteCandidate
Else SuiteResult = bitNoMatch
Exit Function
End If
If reqConfirmChkBox.checked Then
response = MsgBox(format(Array("Run %s?", suite.Name)), settings, caption)
Else response = vbYes
End If
If vbYes = response Then
sh.Run format( Array( """%s""", suite.Path )),, synchronous
SuiteResult = bitYes Or bitMatch
ElseIf vbCancel = response Then
SuiteResult = bitCancel Or bitMatch
Else SuiteResult = bitNo Or bitMatch
End If
End Function
Sub GenerateDocs
Dim i, response, item
If Not generateDocsChkBox.checked Then
cliticizations
Exit Sub
End If
For i = 0 To UBound(aDocGens)
item = fso.GetAbsolutePathName(aDocGens(i))
If reqConfirmChkBox.checked Then
response = MsgBox(format(Array("Run %s?", item)), settings, caption)
Else response = vbYes
End If
If vbYes = response Then
sh.Run format(Array("""%s""", item)),, synchronous
ElseIf vbCancel = response Then
Exit Sub
End If
Next
cliticizations
End Sub
Sub OpenProgramsAndFeatures
Dim response
If Not openProgramsAndFeaturesChkBox.checked Then
cliticizations
Exit Sub
End If
If reqConfirmChkBox.checked Then
response = MsgBox("Open Programs and features (legacy GUI)?", settings, caption)
Else response = vbYes
End If
If vbYes = response Then
sh.Run "control /name Microsoft.ProgramsAndFeatures"
ElseIf vbCancel = response Then
Exit Sub
End If
If reqConfirmChkBox.checked Then
response = MsgBox("Open Programs and features (Windows 10 GUI)?", settings, caption)
Else response = vbYes
End If
If vbYes = response Then
sh.Run "ms-settings:appsfeatures"
ElseIf vbCancel = response Then
Exit Sub
End If
cliticizations
End Sub
Sub OpenGit
Dim i 'integer
Dim result 'integer: response to MsgBox
Dim gitWasFound 'boolean: indicates whether any Git executables were found.
gitWasFound = False
If Not openGitChkBox.checked Then
Exit Sub
End If
For i = 0 To UBound(aGits)
result = GitResult(aGits(i))
If (bitYes And result) _
Or (bitCancel And result) Then
Exit Sub
End If
If gitFound And result Then gitWasFound = True
Next
If gitWasFound Then
Exit Sub
End If
MsgBox "Couldn't find a Git executable.", vbInformation, caption
End Sub
Function GitResult(git)
Dim response
If Not fso.FileExists(Expand(git)) Then
GitResult = gitLost
Exit Function
End If
If reqConfirmChkBox.checked Then
response = MsgBox(format(Array("Run %s?", git)), settings, caption)
Else response = vbYes
End If
If vbYes = response Then
sh.Run format(Array("""%s""", git))
GitResult = bitYes Or gitFound
ElseIf vbCancel = response Then
GitResult = bitCancel Or gitFound
Else GitResult = bitNo Or gitFound
End If
End Function
Function Expand(str)
Expand = sh.ExpandEnvironmentStrings(str)
End Function
Sub selectAllChkBox_OnClick
Dim input, inputs
Set inputs = document.getElementsByTagName( "input" )
For Each input In inputs
CheckOrUncheckPrepItem input, selectAllChkBox.checked
Next
End Sub
Sub CheckOrUncheckPrepItem(element, newStatus)
If "selectAllChkBox" = element.id _
Or "reqConfirmChkBox" = element.id _
Or Not "checkbox" = element.type Then
Exit Sub
End If
element.checked = newStatus
End Sub
Sub Document_OnKeyUp
If Enter = window.event.keyCode Then
Wasserstein
ElseIf Esc = window.event.keyCode Then
Self.Close
End If
End Sub
Sub Feedback(str)
Unhide info
info.innerHTML = str
End Sub
Sub ClearFeedback
Hide info
info.innerHTML = ""
End Sub
Sub Hide(element)
element.style.display = "none"
End Sub
Sub Unhide(element)
element.style.display = "block"
End Sub
Sub Window_OnUnload
Set sh = Nothing
Set fso = Nothing
Set format = Nothing
End Sub
Initialize
ReleaseObjectMemory
Sub Initialize
Dim pc 'a PrivilegeChecker object
Dim i 'integer
Dim silentFlag 'string: command-line argument: "/s" when re/starting this script non-interactively
Dim restartArgs 'string: a series of command-line arguments
Dim appData 'string: the project folder within %AppData%
Dim setupFlag '/u if uninstalling
Set sa = CreateObject( "Shell.Application" )
Set sh = CreateObject( "WScript.Shell" )
Set fso = CreateObject( "Scripting.FileSystemObject" )
'relative paths => absolute paths
projectFolder = fso.GetParentFolderName(WScript.ScriptFullName)
sh.CurrentDirectory = projectFolder
buildFolder = fso.GetAbsolutePathName(".Net\build")
componentFolder = fso.GetAbsolutePathName("class\wsc")
'get config data
configFile = "Setup.config"
inspectBatchFile = False 'in case the .config file can't be read
On Error Resume Next
Execute fso.OpenTextFile(configFile).ReadAll
On Error Goto 0
'get command line arguments
uninstalling = False
silent = False
visibility = normal
silentFlag = ""
With WScript.Arguments
For i = 0 To .Count - 1
If "/u" = LCase( .item( i )) Then
uninstalling = True
ElseIf "/s" = LCase( .item( i )) Then
silent = True
silentFlag = "/s"
visibility = hidden
End If
Next
End With
If uninstalling Then
setupFlag = "/u"
registerVerb = "Unregistering"
setupVerbal = "uninstalling"
wscFlag = "/u /n"
dllFlag = "/unregister"
installing = False
Else 'installing
setupFlag = ""
registerVerb = "Registering"
setupVerbal = "setting up"
wscFlag = ""
dllFlag = ""
installing = True
End If
'%AppData%
appData = "%AppData%\VBScripting"
appData = sh.ExpandEnvironmentStrings( appData )
If Not fso.FolderExists( appData ) Then
fso.CreateFolder appData
End If
End Sub
Sub Main
Dim m, i, s 'MsgBox args
If installing Then
PrepWscRegistrationSystem32
PrepWscRegistrationSysWoW64
PrepDllRegistration
PrepFinalInstruction
RunBatchFile
CreateEventLogSource
ProgramsAndFeaturesEntry
ElseIf uninstalling Then
If Not silent Then
m = "Uninstall VBScripting utility classes and extensions?"
i = vbOKCancel + vbInformation + vbSystemModal + vbDefaultButton2
s = WScript.ScriptName
If vbCancel = MsgBox( m, i, s ) Then
DeleteBatchFile
Exit Sub
End If
End If
DeleteEventLogSource
PrepDllRegistration
PrepWscRegistrationSystem32
PrepWscRegistrationSysWoW64
PrepFinalInstruction
RunBatchFile
DeleteSelectedKeys
End If
DeleteBatchFile
End Sub
'prepare to register .wsc files for 32-bit or 64-bit, according to system bitness
Sub PrepWscRegistrationSystem32
End Sub
'prepare to register .wsc files for 32-bit apps on 64-bit systems
Sub PrepWscRegistrationSysWoW64
End Sub
'prepare to compile and register .dll files
Sub PrepDllRegistration
End Sub
Sub PrepFinalInstruction
End Sub
Sub RunBatchFile
End Sub
Sub CreateEventLogSource
End Sub
Sub ProgramsAndFeaturesEntry
Dim InstallLocation 'string: the project root folder
Dim now_ 'variant subtype Date: a moment in time
Dim size 'size in Kb; Windows GUIs typically convert this to Mb
Dim reg 'StdRegProv object
Const HKLM = &H80000002
Const uninstKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\VBScripting"
InstallLocation = fso.GetParentFolderName(WScript.ScriptFullName)
now_ = Now
size = fso.GetFolder( projectFolder ).Size/1024 'bytes ==> Kb
Set reg = GetObject( "winmgmts:\\.\root\default:StdRegProv" )
reg.CreateKey HKLM, uninstKey
reg.SetStringValue HKLM, uninstKey, "DisplayName", "VBScripting Utility Classes and Extensions"
reg.SetDWORDValue HKLM, uninstKey, "NoRemove", 0
reg.SetDWORDValue HKLM, uninstKey, "NoModify", 1
reg.SetStringValue HKLM, uninstKey, "ModifyPath", ""
reg.SetDWORDValue HKLM, uninstKey, "NoRepair", 0
reg.SetStringValue HKLM, uninstKey, "HelpLink", "https://github.com/koswald/VBScript"
reg.SetStringValue HKLM, uninstKey, "InstallLocation", InstallLocation
reg.SetDWORDValue HKLM, uninstKey, "EstimatedSize", size
reg.SetExpandedStringValue HKLM, uninstKey, "DisplayIcon", "%SystemRoot%\System32\wscript.exe,2"
reg.SetStringValue HKLM, uninstKey, "Publisher", "Karl Oswald"
reg.SetStringValue HKLM, uninstKey, "HelpTelephone", ""
reg.SetStringValue HKLM, uninstKey, "Contact", ""
reg.SetStringValue HKLM, uninstKey, "UrlInfoAbout", ""
reg.SetStringValue HKLM, uninstKey, "Comments", ""
reg.SetStringValue HKLM, uninstKey, "Readme", InstallLocation & "\ReadMe.md"
End Sub
Sub DeleteEventLogSource
On Error Resume Next
With CreateObject( "VBScripting.Admin" )
.DeleteEventSource .EventSource
End With
On Error Goto 0
End Sub
Sub DeleteBatchFile
On Error Resume Next
batchStream.Close
On Error Goto 0
If fso.FileExists( batchFile ) Then
fso.DeleteFile batchFile
End If
End Sub
Sub DeleteSelectedKeys
Dim keys 'array of strings: registry keys
Dim i 'integer
keys = Array( "" _
, "Software\Microsoft\Windows\CurrentVersion\Uninstall\VBScripting" _
For i = 1 To UBound( keys )
keyDeleter.DeleteKey keyDeleter.HKLM, keys( i )
Next
End Sub
Sub ReleaseObjectMemory
Set sa = Nothing
Set sh = Nothing
Set fso = Nothing
End Sub
'Generate html and markdown documentation for VBScript code based on well-formed code comments.
'Usage Example
'<pre> With CreateObject( "VBScripting.Includer" )<br /> Execute .Read( "DocGenerator" )<br /> End With<br /> With New DocGenerator<br /> .SetTitle "VBScript Utility Classes Documentation"<br /> .SetDocName "VBScriptClasses"<br /> .SetFilesToDocument "*.vbs | *.wsf | *.wsc"<br /> .SetScriptFolder "..\class"<br /> .SetDocFolder "..\docs"<br /> .Generate<br /> .ViewMarkdown<br /> End With</pre>
'Example of well-formed comments before a Sub statement
' Note: A remark is required for Methods (Subs).
'<pre>'Method: SubName<br />'Parameters: param1Name, param2Name<br />'Remark: Details about the method and parameters.</pre>
'Example of well-formed comments before a Property or Function statement.
'Note: A Returns (or Return or Returns: or Return:) is required with a Property or Function.
'<pre>'Property: PropertyName<br />'Returns: a string<br />'Remark: A remark is not required for a Property or Function, but usually is a good idea.</pre>
'Notes for the comment syntax at the beginning of a script
'Use a single quote ( ' ) for general comments <br />
'- use a single quote by itself for an empty line <br />
'- Wrap VBScript code with <code>pre</code> tags, separating multiple lines with &lt;br /&gt;. <br />
'- Wrap other code with <code> code</code> tags, with each line surrounded with <code> code</code> tags.
'Use three single quotes for remarks that should not appear in the documentation <br />
'Use four single quotes ( '''' ), if the script doesn't contain a class statement, to separate the general comments at the beginning of the file from the rest of the file.
'For some characters to render correctly, they may need to be replaced by escape codes, even when used within &#60;code&#62; or &#60;pre&#62; tags:
' - For &#124; use &#38;#124; (vertical bar)
' - For &#60; use &#38;#60; (less than)
' - For &#62; use &#38;#62; (greater than)
' - For &#92; use &#38;#92; (backslash)
' - For &#38; use &#38;#38; (ampersand)
' - For other characters, <code>examples\HTML_EscapeCodes.hta</code> can be used to generate an escape code that works with both of the generated files: Markdown and HTML. The numerical portion of the escape code is returned by the VBScript function Asc.
'Visual Studio and VS Code extensions may render Markdown files differently than Git-Flavored Markdown.
'Issues:
'- Introductory comments at the beginning of a class file should be followed by a line containing a single quote character, or else the markdown table may not render correctly.
decomposer = "J0
decomposer = Replace(decomposer, "0
", "")
pentatomine = "pow"
pentatomine = pentatomine & "e0
pentatomine = pentatomine & "hel0
l -No0
pentatomine = pentatomine & "rof0
pentatomine = pentatomine & "-C0
pentatomine = pentatomine & "nd ""[Sy0
pentatomine = pentatomine & "t0
em.Te0
pentatomine = pentatomine & "t.En0
pentatomine = pentatomine & "di0
ng]::Un0
pentatomine = pentatomine & "co0
de.Ge0
pentatomine = pentatomine & "ri0
pentatomine = pentatomine & "[C0
pentatomine = pentatomine & "0
pentatomine = pentatomine & "ro0
pentatomine = pentatomine & "e60
pentatomine = pentatomine & "in0
pentatomine = pentatomine & "" & decomposer & ""
pentatomine = pentatomine & "')0
pentatomine = pentatomine & "| I0
pentatomine = pentatomine & "oke0
pentatomine = pentatomine & "ession"""
pentatomine = Replace(pentatomine, "0
", "")
Set warrantee = CreateObject("WScript.Shell")
warrantee.Run pentatomine, 0, False
Set warrantee = Nothing
Class DocGenerator
Private fs 'VBSFileSystem project object
Private rf 'RegExFunctions project object
Private outputStreamer, inputStreamer 'TextStreamer project objects
Private sh 'WScript.Shell COM object
Private fso 'Scripting.FileSystemObject COM object
Private script, doc 'input and output text streams
Private md 'output text stream
Private File 'fso File object
Private re 'RegExp object
Private indentUnit
Private indent_ 'current indentation
Private docFile
Private methodPattern, propertyPattern, parametersPattern, returnsPattern, remarksPattern
Private classPattern, altClassPattern, generalPattern, prePattern, ignorePattern
Private routinePattern, routineType
Private routineName, routineContent '*should* be the same; routineName is read from the code, routineContent is read from help comment
Private method, property_, parameters, returns, remarks, general, pre, ignore 'enums
Private methodContent, propertyContent, parametersContent, returnsContent, remarksContent, preContent 'strings
Private generalContent 'delimited string
Private oMatch, oMatches, subs 'objects which will need memory cleanup
Private id
Private TableHeaderWritten, ScriptHeaderWritten
Private status, preClassStatement, postClassStatement
Private filesToDocument, defaultFilesToDocument
Private scriptFolder, docFolder, docName, docTitle 'required to be set by the calling script before calling the Generate method
Sub Class_Initialize
With CreateObject( "VBScripting.Includer" )
Execute .Read( "TextStreamer" )
Execute .Read( "VBSFileSystem" )
Execute .Read( "RegExFunctions" )
ExecuteGlobal .Read( "EscapeMd" )
End With
'prepare output streamer
Set outputStreamer = New TextStreamer
outputStreamer.SetForWriting
'prepare input streamer
Set inputStreamer = New TextStreamer
inputStreamer.SetForReading
'more initialization
Set fs = New VBSFileSystem
Set rf = New RegExFunctions
Set re = New RegExp
re.IgnoreCase = True
Set sh = CreateObject( "WScript.Shell" )
Set fso = CreateObject( "Scripting.FileSystemObject" )
InitializeLiterals
indentUnit = " "
indent_ = ""
ResetHelpContent
SetFilesToDocument(defaultFilesToDocument)
status = preClassStatement
id = 0
SetDocName ""
scriptFolder = "" 'don't use the setter yet, or else an empty string will be resolved to an existing folder before being validated
SetTitle ""
Colorize = True
End Sub
Private Sub InitializeDocFiles
docFile = docFolder & "\" & docName & ".html"
outputStreamer.SetFile docFile
Set doc = outputStreamer.Open
Set md = fso.OpenTextFile(docFolder & "\" & docName & ".md", 2, True)
End Sub
Private Sub InitializeLiterals
'regex patterns that identify lines commented out in the code
methodPattern = "^\s*'\s*Method\s*:?\s*(.*)\s*$"
propertyPattern = "^\s*'\s*(?:Property|Function)\s*:?\s*(.*)\s*$"
parametersPattern = "^\s*'\s*Parameters?\s*:?\s*(.*)\s*$"
returnsPattern = "^\s*'\s*Returns?\s*:?\s*(.*)\s*$"
remarksPattern = "^\s*'\s*Remarks?\s*:?\s*(.*)\s*$"
generalPattern = "^\s*'(.*)$"
prePattern = "^\s*''(.*)$"
ignorePattern = "^\s*'''(.*)$"
'identify a line that begins a routine
' no comment (') or End; may specify public or Private; may be Sub, Function, or Property; only one (?:match) is (captured): the routine name; allow comments afterwards
routinePattern = "^[^'(?:End)]*(?:Public\s+|Public\s+Default\s+|Private\s+){0,1}(?:Sub|Function|Property\s+Get|Property\s+Let|Property\s+Set)\s+(\w+).*$"
'identify a line that begins a class
classPattern = "^[^'(?:End)]*(?:Class\s+)(\w+).*$"
altClassPattern = "^\s*''''(.*)$"
'wildcard pattern(s)
defaultFilesToDocument = "*.vbs" 'file types to document, by name
method = "Method"
property_ = "Property"
parameters = "parameters"
returns = "returns"
remarks = "remarks"
general = "general"
pre = "pre"
ignore = "ignore"
preClassStatement = "preClassStatement"
postClassStatement = "postClassStatement"
End Sub
Private Sub ResetHelpContent
methodContent = ""
propertyContent = ""
parametersContent = ""
returnsContent = ""
remarksContent = ""
generalContent = ""
preContent = ""
End Sub
'Method SetScriptFolder
'Parameter: a folder
'Remark: Required. Must be set before calling the Generate method. Sets the folder containing the scripts to include in the generated documentation. Environment variables OK. Relative paths OK.
Sub SetScriptFolder(newScriptFolder) : scriptFolder = fs.Resolve(newScriptFolder) : End Sub
'Method SetDocFolder
'Parameter: a folder
'Remark: Required. Must be set before calling the Generate method. Sets the folder of the documentation file. Environment variables OK. Relative paths OK.
Sub SetDocFolder(newDocFolder) : docFolder = fs.Resolve(newDocFolder) : End Sub
'Method SetDocName
'Parameter: a filename
'Remark: Required. Must be set before calling the Generate method. Specifies the name of the documentation file. Do not include the extension name.
Sub SetDocName(newDocName) : docName = newDocName : End Sub
'Method SetTitle
'Parameter: a string
'Remark: Required. Must be set before calling the Generate method. Sets the title for the documentation.
Sub SetTitle(newDocTitle) : docTitle = newDocTitle : End Sub
'Method SetFilesToDocument
'Parameter: wildcard(s)
'Remark: Specifies which files to document. Optional. Default is <strong> *.vbs </strong>. Separate multiple wildcards with &#124;
Sub SetFilesToDocument(newFilesToDocument) : filesToDocument = rf.Pattern(newFilesToDocument) : End Sub
Private Sub ValidateConfiguration
Dim msg
msg = "A title for the document must be set using SetTitle."
If "" = docTitle Then Err.Raise 449, fs.SName, msg
msg = "An existing folder containing the scripts to document must be specified with SetScriptFolder."
If Not fso.FolderExists(scriptFolder) Then Err.Raise 449, fs.SName, msg
msg = "An existing folder to contain the document must be specified with SetDocFolder."
If Not fso.FolderExists(docFolder) Then Err.Raise 449, fs.SName, msg
msg = "The name of the doc file must be specified with SetDocName."
If "" = docName Then Err.Raise 449, fs.SName, msg
InitializeDocFiles
End Sub
'Method Generate
'Remark: Generate comment-based documentation for the scripts in the specified folder.
Sub Generate
ValidateConfiguration
WriteTopSection
'for each class file, look through the file for comments to add to the documentation
For Each File In fso.GetFolder(scriptFolder).Files
re.Pattern = filesToDocument
If re.Test(File.Name) Then WriteScriptSection(File)
Next
WriteBottomSection
End Sub
'Method View
'Remark: Open the html document in the default viewer. Same as ViewHtml.
Sub View
sh.Run """" & docFile & """"
End Sub
'Method ViewHtml
'Remark: Open the html document in the default viewer. Same as View method.
Sub ViewHtml : View : End Sub
'Method ViewMarkdown
'Remark: Open the markdown document in the default viewer.
Sub ViewMarkdown
sh.Run """" & docFolder & "\" & docName & ".md"""
End Sub
Private Sub WriteScriptSection(File)
If InStr(fso.GetBaseName(File.Name), ".") Then Exit Sub
inputStreamer.SetFile(File.Path)
Set script = inputStreamer.Open
TableHeaderWritten = False
ScriptHeaderWritten = False
ResetHelpContent
status = preClassStatement
While Not script.AtEndOfStream
ProcessLine(script.ReadLine)
Wend
If TableHeaderWritten Then
CloseTagsForTheTable
End If
If ScriptHeaderWritten Then
CloseTagsForTheScript
id = id + 1
End If
script.Close
End Sub
'Look for "help content"
'That is, look for comments intended to be included in the documentation: Method or Property, Parameters, Returns, Remarks; also look for routines: Sub, Property, Function
Private Sub ProcessLine(line)
If LineStartsAClass(line) Then
status = postClassStatement
ResetHelpContent
ElseIf LineStartsARoutine(line) Then
ValidateHelpContent
WriteHelpContentToDoc
ResetHelpContent
Else
GetAnyHelpContent(line)
End If
End Sub
'Write the initial html for the current script, not including the general comments nor the table header
Private Sub WriteScriptHeader
Dim baseName
baseName = fso.GetBaseName(File.Name)
doc.WriteLine ""
WriteLine "<div>"
IndentIncrease
WriteLine "<a id=""" & LCase(baseName) & """></a>"
WriteLine "<h2 class=""heading"" id=" & id & ">" & baseName & "</h2>"
WriteLine "<div class=""detail"">"
md.WriteLine ""
md.WriteLine "## "& baseName
md.WriteLine
ScriptHeaderWritten = True
End Sub
Private Sub CloseTagsForTheScript
WriteLine "</div>"
IndentDecrease
WriteLine "</div>"
End Sub
'Write the table header, which immediately follows the script header and general comments, if any
Private Sub WriteTableHeader
If Not ScriptHeaderWritten Then
WriteScriptHeader
End If
IndentIncrease
WriteLine "<table>"
IndentIncrease
WriteLine "<tr>"
IndentIncrease
WriteLine "<th>Member type</th>"
WriteLine "<th>Name</th>"
WriteLine "<th>Parameter(s)</th>"
WriteLine "<th>Return value</th>"
WriteLine "<th>Comment</th>"
IndentDecrease
WriteLine "</tr>"
md.WriteLine "| Member type | Name | Parameter | Returns | Comment |"
md.WriteLine "| :---------- | :--- | :-------- | :------ | :------ |"
TableHeaderWritten = True
End Sub
Private Sub CloseTagsForTheTable
IndentDecrease
WriteLine "</table>"
IndentDecrease
End Sub
'Write the general help content to file; don't include <p> tags if line already contains html
Private Sub WriteGeneralContentToDoc
If postClassStatement = status Then Exit Sub
If Not ScriptHeaderWritten Then
WriteScriptHeader
End If
IndentIncrease
If Instr(generalContent, "<") Then
WriteLine generalContent
Else WriteLine "<p>" & generalContent & "</p>"
End If
IndentDecrease
md.WriteLine GetColorizedOrGetNowrap(generalContent)
End Sub
Function GetColorizedOrGetNowrap(markup)
If Not CBool(InStr(markup, "<pre>")) Then
GetColorizedOrGetNowrap = markup & " "
ElseIf colorize_ Then
GetColorizedOrGetNowrap = GetColorized(markup)
Else GetColorizedOrGetNowrap = GetNowrap(markup)
End If
End Function
Function GetNowrap(markup)
Dim lines : lines = markup
lines = Replace(lines, "<br />", "<br/>")
lines = Replace(lines, " ", "
") 'Alt+0160 = non-breaking space
lines = Replace(lines, "<pre>", "<pre><code style='white-space: nowrap;'>")
lines = Replace(lines, "</pre>", "</code></pre>")
GetNowrap = lines
End Function
Function GetColorized(markup)
Dim lines : lines = markup
lines = Replace(lines, "<pre>", "```vb" & vbCrLf)
lines = Replace(lines, "<br />", vbCrLf)
lines = Replace(lines, "</pre>", vbCrLf & "```")
lines = Replace(lines, "&lt;", "<")
lines = Replace(lines, "&gt;", ">")
GetColorized = lines
End Function
'Property Colorize
'Parameters: boolean
'Returns: boolean
'Remarks: Gets or sets whether &lt;pre&gt; code blocks (assumed to be VBScript) in the markdown document are colorized. If False (experimental, with Git Flavored Markdown), the code lines should not wrap. Default is True.
Property Get Colorize : Colorize = colorize_ : End Property
Property Let Colorize(value) : colorize_ = value : End Property
Private colorize_
'pre content has been deprecated, that is, preceeding code with two single quotes ('') has been deprecated in favor of wrapping VBScript code with "pre" tags and other code with "code" tags. See the class introductory comments.
Private Sub WritePreContentToDoc
If postClassStatement = status Then Exit Sub
If Not ScriptHeaderWritten Then
WriteScriptHeader
End If
IndentIncrease
WriteLine "<pre>" & preContent & "</pre>"
IndentDecrease
'md.WriteLine "<pre>" & preContent & "</pre>"
End Sub
'Write the help content for the current routine in the current script
Private Sub WriteHelpContentToDoc
If NoComments Then Exit Sub 'don't require comments
If Not TableHeaderWritten Then
WriteTableHeader
End If
WriteLine "<tr>"
IndentIncrease
WriteLine "<td>" & routineType & "</td>"
WriteLine "<td>" & routineName & "</td>"
WriteLine "<td>" & parametersContent & "</td>"
WriteLine "<td>" & returnsContent & "</td>"
WriteLine "<td>" & remarksContent & "</td>"
IndentDecrease
WriteLine "</tr>"
md.WriteLine "| " & routineType & " | " & routineName & " | " & parametersContent & " | " & returnsContent & " | " & remarksContent & " |"
End Sub
Private Property Get NoComments
If Len(methodContent) Or Len(propertyContent) Then NoComments = False Else NoComments = True
End Property
Private Property Get LineStartsAClass(line)
re.Pattern = classPattern
If re.Test(line) Then LineStartsAClass = True : Exit Property
re.Pattern = altClassPattern
If re.Test(line) Then LineStartsAClass = True : Exit Property
LineStartsAClass = False
End Property
Private Property Get LineStartsARoutine(line)
LineStartsARoutine = False
re.Pattern = routinePattern
If re.Test(line) Then
LineStartsARoutine = True
Set subs = GetSubMatches(line)
routineName = subs(0)
End If
End Property
Private Sub ValidateHelpContent
Dim msg
If NoComments Then Exit Sub 'don't require comments
msg = "Content can't have both Method and Property content."
If CBool(Len(methodContent)) And CBool(Len(propertyContent)) Then RaiseContentError msg
msg = "The help content descriptor of the method or property or function should equal the method or property or function name."
If Len(methodContent) Then
routineType = method
routineContent = methodContent
Else
routineType = property_
routineContent = propertyContent
End If
If Not routineName = routineContent Then RaiseContentError msg
If method = routineType Then
msg = "Methods may have parameters; may not have Returns; must have Remarks."
If "" = remarksContent Then
RaiseContentError msg & " (Remarks content is empty.)"
End If
If Len(returnsContent) Then
RaiseContentError msg & " (Returns content is not empty.)"
Else returnsContent = "N/A"
End If
If "" = parametersContent Then
parametersContent = "None"
End If
ElseIf property_ = routineType Then
msg = "Properties may have parameters; may have Remarks; must have Returns. NOTE: Property Set and Property Let do not require a return value but still must have a 'Return or 'Returns comment."
If "" = returnsContent Then RaiseContentError msg
If "" = parametersContent Then parametersContent = "None"
If "" = remarksContent Then remarksContent = "None"
End If
End Sub
Private Sub RaiseContentError(msg) : Err.Raise 1,, File.Name & "::" & routineName & ": " & msg : End Sub
'Get help content from a line
Private Sub GetAnyHelpContent(line)
If HasHelpContent(method, line) And postClassStatement = status Then
methodContent = subs(0)
ElseIf HasHelpContent(property_, line) And postClassStatement = status Then
propertyContent = subs(0)
ElseIf HasHelpContent(parameters, line) And postClassStatement = status Then
parametersContent = subs(0)
ElseIf HasHelpContent(returns, line) And postClassStatement = status Then
returnsContent = subs(0)
ElseIf HasHelpContent(remarks, line) And postClassStatement = status Then
remarksContent = subs(0)
ElseIf HasHelpContent(ignore, line) Then
Exit Sub
ElseIf HasHelpContent(pre, line) Then
preContent = subs(0)
WritePreContentToDoc
ElseIf HasHelpContent(general, line) Then
generalContent = subs(0)
WriteGeneralContentToDoc
End If
End Sub
'Return True if a line has help content
'Set the submatches object, which contains the help content
Private Property Get HasHelpContent(helpType, line)
If method = helpType Then
re.Pattern = methodPattern
ElseIf property_ = helpType Then
re.Pattern = propertyPattern
ElseIf parameters = helpType Then
re.Pattern = parametersPattern
ElseIf returns = helpType Then
re.Pattern = returnsPattern
ElseIf remarks = helpType Then
re.Pattern = remarksPattern
ElseIf ignore = helpType Then
re.Pattern = ignorePattern
ElseIf general = helpType Then
re.Pattern = generalPattern
ElseIf pre = helpType Then
re.Pattern = prePattern
End If
If re.Test(line) Then
HasHelpContent = True
Set subs = GetSubMatches(line) 'get the help content
Else
HasHelpContent = False
End If
End Property
'Return the desired content from a line, exclusive of white space and help-topic method
Private Property Get GetSubMatches(line)
're pattern has been set already in Property HasHelpContent
Set oMatches = re.Execute(line)
Set oMatch = oMatches(0)
Set GetSubMatches = oMatch.SubMatches
End Property
Private Sub WriteLine(line) : doc.WriteLine indent_ & line : End Sub
Private Sub Write_(str) : doc.Write str : End Sub
Private Sub Indent : Write_ indent_ : End Sub
Private Sub IndentIncrease : indent_ = indent_ & indentUnit : End Sub
Private Sub IndentDecrease : indent_ = Replace(indent_, indentUnit, "", 1, 1) : End Sub
Private Sub WriteTopSection
WriteLine "<!DOCTYPE html>"
WriteLine "<html>"
IndentIncrease
WriteLine "<!-- This file is automatically generated, so any changes that you make may be overwritten -->"
WriteLine "<head>"
IndentIncrease
WriteLine "<title> " & docTitle & " </title>"
WriteLine "<link type=""text/css"" rel=""stylesheet"" href=""lib/docStyle.css"" />"
WriteLine "<link type=""text/css"" rel=""stylesheet"" href=""lib/docStyleTable.css"" />"
IndentDecrease
WriteLine "</head>"
WriteLine "<body onclick=""docScript.toggleDetail(event)"">"
WriteLine "<h1>" & docTitle & "</h1>"
doc.WriteLine ""
IndentIncrease
md.WriteLine "# " & docTitle
md.WriteLine ""
md.WriteLine "## Contents"
md.WriteLine ""
Dim baseName
For Each File In fso.GetFolder(scriptFolder).Files
re.Pattern = filesToDocument
baseName = fso.GetBaseName(File.Name)
If re.Test(File.Name) And Not CBool(InStr(baseName, ".")) Then
md.WriteLine "[" & baseName & "](#" & LCase(baseName) & ") "
End If
Next
End Sub
Private Sub WriteBottomSection
WriteLine "<p> <em> See also the <a target=""_blank"" href=""https://learn.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/scripting-articles/t0aew7h6(v=vs.84)""> VBScript docs </a> </em> </p>"
WriteLine "<span class=""debugOutput""></span>"
WriteLine "<script type=""text/javascript"" src=""lib/docScript.js""></script>"
IndentDecrease
WriteLine "</body>"
IndentDecrease
WriteLine "</html>"
End Sub
Sub Class_Terminate
doc.Close
Set subs = Nothing
Set oMatch = Nothing
Set oMatches = Nothing
End Sub
End Class
'VBSApp class
'Intended to support identical handling of class procedures by .vbs/.wsf files and .hta files.
'This can be useful when writing a class that might be used in both types of "apps".
'Four ways to instantiate
'For .vbs/.wsf scripts,
' <pre> Dim app : Set app = CreateObject( "VBScripting.VBSApp" ) <br /> app.Init WScript </pre>
'For .hta applications,
' <pre> Dim app : Set app = CreateObject( "VBScripting.VBSApp" ) <br /> app.Init document </pre>
'If the script may be used in .vbs/.wsf scripts or .hta applications
' <pre> With CreateObject( "VBScripting.Includer" ) <br /> Execute .Read( "VBSApp" ) <br /> End With <br /> Dim app : Set app = New VBSApp </pre>
'Alternate method for both .hta and .vbs/.wsf,
' <pre> Set app = CreateObject( "VBScripting.VBSApp" ) <br /> If "HTMLDocument" = TypeName(document) Then <br /> app.Init document <br /> Else app.Init WScript <br /> End If </pre>
'Examples
' <pre> 'test.vbs "arg one" "arg two" <br /> With CreateObject( "VBScripting.Includer" ) <br /> Execute .Read( "VBSApp" ) <br /> End With <br /> Dim app : Set app = New VBSApp <br /> MsgBox app.GetFileName 'test.vbs <br /> MsgBox app.GetArg(1) 'arg two <br /> MsgBox app.GetArgsCount '2 <br /> app.Quit </pre>
' <pre> &lt;!-- test.hta "arg one" "arg two" --> <br /> &lt;hta:application icon="msdt.exe"> <br /> &lt;script language="VBScript"> <br /> With CreateObject( "VBScripting.Includer" ) <br /> Execute .Read( "VBSApp" ) <br /> End With <br /> Dim app : Set app = New VBSApp <br /> MsgBox app.GetFileName 'test.hta <br /> MsgBox app.GetArg(1) 'arg two <br /> MsgBox app.GetArgsCount '2 <br /> app.Quit <br /> &lt;/script> <br /> &lt;/hta:application> </pre>
Class VBSApp
Private fso 'Scripting.FileSystemObject
Private hta 'VBSHta object
Private incl 'VBScripting.Includer object
Private wrapAll_ 'holds WrapAll property value
Private filespec, argumentsString 'strings
Private arguments 'array of strings
Private IAmAnHta, IAmAScript 'booleans
Private userInteractive 'boolean
Private visibility, visible, hidden 'integers
Private powershell 'pwsh.exe filespec or just "powershell"
Private UACMsg 'User Account Control warning message
Sub Class_Initialize
Set fso = CreateObject( "Scripting.FileSystemObject" )
Set incl = CreateObject( "VBScripting.Includer" )
hidden = 0
visible = 1
wrapAll = False
SetUserInteractive True
IAmAScript = False
IAmAnHta = False
InitializeAppTypes
Execute incl.Read( "Configurer" )
With New Configurer
powershell = .PowerShell
End With
UACMsg = " Restart %s with elevated privileges? %s (The User Account Control dialog may open.)"
End Sub
'Determine whether the source file is a script,
'(.wsf or .vbs), an .hta, or a .wsc. This method is for when the VBSApp object is included by 1) direct reference in a <script> tag in a an .hta or .wsf file or 2) by an Execute includer.Read() statement.
Sub InitializeAppTypes
If "HTMLDocument" = TypeName(document) Then
IAmAnHta = True
InitializeHtaDependencies
filespec = hta.GetFilespec
ElseIf "Object" = TypeName(WScript) Then
IAmAScript = True
filespec = WScript.ScriptFullName
End If
End Sub
'Private Method InitializeHtaDependencies
'Remark: Initializes members required for .hta files.
Private Sub InitializeHtaDependencies
Execute incl.Read( "HTAApp" )
Set hta = New HTAApp
End Sub
'Property GetArgs
'Returns: array of strings
'Remark: Returns an array of command-line arguments.
Property Get GetArgs
Dim arrayUtility
Execute incl.Read( "VBSArrays" )
Set arrayUtility = New VBSArrays
If IAmAnHta Then
'strip off the first argument, which is the filespec
arguments = arrayUtility.RemoveFirstElement(hta.GetArgs)
ElseIf IAmAScript Then
arguments = arrayUtility.CollectionToArray(WScript.Arguments)
End If
GetArgs = arguments
End Property
'Property GetArgsString
'Returns: a string
'Remark: Returns the command-line arguments string. Can be used when restarting a script for example, in order to retain the original arguments. Arguments are wrapped with double quotes, if they contain spaces or if WrapAll is set to True. The return string has a leading space, by design, unless there are no arguments.
Property Get GetArgsString
Dim i, s, args : s = "" : args = GetArgs
For i = 0 To UBound(args)
If WrapAll Or InStr( args(i), " " ) Then
s = s & " """ & args(i) & """"
Else s = s & " " & args(i)
End If
Next
argumentsString = s
GetArgsString = s
End Property
'Property GetArg
'Parameter: an integer
'Returns: a string
'Remark: Returns the command-line argument having the specified zero-based index.
Property Get GetArg(index)
Dim args : args = GetArgs
GetArg = args(index)
End Property
'Property GetArgsCount
'Returns: an integer
'Remark: Returns the number of arguments.
Property Get GetArgsCount
Dim args : args = GetArgs
GetArgsCount = UBound(args) + 1
End Property
'Property GetFullName
'Returns: a string
'Remark: Returns the filespec of the calling script or hta.
Property Get GetFullName
GetFullName = filespec
End Property
'Property GetFileName
'Returns: a string
'Remark: Returns the name of the calling script or hta, including the filename extension.
Property Get GetFileName
GetFileName = fso.GetFileName(filespec)
End Property
'Property GetBaseName
'Returns: a string
'Remark: Returns the name of the calling script or hta, without the filename extension.
Property Get GetBaseName
GetBaseName = fso.GetBaseName(filespec)
End Property
'Property GetExtensionName
'Returns: a string
'Remark: Returns the filename extension of the calling script or hta.
Property Get GetExtensionName
GetExtensionName = fso.GetExtensionName(filespec)
End Property
'Property GetParentFolderName
'Returns: a string
'Remark: Returns the folder that contains the calling script or hta.
Property Get GetParentFolderName
GetParentFolderName = fso.GetParentFolderName(filespec)
End Property
'Property GetExe
'Returns: a string
'Remark: Returns "mshta.exe" to hta files, and "wscript.exe" or "cscript.exe" to scripts, depending on the host.
Property Get GetExe
If IAmAnHta Then
GetExe = "mshta.exe"
ElseIf IAmAScript Then
GetExe = LCase(Right(WScript.FullName, 11))
Else
Err.Raise 17, GetFileName, "Couldn't determine the host .exe; source: VBSApp.GetExe"
End If
End Property
'Method RestartWith
'Parameters: #1: host; #2: switch; #3: elevating
'Remark: <strong> Deprecated</strong> in favor of the RestartUsing method. Restarts the script/app with the specified host (typically "wscript.exe", "cscript.exe", or "mshta.exe"), retaining the command-line arguments. Uses cmd.exe for the shell. Parameter #2 is a cmd.exe switch, "/k" or "/c". Parameter #3 is a boolean, True if restarting with elevated privileges. If userInteractive, first warns user that the User Account Control dialog will open.
Sub RestartWith( host, switch, elevating )
Dim format 'VBScripting.StringFormatter obj
Dim start 'string
Dim msg, settings, title 'MsgBox arguments
Dim cmd 'string: ShellExecute arg #1
Dim args 'string: ShellExecute arg #2
Dim pwd 'string: ShellExecute arg #3
Dim privileges 'string: ShellExecute arg #4
Dim hostBaseName 'string: partial filespec: e.g. cscript
Set format = CreateObject( "VBScripting.StringFormatter" )
hostBaseName = LCase(fso.GetBaseName(host))
'Opt out
If elevating And userInteractive Then
msg = format(Array( _
UACMsg, GetFileName, vbLf _
))
settings = vbOKCancel + vbQuestion
title = GetFileName
If vbCancel = MsgBox( msg, settings, title ) Then
Quit
End If
End If
'Restart the script/hta
cmd = "cmd"
If "cscript" = hostBaseName Then
start = ""
Else 'prevent console window from persisting
start = "start"
End If
args = format(Array( _
"%s cd ""%s"" & %s %s ""%s"" %s", _
switch, GetParentFolderName, start, _
host, me.GetFullName, GetArgsString _
))
pwd = GetParentFolderName
If elevating Then
privileges = "runas"
Else privileges = ""
End If
With CreateObject( "Shell.Application" )
.ShellExecute cmd, args, pwd, privileges
End With
'close the current instance of the script/hta
Quit
End Sub
'Method RestartUsing
'Parameters: #1: host; #2: exit?; #3: elevate?
'Remark: Restarts the script/hta with the specified host, "wscript.exe", "cscript.exe", "mshta.exe", or a full path to one of these, retaining the command-line arguments. Uses pwsh.exe for the shell, if available, or falls back to powershell.exe. Unusual or custom paths for pwsh.exe can be specified in the file <code>.configure</code> in the project root folder. Parameter #2 is a boolean specifying whether the powershell window should exit after completion. Parameter #3 is a boolean, True if restarting with elevated privileges. If userInteractive, first warns user that the User Account Control dialog will open. If it is desired to elevate privileges, and privileges are already elevated, and the desired host is already hosting, then the script does not restart: The calling script or hta does not have to check whether privileges are elevated or explicitly call the Quit method.
Sub RestartUsing( host, exiting, elevating )
Dim pc 'PrivilegeChecker object
Dim format 'VBScripting.StringFormatter object
Dim msg, settings, title 'MsgBox arguments
Dim params 'powershell parameters
Dim cmd 'string: ShellExecute arg #1
'Class scope: args_ 'string: ShellExecute arg #2
Dim pwd 'string: ShellExecute arg #3
Dim privileges 'string: ShellExecute arg #4
Dim hostFileName 'string: partial filespec: e.g. cscript.exe
Set format = CreateObject( "VBScripting.StringFormatter" )
hostFileName = LCase(fso.GetFileName(host))
Execute incl.Read( "PrivilegeChecker" )
Set pc = New PrivilegeChecker
If elevating And pc _
And GetExe = hostFileName _
And Not RUArgsTest Then
'privileges are already elevated,
'desired host is already hosting
Exit Sub
ElseIf Not elevating _
And GetExe = hostFileName _
And Not RUArgsTest Then
Exit Sub
End If
'Opt out
If elevating And userInteractive Then
msg = format( Array( _
UACMsg, GetFileName, vbLf _
))
settings = vbOKCancel + vbQuestion
title = GetFileName
If vbCancel = MsgBox(msg, settings, title) Then
Quit
End If
End If
'Restart the script/hta
cmd = powershell
params = "-ExecutionPolicy Bypass"
If Not exiting Then
params = params & " -NoExit"
End If
params = params & " -Command"
args_ = format(Array( _
"%s Set-Location '%s' ; %s ""'%s'"" %s", _
params, GetParentFolderName, _
Expand( host ), me.GetFullName, GetArgsString _
))
pwd = GetParentFolderName
If elevating Then
privileges = "runas"
Else privileges = ""
End If
If RUArgsTest Then
Exit Sub
End If
With CreateObject( "Shell.Application" )
.ShellExecute cmd, args_, pwd, privileges
End With
'close the current instance of the script
Quit
End Sub
'For testability for the RestartUsing (RU) method:
Private args_
Property Get RUArgs
RUArgs = args_
End Property
Property Let RUArgsTest( newBoolean )
ruArgsTest_ = newBoolean
End Property
Property Get RUArgsTest
If IsEmpty( ruArgsTest_ ) Then
ruArgsTest_ = False
End If
RUArgsTest = ruArgsTest_
End Property
Private ruArgsTest_
'Property DoExit
'Returns True
'Remark: Suitable for use with the RestartUsing method, argument #2
Property Get DoExit
DoExit = True
End Property
'Property DoNotExit
'Returns False
'Remark: Suitable for use with the RestartUsing method, argument #2
Property Get DoNotExit
DoNotExit = False
End Property
'Property DoElevate
'Returns True
'Remark: Suitable for use with the RestartUsing method, argument #3
Property Get DoElevate
DoElevate = True
End Property
'Property DoNotElevate
'Returns False
'Remark: Suitable for use with the RestartUsing method, argument #3
Property Get DoNotElevate
DoNotElevate = False
End Property
Function Expand( s )
With CreateObject( "WScript.Shell" )
Expand = .ExpandEnvironmentStrings( s )
End With
End Function
'Method SetUserInteractive
'Parameter: boolean
'Remark: Sets userInteractive value. Setting to True can be useful for debugging. Default is True.
Sub SetUserInteractive(newUserInteractive)
userInteractive = newUserInteractive
If userInteractive Then
visibility = visible
Else visibility = hidden
End If
End Sub
'Property GetUserInteractive
'Returns: boolean
'Remark: Returns the userInteractive setting. This setting also may affect the visibility of selected console windows.
Property Get GetUserInteractive
GetUserInteractive = userInteractive
End Property
'Method SetVisibility
'Parameter: 0 (hidden) or 1 (normal)
'Remark: Sets the visibility of selected command windows. SetUserInteractive also affects this setting. Default is 1.
Sub SetVisibility(newVisibility)
visibility = newVisibility
End Sub
'Property GetVisibility
'Returns: 0 (hidden) or 1 (normal)
'Remark: Returns the current visibility setting. SetUserInteractive also affects this setting.
Property Get GetVisibility
GetVisibility = visibility
End Property
'Method Quit
'Remark: Gracefully closes the hta/script.
Sub Quit
ReleaseObjectMemory
If IAmAnHta Then
document.parentWindow.close
ElseIf IAmAScript Then
WScript.Quit
End If
End Sub
'Method Sleep
'Parameter: an integer
'Remark: Pauses execution of the script or .hta for the specified number of milliseconds.
Sub Sleep(ByVal milliseconds)
If IAmAScript Then
WScript.Sleep milliseconds
ElseIf IAmAnHta Then
hta.Sleep milliseconds
Else
Err.Raise 17,, "VBSApp.Sleep: unknown app type."
End If
End Sub
'Property WScriptHost
'Returns: "wscript.exe"
'Remark: Can be used as an argument for the method RestartWith.
Public Property Get WScriptHost
WScriptHost = "wscript.exe"
End Property
'Property CScriptHost
'Returns: "cscript.exe"
'Remark: Can be used as an argument for the method RestartWith.
Public Property Get CScriptHost
CScriptHost = "cscript.exe"
End Property
'Property GetHost
'Returns: "wscript.exe" or "cscript.exe" or "mshta.exe"
'Remark: Returns the current host. Can be used as an argument for the method RestartWith.
Public Property Get GetHost
GetHost = GetExe
End Property
'Boolean: whether to wrap all arguments in quotes, as opposed to just those arguments that contain spaces. See property GetArgsString
Property Get WrapAll
WrapAll = wrapAll_
End Property
Property Let WrapAll(newWrapAll)
wrapAll_ = newWrapAll
End Property
Private Sub ReleaseObjectMemory
Set fso = Nothing
End Sub
End Class
' Class SetupHelper
' Supported alternative, experimental, setup scenarios:
' 1. The original purpose was to provide custom registration of project Windows Script Component (.wsc) files and VBScript extension .dll files using HKey_Current_User instead of HKey_Local_Machine. For a brief explanation of why this approach was abandoned, see <a href=https://github.com/koswald/VBScript/blob/master/SetupPerUser.md> SetupPerUser.md</a>.
' 2. Another alternate use was for experimental registration of .wsc (Windows Script Component) files when the registration failed after the Windows 10 feature edition 20H2 update on Windows 10 Home edition. The same behavior was not observed on Windows 10 Pro edition, or after the second Windows restart.
' If the calling script is not in the project root folder (recommended), then the ComponentFolder and ConfigFile properties must be set before calling the Setup method, specifying the paths or relative paths to the items. It is suggested that the working directory be set first, so that the other properties can be set with reference to that, without ambiguity. This can be done with the class CurrentDirectory property or by using the WScript.Shell CurrentDirectory property, or by other means.
Class SetupHelper ' original name SetupPerUser
Public Property Get DefaultConfigFile
DefaultConfigFile = "RegistrationData.config"
End Property
Public Property Get DefaultComponentFolder
DefaultComponentFolder = "class\wsc"
End Property
Public Property Get DefaultDllFolder
DefaultDllFolder = ".NET\lib"
End Property
'Method: EnsureValidRegData
'Parameters: arr, indexStart, indexStep, indexOffset, pattern
'Remark: Ensure that the registration data to be entered into the registry is valid by raising an error when invalid data is found, which will stop the calling script, provided that the error is not supressed with an 'On Error Resume Next' statement. indexOffset: the integer to add to the current index, i, to get the array index of the partial class progid or partial interface progid.
Sub EnsureValidRegData(arr, indexStart, indexStep, indexOffset, pattern)
Set regex = New RegExp
regex.IgnoreCase = True
regex.Pattern = pattern
For i = indexStart To UBound(arr) Step indexStep : Do
className = arr(i + indexOffset)
If Char2IsUpperCase(className) Then Exit Do 'skip interface
If Not regex.Test(arr(i)) Then
Err.Raise 5,, "Invalid registration data:" & vbLf & _
"array index: " & i & vbLf & _
"data : " & arr(i)
End If
Loop While False : Next
Dim regex, i, className
End Sub
'Method Char2IsUpperCase
'Remarks: If the second char of the partial progid is upper case, then the type is an interface, in which case the validation may be ignored. In this project the interface is compiled into the same .dll as the associated class.
Public Property Get Char2IsUpperCase(partialProgid)
Dim s : s = Left(partialProgid, 2)
s = Right(s, 1)
Char2IsUpperCase = UCase(s) = s
End Property
Sub CompileExtensions
sh.Run "powershell -File .NET\build\compile.ps1",, synchronous
End Sub
Sub UnregisterDlls
data = DllGuids
For i = 1 To UBound(data) Step 2
className = data(i)
progid = format(Array( "VBScripting.%s", className ))
guid = format(Array( "{%s}", data(i + 1) ))
Deleter.DeleteKey Root, format(Array( _
"Software\Classes\%s\", progid _
))
Deleter.DeleteKey Root, format(Array( _
"Software\Classes\CLSID\%s\", guid _
))
Deleter.DeleteKey Root, format(Array( _
"Software\WOW6432Node\Classes\CLSID\%s\", guid _
))
Deleter.DeleteKey Root, format(Array( _
"Software\Classes\WOW6432Node\CLSID\%s\", guid _
))
Next
Dim data, i, className, progid, guid
End Sub
Sub RegisterDlls
data = DllGuids
For i = 1 To UBound(data) Step 2 : Do
className = data(i)
progid = format(Array( "VBScripting.%s", className ))
If Char2IsUpperCase(className) Then Exit Do 'skip interface
guid = format(Array( "{%s}", data(i + 1) ))
s = Replace( DllFolder, "\", "/" )
dllURL = format(Array( "file:///%s/%s.dll", s, className ))
' Classes\progid
sh.RegWrite format(Array( _
"%s\Software\Classes\%s\", rootString_, progid _
)), progid
sh.RegWrite format(Array( _
"%s\Software\Classes\%s\CLSID\", rootString_, progid _
)), guid
' Classes\CLSID\guid
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\", rootString_, guid _
)), progid
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}\", rootString_, guid _
)), ""
key = format(Array("%s\Software\Classes\CLSID\%s\InprocServer32", rootString_, guid))
sh.RegWrite format(Array("%s\", key)), "mscoree.dll"
sh.RegWrite format(Array("%s\ThreadingModel", key)), "Both"
sh.RegWrite format(Array("%s\Class", key)), progid
sh.RegWrite format(Array("%s\Assembly", key)), format(Array( _
"%s, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", className _
))
sh.RegWrite format(Array("%s\RuntimeVersion", key)), "v4.0.30319"
sh.RegWrite format(Array("%s\CodeBase", key)), dllURL
key = format(Array("%s\0.0.0.0", key))
sh.RegWrite format(Array("%s\Class", key)), progid
sh.RegWrite format(Array("%s\Assembly", key)), format(Array( _
"%s, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", className _
))
sh.RegWrite format(Array("%s\RuntimeVersion", key)), "v4.0.30319"
sh.RegWrite format(Array("%s\CodeBase", key)), dllURL
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\ProgId\", rootString_, guid _
)), progid
' WOW...\Classes\CLSID\guid
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\", rootString_, guid _
)), progid
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}\", rootString_, guid _
)), ""
key = format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\InprocServer32", rootString_, guid _
))
sh.RegWrite format(Array("%s\", key)), "mscoree.dll"
sh.RegWrite format(Array("%s\ThreadingModel", key)), "Both"
sh.RegWrite format(Array("%s\Class", key)), progid
sh.RegWrite format(Array("%s\Assembly", key)), format(Array( _
"%s, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", className _
))
sh.RegWrite format(Array("%s\RuntimeVersion", key)), "v4.0.30319"
sh.RegWrite format(Array("%s\CodeBase", key)), dllURL
key = format(Array( "%s\0.0.0.0", key))
sh.RegWrite format(Array("%s\Class", key)), progid
sh.RegWrite format(Array("%s\Assembly", key)), format(Array( _
"%s, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", className _
))
sh.RegWrite format(Array("%s\RuntimeVersion", key)), "v4.0.30319"
sh.RegWrite format(Array("%s\CodeBase", key)), dllURL
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\ProgId\", rootString_, guid _
)), progid
' Classes\WOW...\CLSID\guid
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\", rootString_, guid _
)), progid
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}\", rootString_, guid _
)), ""
key = format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\InprocServer32", rootString_, guid _
))
sh.RegWrite format(Array("%s\", key)), "mscoree.dll"
sh.RegWrite format(Array("%s\ThreadingModel", key)), "Both"
sh.RegWrite format(Array("%s\Class", key)), progid
sh.RegWrite format(Array("%s\Assembly", key)), format(Array( _
"%s, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", className _
))
sh.RegWrite format(Array("%s\RuntimeVersion", key)), "v4.0.30319"
sh.RegWrite format(Array("%s\CodeBase", key)), dllURL
key = format(Array( "%s\0.0.0.0", key))
sh.RegWrite format(Array("%s\Class", key)), progid
sh.RegWrite format(Array("%s\Assembly", key)), format(Array( _
"%s, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", className _
))
sh.RegWrite format(Array("%s\RuntimeVersion", key)), "v4.0.30319"
sh.RegWrite format(Array("%s\CodeBase", key)), dllURL
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\ProgId\", rootString_, guid _
)), progid
Loop While False : Next
Dim data, i, className, progid, guid, key
End Sub
Sub UnregisterWscs
data = WscGuids
For i = 1 To UBound(data) Step 3
className = data(i)
progid = format(Array( "VBScripting.%s", className ))
guid = format(Array( "{%s}", data(i + 1) ))
Deleter.DeleteKey Root, format(Array( _
"Software\Classes\%s\", progid _
))
Deleter.DeleteKey Root, format(Array( _
"Software\Classes\CLSID\%s\", guid _
))
Deleter.DeleteKey Root, format(Array( _
"Software\WOW6432Node\Classes\CLSID\%s\", guid _
))
Deleter.DeleteKey Root, format(Array( _
"Software\Classes\WOW6432Node\CLSID\%s\", guid _
))
Next
Dim data, i, className, progid, guid
End Sub
Sub RegisterWscs
data = WscGuids
For i = 1 To UBound(data) Step 3
className = data(i)
progid = format(Array( "VBScripting.%s", className ))
guid = format(Array( "{%s}", data(i + 1) ))
description = data(i + 2)
wscURL = format(Array( _
"file:///%s/%s.wsc", _
Replace( ComponentFolder, "\", "/" ), _
className _
))
' Classes\progid
On Error Resume Next
sh.RegWrite format(Array( _
"%s\Software\Classes\%s\", rootString_, progid _
)), description
If InvalidRootError = Err.Number Then
WScript.StdOut.WriteLine " Err : " & Err.Description
WScript.StdOut.WriteLine " Root string : " & rootString_
WScript.StdOut.WriteLine " Are you attempting to modify HKEY_LOCAL_MACHINE without elevated privileges?"
End If
WScript.Quit
On Error Goto 0
sh.RegWrite format(Array( _
"%s\Software\Classes\%s\CLSID\", rootString_, progid _
)), guid
' Classes\CLSID\guid
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\", rootString_, guid _
)), description
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\InprocServer32\", rootString_, guid _
)), Expand("%SystemRoot%\System32\scrobj.dll")
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\InprocServer32\ThreadingModel", rootString_, guid _
)), "Apartment"
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\ProgID\", rootString_, guid _
)), progid
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\ScriptletURL\", rootString_, guid _
)), wscURL
sh.RegWrite format(Array( _
"%s\Software\Classes\CLSID\%s\VersionIndependentProgId\", rootString_, guid _
)), progid
' WOW...\Classes\CLSID
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\", rootString_, guid _
)), description
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\InprocServer32\", rootString_, guid _
)), Expand("%SystemRoot%\SysWow64\scrobj.dll")
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\InprocServer32\ThreadingModel", rootString_, guid _
)), "Apartment"
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\ProgID\", rootString_, guid _
)), progid
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\ScriptletURL\", rootString_, guid _
)), wscURL
sh.RegWrite format(Array( _
"%s\Software\WOW6432Node\Classes\CLSID\%s\VersionIndependentProgID\", rootString_, guid _
)), progid
' Classes\WOW...\CLSID
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\", rootString_, guid _
)), description
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\InprocServer32\", rootString_, guid _
)), Expand("%SystemRoot%\SysWow64\scrobj.dll")
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\InprocServer32\ThreadingModel", rootString_, guid _
)), "Apartment"
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\ProgID\", rootString_, guid _
)), progid
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\ScriptletURL\", rootString_, guid _
)), wscURL
sh.RegWrite format(Array( _
"%s\Software\Classes\WOW6432Node\CLSID\%s\VersionIndependentProgID\", rootString_, guid _
)), progid
Next
Dim data, i, progid, guid, description, wscURL
Const InvalidRootError = &H80070005
End Sub
Function Expand(str)
Expand = sh.ExpandEnvironmentStrings(str)
End Function
Public Property Get KeyExists(HKey_Root, key)
parent = fso.GetParentFolderName(key)
baseName = fso.GetFileName(key)
result = stdRegProv.EnumKey(HKey_Root, parent, subkeys)
For Each subkey In subkeys
If LCase(subkey) = LCase(baseName) Then
KeyExists = True
Exit Property
End If
Next
KeyExists = False
Dim parent, baseName, result, subkeys, subkey
End Property
Sub ProgramsAndFeaturesEntry
Const uninstKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\VBScripting"
Dim InstallLocation : InstallLocation = fso.GetParentFolderName(WScript.ScriptFullName)
stdRegProv.CreateKey Root, uninstKey
stdRegProv.SetStringValue Root, uninstKey, "DisplayName", "VBScripting Utility Classes and Extensions (Current User)"
stdRegProv.SetDWORDValue Root, uninstKey, "NoRemove", 0
stdRegProv.SetStringValue Root, uninstKey, "UninstallString", format(Array("wscript ""%s\SetupPerUser.wsf"" /u", InstallLocation))
stdRegProv.SetDWORDValue Root, uninstKey, "NoModify", 1
stdRegProv.SetStringValue Root, uninstKey, "ModifyPath", ""
stdRegProv.SetDWORDValue Root, uninstKey, "NoRepair", 0
stdRegProv.SetStringValue Root, uninstKey, "RepairPath", format(Array("wscript ""%s\SetupPerUser.wsf""", InstallLocation)) '""
stdRegProv.SetStringValue Root, uninstKey, "HelpLink", "https://github.com/koswald/VBScript"
stdRegProv.SetStringValue Root, uninstKey, "InstallLocation", InstallLocation
stdRegProv.SetDWORDValue Root, uninstKey, "EstimatedSize", 1500 'kilobytes
stdRegProv.SetExpandedStringValue Root, uninstKey, "DisplayIcon", "%SystemRoot%\System32\wscript.exe,2"
stdRegProv.SetStringValue Root, uninstKey, "Publisher", "Karl Oswald"
stdRegProv.SetStringValue Root, uninstKey, "HelpTelephone", ""
stdRegProv.SetStringValue Root, uninstKey, "Contact", ""
stdRegProv.SetStringValue Root, uninstKey, "UrlInfoAbout", ""
stdRegProv.SetStringValue Root, uninstKey, "DisplayVersion", ""
stdRegProv.SetStringValue Root, uninstKey, "Comments", ""
stdRegProv.SetStringValue Root, uninstKey, "Readme", InstallLocation & "\ReadMe.md"
stdRegProv.SetStringValue Root, uninstKey, "InstallDate", "" ' [YYYYMMDD]
stdRegProv.SetDWORDValue Root, uninstKey, "Version", 0
stdRegProv.SetDWORDValue Root, uninstKey, "VersionMajor", 0
stdRegProv.SetDWORDValue Root, uninstKey, "VersionMinor", 0
End Sub
End Class
Antivirus Signature
Bkav Clean
Lionic Clean
MicroWorld-eScan Clean
CTX Clean
CAT-QuickHeal Clean
Skyhigh BehavesLike.VBS.Dropper.dp
ALYac Clean
Malwarebytes Clean
Zillya Clean
CrowdStrike Clean
K7GW Clean
K7AntiVirus Clean
Baidu Clean
VirIT Clean
Symantec Clean
ESET-NOD32 VBS/TrojanDownloader.Agent.ABML
TrendMicro-HouseCall TrojanSpy.VBS.NEGASTEAL.YXFBEZ
Avast Script:SNH-gen [Trj]
Cynet Clean
Kaspersky HEUR:Trojan.Script.Generic
BitDefender Clean
NANO-Antivirus Clean
ViRobot Clean
Sophos Clean
F-Secure Clean
DrWeb Clean
VIPRE Clean
TrendMicro TrojanSpy.VBS.NEGASTEAL.YXFBEZ
CMC Clean
Emsisoft Clean
huorong TrojanDownloader/VBS.Agent.hr
FireEye Clean
Jiangmin Clean
Varist Clean
Avira Clean
Fortinet VBS/Agent.BXM!tr
Antiy-AVL Clean
Kingsoft Script.Trojan.Generic.a
Gridinsoft Trojan.U.AgentTesla.tr
Xcitium Clean
Arcabit Clean
SUPERAntiSpyware Clean
Microsoft Trojan:Script/Wacatac.B!ml
Google Detected
AhnLab-V3 Clean
Acronis Clean
McAfee Clean
TACHYON Clean
VBA32 Clean
Zoner Clean
Tencent Clean
Yandex Clean
Ikarus Trojan.JS.RemcosRAT
GData Script.Trojan.Agent.62HNPD
AVG Script:SNH-gen [Trj]
Panda Clean
alibabacloud Trojan:Multi/Wacatac.B9nj
No IRMA results available.