Create Sub-folder list when dropdown option is selected - vbscript

I have a HTA code below which list all sub-folder in a specific folder.
My question is that if I click one sub-folder from list, how can it auto-create the second list that gives me all child-folder in that sub-folder? and so on till there is no more child-folder found, the last child-folder needs to list all files in it. Also how can I add a extra option in the end of each list called [new folder] that will pop-up a window allowing enter the name to create a new folder.
In the end if click [submit] button, It will open the last child-folder I choose in windows explorer.
I am new to vbs, so please help
<HEAD>
<TITLE>K Drive Program Structure</TITLE>
<HTA:APPLICATION ID="Hello"
APPLICATIONNAME="K Drive Program Structure"
BORDER="Dialog"
CAPTION="Yes"
SCROLL="NO"
SHOWINTASKBAR="yes"
SINGLEINSTANCE="yes"
SYSMENU="Yes"
WINDOWSTATE="maximize">
</HEAD>
<BODY>
<SCRIPT LANGUAGE="VBScript">
Sub UpdateList
For Each opt In list.Options
opt.RemoveNode
Next
Set fso = CreateObject("Scripting.FileSystemObject")
For Each f In fso.GetFolder("K:\AppData").SubFolders
Set opt = document.createElement("OPTION")
opt.Text = f.Name
opt.Value = f.Path
list.Add(opt)
Next
End Sub
</SCRIPT>
<H2>K Drive Structure</H2>
<P>CUSTOMER
<select id="list" name="list" onMouseOver="UpdateList"></select><P>
<BR>
<BR>
<Input Type = "Button" Name = "btn01" VALUE = "SUBMIT">
<Input Type = "Button" Name = "btn02" VALUE = "CLOSE">
<BR>
<BR>
</BODY>
Thanks for help

Why aren't you using the Shell.BrowseForFolder method like I suggested? Trying to re-invent it in HTA will always be awkward.
As for your question, you need to add an onChange handler to the <select> tag:
<select id="list" name="list" onMouseOver="UpdateList" onChange="EnumSubFolders">
</select>
and a procedure EnumSubFolders to enumerate the child folders:
Sub EnumSubFolders
Set fso = CreateObject("Scripting.FileSystemObject")
For Each opt In list.options
If opt.selected Then
Set sf = fso.GetFolder(opt.value).SubFolders
'do stuff with sf
Exit For
End If
Next
End Sub
You may need to apply some modifications to UpdateList, too (like remembering the currently selected option before refreshing the list).

Related

Way to close child HTA file if it gets called again from a parent HTA file

I want to run a HTA file where, there is a loop in which the parent HTA calls a child HTA to display an update on a regular interval. I want the child HTA to be remain open with old update and it should close when it is called again with new update and diplay it. I tried to do it, but I am unable to add close HTA condition on the child HTA. Which results in all Child HTA opened in the background.
Parent HTA File,
Code given below
<html>
<head>
<title>Parent Application</title>
<HTA:APPLICATION
APPLICATIONNAME="Parent Application"
ID="ParentApplication"
VERSION="1.0"/>
</head>
<script language="VBScript">
Sub OnClickButtonConnect()
Dim currentDirectory,pos
pos=InStrRev(document.location.pathname,"\")
currentDirectory=""
If pos>0 Then
currentDirectory = Left(document.location.pathname,pos)
End If
Dim WshShell, i, g
g = 5
set WshShell = CreateObject("wscript.Shell")
For i = 1 To g
cmdline = "mshta.exe """ & currentDirectory & "child.hta"" """ & login.value & """ """ & password.Value & """"
WshShell.Run cmdline,1,False
next
window.close
End Sub
</script>
<body bgcolor="white">
<!--Add your controls here-->
Login:<input type="text" name="login" id="login"><BR>
Password:<input type="password" name="password" id="password"><BR>
<input type="button" name="Connect" id="Connect" value="Connect" onclick="OnClickButtonConnect">
<!--{{InsertControlsHere}}-Do not remove this line-->
</body>
</html>
Child HTA
<html>
<head>
<title>Child Application</title>
<HTA:APPLICATION
APPLICATIONNAME="Child Application"
ID="ChildApplication"
VERSION="1.0"/>
</head>
<script language="VBScript">
Sub Window_OnLoad
str=""
arguments = Split(ChildApplication.CommandLine," """)
For i=0 To UBound(arguments)
arguments(i)=Replace(arguments(i),"""","")
Next
document.body.innerhtml="login is: " & arguments(1) & "<BR>password is: " & arguments(2)
End Sub
</script>
<body bgcolor="white">
<!--Add your controls here-->
<!--{{InsertControlsHere}}-Do not remove this line-->
</body>
</html>
Call this Sub before opening the child hta. Make sure the name of the hta matches its actual name.
Sub CloseChild
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select CommandLine from Win32_Process where CommandLine like '%child.hta%'")
For Each objProcess In colProcessList
objProcess.Terminate()
Next
End Sub
Edit: I just wanted to comment for anyone who may read this later. Putting CommandLine in the select statement is not explicitly required, even though this property is used in the where clause. You can select any or all of the properties in the Win32_Process class, including or excluding CommandLine.
I do suggest selecting only the properties you need to increase the speed of the query, and historically, for clarity, I select the same property as I use in the where clause if I don't actually need one.

Start/Stop methods for embedded Windows Media Player via VBScript

I have following code working fine.
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6" id="WindowsMediaPlayer"
width="242" height="202" style="position:absolute; left:1;top:1;">
<param name="URL" value="C:\HTML\Sounds\oos.wav">
<param name="autoStart" value="0">
</object>
I would like to crearte Start/Stop methods in VBScript for this object.
So I am doing like
Sub Start
Dim oElm
Set oElm = document.getElementById("WindowsMediaPlayer")
if oElm Is Nothing then
MsgBox("element does not exist")
else
' MsgBox("element exists")
oElm.controls.play();
end if
End sub
But it does not work.
How to fix it?
I have been fighting with this for month. I know that this is not going to get everywhere but I want to share the resolution with a bit of backstory.
I have been creating unattended installations for everything under the sun and it has been going really well except that it's... well, unattended and mostly hidden so that I did not know where it was in its progress or anything else for that matter. I decided then to use an HTA file instead of Powershell or VBScript alone. Figured it would give me something to look at while all this was happening. Cool, right? Almost a year of working on it and trying every different devolving code I could find. Today that paid off.
I found the same code you used with the OBJECT instead of a common VIDEO tag. It was clunky and more code that I wanted to write but it worked... mostly. I could not send CSS references to it (ie. OPACITY:.5) or even position the darn thing. I found I could using the IE=7 or 8 references make slight changes, but then scripting it (VBScript) was almost impossible. Could not find the references that would work all the time. Alternately, switching to IE9 - IE11 broke the rest of my code. None of the calls or refs made sense.
Ultimately, it was a whole lot easier than anything I had found! SO much wasted time to get back to the very beginning...C'est la vie! Here is my code, though for privacy I've removed my personal domain and made everything local. It works, though not as efficiently as using a stream. Hope this helps. Share it with everyone!
Note: for fun I've opted to show my custom Office 365 install. Obviously I could make this fully unattended, but I just used the files rather than allowing the download function!
<meta http-equiv="X-UA-Compatible" content="IE=8;IE=9" />
^^^ This is KEY! ^^^
<html>
<head>
<TITLE>Office 365 Installer</TITLE>
<hta:application id="O365TK"
applicationname="O365TK"
border="none"
caption="no"
icon=".\MEDIA\myico.ico"
showintaskbar="no"
singleinstance="yes"
sysmenu="no"
windowstate="maximize"
>
<style>
body{overflow:hidden;background:black;}
#proc{position:absolute;top:400px;left:20px;color:red;background:black;opacity:.3;}
#BG{position:absolute;top:0;left:0;z-index:-1;}
#myhead{position: absolute; top:0;left:0;z-index:0;}
#myvideo{position:absolute;top:0;left:0;height:100%;z-index:1; opacity:.5;}
</style>
</head>
<body>
<img id="BG">
<video id=myvideo type="video/mp4" autoplay src=".\MEDIA\cot.mp4"></video>
<div id="proc">Click Here to Start!</div>
<img id="myhead" src=".\MEDIA\label.png">
<script language="vbscript">
x = 5
Set ws = createobject("wscript.shell")
set fs = createobject("scripting.filesystemobject")
set sa = createobject("shell.application")
Sub window_onload
sa.MinimizeAll
pc=setInterval("pic_changer()",3000)
setTimeout "clicker()",4000
setTimeout "musicbox()", 3200
settimeout "pic_changer()",10
End Sub
Sub window_onbeforeunload()
'Set cd=location.pathname
Unloader()
End Sub
Function wait()
ws.Run "wait.vbs",0,1
'Lots of ways to go about putting a pause in the transmission.
'I use an external vbs file with one line: wscript.sleep 1000 That's all!
window.focus
End Function
Function document_onclick()
myvideo.stop
musicbox()
End Function
Sub document_onkeypress()
If window.event.keyCode=27 Then
Unloader
End if
End sub
Function proc_onclick()
'proc.innerhtml = "Download Office...<br>Please wait."
'wait:wait
'ws.run ".\Setup /configure .\TKO365.xml",0,1
proc.innerhtml = "Packaging Office...<br>Please wait."
wait:wait
ws.run ".\Setup /packager .\TKO365.xml .\Office",0,1
wait:wait
proc.innerhtml = "Install Office...<br>Please wait."
wait:wait
ws.run ".\Setup /configure .\TKO365.xml",0,1
proc.innerhtml = "Customize Office!<br>Please wait."
wait:wait
ws.run ".\Setup /customize .\TKO365.xml",0,1
wait:wait
proc.innerhtml = "Mission Complete!<br>We're done here!"
wait:wait
proc.innerhtml = "Goodbye!"
wait
Unloader()
End Function
Function Unloader()
clearInterval(pc)
sa.UndoMinimizeALL
ws.run "taskkill /f /im wscript.exe",0
ws.run "taskkill /f /im mshta.exe",0
End Function
Function clicker()
do while x => 0
proc.innerhtml="Autostart in " & x & " seconds"
wait
x = x-1
Loop
proc.click()
end Function
Function musicbox()
max=230
min=1
Randomize
d = Int((max-min+1)*Rnd+min)
t = ".\MEDIA\" & d & ".mp4"
'I renamed 230 tracks 1-230 for ease of calling them
myvideo.filename=t
myvideo.play
End Function
Function pic_changer()
Randomize
'Set ddd = document.getelementbyid("BG")
' I've left the above line for a sign of how horribly convoluted
'things got when using IE8 and below. BG already exists.
'I did not need to create another variable for it,
'though this is what I had been forced to do with those other iterations of IE
dd = Int(Rnd*230)+1
bg.src=".\MEDIA\"& dd &".jpg"
With bg.style
.display="block"
.width="100%"
.position="absolute"
.top="0px"
.left="0px"
.backgroundRepeat="no-repeat"
End With
window.focus
End Function
</script>
It shoul dbe done like this
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6" id="WindowsMediaPlayer" width="0" height="0">
</object>
Sub Start
Dim oElm
Set oElm = document.getElementById("WindowsMediaPlayer")
if oElm Is Nothing then
MsgBox("element does not exist")
else
oElm.controls.stop()
oElm.URL = "C:\HTML\Sounds\oos.wav"
end if
End sub

VBScript/HTA Application - Running multiple programs at once chosen by user

So here is what i am wondering about boys and girls - first of all i am a complete noob to this, LITERALLY just starting so don't go too hard on me. I have a bunch of code i wrote, to make a .HTA application:
> <html> <head>
>
> <script type="text/vbscript">
>
> Dim objShell Sub Button1_OnClick()
>
> if box2.checked AND box1.checked then
>
> Set objShell = CreateObject( "WScript.Shell" )
> objShell.Run("""%programfiles(x86)%\Mozilla Firefox\firefox.exe""")
> Set objShell = Nothing
>
> Set objShell = CreateObject( "WScript.Shell" ) objShell.Run("cmd.exe")
> Set objShell = Nothing
>
> elseif box1.checked then
>
> Set objShell = CreateObject( "WScript.Shell" ) objShell.Run("cmd.exe")
> Set objShell = Nothing
>
> Elseif box2.checked then
>
> Set objShell = CreateObject( "WScript.Shell" )
> objShell.Run("""%programfiles(x86)%\Mozilla Firefox\firefox.exe""")
> Set objShell = Nothing
>
>
> End If End Sub
>
>
> </script> </head> <body> <font face=Calibri> Check the program you
> would like to run! <br> Available programs to run for now: <br> <input
> type="checkbox" name="box1">CMD <br> <input type="checkbox"
> name="box2">Mozilla <br> <i>Choose which program(s) you'd like to run.
> It is possible to run multiple programs at one time!</i></font><br>
> <input type="button" name="btn1" onclick="Button1_OnClick"
> value="Submit"><br> <div id="error"></div>
>
>
>
> </body> </html>
This works perfectly as it is supposed to, when i check both programs, both of them will run, when i check one of them, only one will run. But what if i have like 50 different programs on that list? I suppose there is a simplier way to write this than writing load of if/else/elseif statements for each program combination? As mentioned above im complete noob to this, maybe i simply haven't discovered an easier way yet... But that's also why i ask.
You can use the elements attributes for your purpose.
Iterate over all the checkboxes, then start the process using its path stored in your custom attribute if it's checked. Done.
<html>
<head>
<script type="text/vbscript">
Dim objShell
Set objShell = CreateObject("WScript.Shell")
Sub StartProcesses
Dim Checkbox
For Each Checkbox In Document.getElementsByName("process")
If Checkbox.Checked Then
objShell.Run """" & Checkbox.getAttribute("path") & """"
End If
Next
End Sub
</script>
</head>
<body>
<font face=Calibri>
Check the program you would like to run! <br>
Available programs to run for now: <br>
<div id="ProcessList">
<input type="checkbox" name="process" path="cmd.exe">CMD <br>
<input type="checkbox" name="process" path="iexplore.exe">Internet Explorer <br>
<input type="checkbox" name="process" path="%programfiles(x86)%\Mozilla Firefox\firefox.exe">Firefox <br>
<input type="checkbox" name="process" path="calc.exe">Calculator <br>
<input type="checkbox" name="process" path="notepad.exe">Notepad <br>
</div>
<i>Choose which program(s) you'd like to run. It is possible to run multiple programs at one time!</i>
</font><br>
<input type="button" onclick="StartProcesses" value="Submit"><br>
<div id="error"></div>
</body>
</html>

VBScripts interacting with each other

So I use VBScript frequently, and I have several scripts that call the same function. At the moment, each script has that function just copied in there at the bottom, but it's a pain when I have to make an updated, because I have to update several files (and I usually forget about some). Is there a way where I can:
1. Have "TestScript1" call "TestScript2"
2. Have "TestScirpt2" take an argument from "TestScript1" (i.e. a specific date variable)
3. Have "TestScript2" run its functions, and pass 3 different arguments back to "TestScript1"
And a bonus would be if I could actually somehow do all of that and have it work for multiple scripts interacting with "TestScript2".
I do this with objShell.Exec in some of my scripts. Essentially I have a script named after the function I want to do and I call it from another script.
In the "parent script" I have a function called runExternal:
Function runExternal(strScript,strComputer)
'strScript is the name of the script/function I'm calling
Set objExec = objShell.Exec("cmd.exe /c cscript.exe """ & strPath & strScript & ".vbs"" " & strComputer)
intDelay = Timer+5
intTimer = Timer
While objExec.Status = 0 And intTimer <= intDelay
intTimer = Timer
Wend
If objExec.Status = 1 Then
strReturn = objExec.StdErr.ReadAll
writeLog strScript & " returned " & strReturn
Else
objExec.Terminate 'terminate script if it times out
writeLog strScript & " timed/errored out and was terminated."
End If
End function
Then in each "child" script, I accept the argument I passed to it by using:
strComputer = WScript.Arguments(0)
then to output I write this way:
WScript.StdErr.Write "whatever the output is"
Have you considered using an HTA? This is an example how you can use HTA's if you want to load and combine multiple script files:
<html>
<head>
<title>Demo IT</title>
<HTA:APPLICATION
ID="objShowMe"
APPLICATIONNAME="HTAShowMe"
SCROLL="yes"
SINGLEINSTANCE="yes"
WINDOWSTATE="maximize"
>
<SCRIPT Language="VBScript" src="testscript2.vbs"/>
<SCRIPT Language="VBScript">
Sub TakeOff
text = "1 2 3"
argArray = GiveMeThree(text)
msgbox argArray(0)
msgbox argArray(1)
msgbox argArray(2)
End Sub
</SCRIPT>
</head>
<body>
<h1>In the body</h1>
<input type="button" value="Click me!" onclick="TakeOff">
</body>
</html>
In testscript2.vbs
Public Function GiveMeThree(x)
GiveMeThree = split(x, " ")
End Function
I think the best way to do this is to create a Windows Script Component. This will expose your script as a fully baked COM object that you can call from anywhere - VBScript or any other programming language that supports COM.
Here's some example code. This is in a file with a .wcs extension.
<?XML version="1.0"?>
<?component error="false" debug="false"?>
<component id="SVInfo">
<registration
progid="Tmdean.ScriptFunctions"
description="Description of your COM object"
version="1.5"
clsid="{3267711E-8359-4BD1-84A6-xxxxxxxxxxxx}"/>
<!-- generate your own GUID to use in the line above -->
<public>
<method name="MyMethod"/>
</public>
<script language="VBScript">
<![CDATA[
Function MyMethod(param1, param2)
MyMethod = param1 + param2
End Function
]]>
</script>
</component>
Register this file to COM with the following command.
regsvr32 scrobj.dll /n /i:file://J:\scripts\scriptfunctions.wcs
Then you can call the methods in VBScript using the ProgID that you defined in the script component.
Dim script_functions
Set script_functions = CreateObject("Tmdean.ScriptFunctions")
WScript.Echo script_functions.MyMethod(2, 2)

VBScript For Each isn't working

I can't get the following function in VBScript to work. I am trying to get all of the files in a folder and loop through them to get the highest numbered file. (file name format is log_XXX.txt) The problem that I am having is that the code never enters my For Each loop. I am new to VBScript, but I don't seem to understand why this won't work.
Function GetFileNumber(folderspec)
Dim fso, f, f1, fc, s, tempHighNum
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.GetFolder(folderspec)
WScript.Echo f.Files.Count : rem prints 3
Set fc = f.Files
WScript.Echo fc.Count : rem prints 3
Set tempHighNum = "000"
For Each f1 in fc
WScript.Echo f1.Size : rem does not print
WScript.Echo f1.Type : rem does not print
WScript.Echo f1.Name : rem does not print
s = Right(f1.name,3)
IF NOT(ISNULL(s)) THEN
IF (s > tempHighNum) THEN
tempHighNum = s
END IF
END IF
Next
GetFileNumber = tempHighNum
End Function
Change this line:
Set tempHighNum = "000"
to the following:
tempHighNum = "000"
You are attempting to set the tempHighNum variable to a string type. Therefore, you should not use the Set keyword. Set is only needed when assigning object types to variables.
I am not sure how your script works so I put this HTML application together for you. It uses a batch file called Dir.Bat located in C:\Batch which makes a file called Data.Txt located in c:\Temp. Then the script takes
over. The script reads the file Data.Txt line by line. As each line is read two split statements are used to separate out the string in the text file's name. After that I collect those strings containing numbers into the variable ListCol as I test for larger and larger numbers. I finally wind up with the largest number which I place in your original variable tempHighNum. I will post the HTA file and the Dir.Bat file. I know I did not write the script as a function using a parameter so if you really need to use a parameter, I will try to help you by changing the HTA file to make it possible to enter the path and file name in a TextBox. That should make it easy to
change and use. I added and changed a thing or two to make it run smoother.
I am not sure how your script works so I put this HTML application together for you. It uses a batch file called Dir.Bat located in C:\Batch which makes a file called Data.Txt located in c:\Temp. Then the script takes
over. The script reads the file Data.Txt line by line. As each line is read two split statements are used to separate out the string in the text file's name. After that I collect those strings containing numbers into the variable ListCol as I test for larger and larger numbers. I finally wind up with the largest number which I place in your original variable tempHighNum. I will post the HTA file and the Dir.Bat file. I know I did not write the script as a function using a parameter so if you really need to use a parameter, I will try to help you by changing the HTA file to make it possible to enter the path and file name in a TextBox. That should make it easy to
change and use. I added and changed a thing or two to make it run smoother.
<HTML><!-- C:\HTML_and_HTA_CODE_EXAMPLES\ATest.Hta -->
<HEAD>
<TITLE>ATest.Hta</TITLE>
<HTA:APPLICATION ID="HTA MyApp"
APPLICATIONNAME="Help4Saul Dolgin"
BORDER ="thick"
BORDERSTYLE ="complex"
CAPTION ="yes"
CONTEXTMENU ="no"
ICON ="http://Your URL/your icon.ico"
INNERBORDER ="yes"
MAXIMIZEBUTTON ="yes"
MINIMIZEBUTTON ="yes"
NAVIGABLE ="no"
SCROLL ="no"
SHOWINTASKBAR ="yes"
SINGLEINSTANCE ="yes"
SYSMENU ="yes"
VERSION ="1.0"
WINDOWSTATE ="Normal"/>
</HEAD>
<style>
.ExBt21 {background:"#E0E0E0";Color:"red";}/* For Exit Button */
.Spn4 {font-family:"arial";font-weight:"bold";Color:"blue"}
.Spn2 {Color:"red"}
.tAr1 {font-family:"arial";font-weight:"bold";Color:"blue"}
</style>
<SCRIPT Language="VBScript">
Sub GetFileNumber
Dim FSO, f, fc, tempHighNum, strLine, objSHO, line
Dim DataArr, Data1Arr, Data2Arr, ListCol
fc=""
ListCol=""
tempHighNum=000
Set objSHO=CreateObject("WScript.Shell")
objSHO.run "C:\Batch\Dir.bat"
Set FSO = CreateObject( "Scripting.FileSystemObject" )
Set f = FSO.OpenTextFile("c:\Temp\Data.Txt", "1")
Do Until f.AtEndOfStream
fc = fc & f.ReadLine & vbLf
Loop
tArea1.innerHTML=fc
Data1Arr = Split(fc,vbLf)
Count=UBound(Data1Arr)
For x=0 To Count
DataArr = Split(Data1Arr(x),".")
If x <= Count-1 Then
Data2Arr = Split(DataArr(0),"_")
ListCol = ListCol & Data2Arr(1) & vbLf
If Data2Arr(1) > tempHighNum Then
tempHighNum = Data2Arr(1)
End If
End If
Next
Span2.innerHTML=tempHighNum
End Sub
Sub ExtBtn:Window.close:End Sub' Exit Script For Window
</SCRIPT>
<BODY bgcolor="#D0D0D0">
<button OnClick="GetFileNumber">Button To Press</button><br/>
<span id="Span1" class="Spn1">The biggest No. is: </span><span id="Span2" class="Spn2"></span><br/><br/>
<span Id="Span3" Class="Spn3">Dir.Bat looks in: </span><span Id="Span4" Class="Spn4">C:\Temp\Log_???.Txt</span><br/>
<textarea Id="tArea1" class="tAr1" rows="10"></textarea><br/><br/>
<input id="ExBtn21" class="ExBt21" type="Button" name="ExitBtn21" OnClick="ExtBtn" value="&nbsp-Exit-&nbsp"/><!-- Exit Button -->
</BODY>
</HTML>
The Dir.Bat file is next:
#Echo Off
Dir/B c:\Temp\Log_???.Txt>c:\Temp\Data.Txt

Resources