Extracting ZIP file to absolute path - vbscript

I am trying to create a VBS file that can extract the content of a ZIP file from a relative path to an absolute file path destination. The reason I am trying to create this VBS file is because my overall goal is to create an EXE file through iExpress that will copy a bunch of code to a user's computer and install nodeJS at the same time.
My thoughts on taking this approach have been to create a batch script that would copy the directory of code to a set position on the user's computer, and then execute an MSI file to install nodeJS. I have been able to get a batch script that can do that, but now I want to package it all nicely into an EXE. For this I believe I need to put the code directory into a ZIP file so I can add it to the EXE file, and then my EXE needs some functionality to extract this.
To add this functionality, my research seems to indicate that VBS is the best option for this (especially considering I am hoping to also compensate for users who have restricted access to PowerShell cmdlets). Searching around seems to indicate that a file of this sort of variety is meant for what I want to do.
ZipFile="test.zip"
ExtractTo="C:\test-install\test"
Set fso = CreateObject("Scripting.FileSystemObject")
sourceFile = fso.GetAbsolutePathName(ZipFile)
destFolder = fso.GetFolder(ExtractTo)
Set objShell = CreateObject("Shell.Application")
Set FilesInZip=objShell.NameSpace(sourceFile).Items()
objShell.NameSpace(destFolder).copyHere FilesInZip, 16
Set fso = Nothing
Set objShell = Nothing
Set FilesInZip = Nothing
This does not seem to work though as on this line...
objShell.NameSpace(destFolder).copyHere FilesInZip, 16
... it complains to me about destFolder needing to be an object. I am not too sure what I am meant to change to fix this error (I am not too familiar with VBS) and most examples on the internet set the ExtractTo variable as a relative file path initially and run a command to turn this into an absolute file path. I don't want to do this though as when iExpress turns it all into an EXE my understanding is that the relative file path starts in some random TEMP folder somewhere.
Any guidance on the error in my VBS file, or indication of a better path to take for extracting ZIP files would be greatly appreciated, thank you.

It seems my inexperience with VBS was the root of my troubles here. The trouble ended up being that on this line:
objShell.NameSpace(destFolder).copyHere FilesInZip, 16
It needed to be this:
objShell.NameSpace(destFolder).copyHere(FilesInZip), 16
I am not sure if this is specific to a certain version of the language or not, because my error was copied from numerous examples of a similar script across the internet, but I haven't really been able to find further details on this (I will edit this answer if more is found).

Related

location of executable invoked by wscript.createobject()

I need to know how to locate the executable invoked by wscript.createobject().
I inherited a mass of old code that I'm trying to untangle. A VBS file invokes a custom executable with this line:
Set TGen = wscript.createobject("VbTextGen.TextGen")
I would like to find that executable but have not been able to. I understand the argument is server.typename but that doesn't tell me much. I've looked in the directory containing the vbscript file, the path, and some system directories
Set TGen = wscript.createobject("VbTextGen.TextGen") is all I have to go on.
Hoping someone can tell me where to find this thing.

current working directory in a vbscript invoked by a drag & drop operation

When I was trying to get elevated rights for my batch script, when I found two related SO questions
How to request Administrator access inside a batch file
How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?
...that led to answers that worked partially. For some reason, I had issues with command line passing for file path arguments containing spaces within the VBS script, so I tried to break the solution into 3 parts and concentrated on the inner (VBS) step, then adding the last step by calling a batch from that VBS which could not be found, despite in the same folder as the VBS script. I found that drag & drop isn't "that easy" and that it's different when using .vbs instead of .bat or .exe as drop targets.
Here is my actual question:
If I drag a file and drop it onto an executable (exe) or batch file (bat, cmd), The current working directory is determined by the source of the dragged item. Its directory is set as the working directory for the program or script that processes it.
If I drop a file onto a VBS script, it's different. On Windows 8.1 x64 I observe it to be C:\Windows\System32 even if the argument resides in the same folder as the VBS.
I can simply use a batch file (as drag'n'drop relay) like this
my.vbs %*
to get "the normal" .bat behaviour (drop source dictates CWD), but I also want to understand it.
Is it a bug or a feature? Is it consistent over all Windows versions?
edit: added the background (on top) for the question showing how I got there (+minor corrections)
After some API monitoring, this is what I see
When you drop a file over a .exe file the explorer.exe uses CreateProcess API function to start the process, passing the executable as lpApplicationName, and the executable and dropped file as lpCommandLine. The lpCurrentDirectory is set in the function call by the caller process to the folder containing the dropped file[1].
When you drop a file over a .cmd file the explorer.exe also uses CreateProcess API, but in this case the lpApplicationName is null and the lplCommandLine contains the batch file and the dropped file. lpCurrentDirectory is also set to the parent folder of the dropped file[1].
When you drop a file over a .vbs file, ShellExecuteEx is used and the lpDirectory field of the SHELLEXECUTEINFO structure is null, so, the process created inherits the current active directory of the parent process. By default the current active directory of the explorer.exe process is %systemroot%\system32, but it is possible to start a explorer instance with a different current active directory that will be inherited in this kind of drop operations.
[1] If we drop more than one file, the path of the file passed as first argument is used
note just for information: to test the active directory inherit the process followed was:
Open a cmd instance and change the current active directory to c:\temp
Kill all explorer.exe instances
From the cmd instance call explorer.exe. This explorer instance has the active directory in the cmd window as its current active directory.
The Arguments property holds the full paths to all items dropped on the script, so you can determine the directory of each dropped item like this:
Set fso = CreateObject("Scripting.FileSystemObject")
For Each item In WScript.Arguments
WScript.Echo fso.GetParentFolderName(item)
Next
Assuming that the working directory would be defined by what is dropped onto a script is a misguided approach. If you require that logic you can implement it in the script yourself, though, e.g. like this:
Set fso = CreateObject("Scripting.FileSystemObject")
Set sh = CreateObject("WScript.Shell")
For Each item In WScript.Arguments
sh.CurrentDirectory = fso.GetParentFolderName(item)
'working directory is now the parent folder of the current item
'...
Next
If you need the working directory to be the parent directory of the VBScript file you can derive that from the ScriptFullName property:
Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetParentFolderName(WScript.ScriptFullName)
If I lookup the file types in the Windows registry, I see the following in their Shell\Open\Command values:
batfile: "%1" %*
cmdfile: "%1" %*
exefile: "%1" %*
VBSFile: "%SystemRoot%\System32\WScript.exe" "%1" %*
This seems to suggest that bat, cmd, exe are treated as executable on their own, maybe for historical reasons, whereas VBS is considered an ordinary script, that is only executable because its extension is registered with some executable to be called to interpret it. Pretty much the same as Python or Perl.
[Update] Indeed I proved that a Python script shows exactly the same behaviour as my VBS script: calling it from the command line providing arguments keeps the CWD, dropping a file on it causes the CWD to be C:\Windows\System32. So my question seems to be sort of wrong, but finally it helped people to point me into the right direction for further research...
c:\windows\system32\CScript.exe or c:\windows\system32\Wscript.exe are the programs that run vbscript. As you can see they are in system32.
Windows uses ShellExecuteEx to start programs - see it's rules at MSDN: ShellExecuteEx function (Windows)
ShellExecuteEx uses CreateProcess (CreateProcessEx) to actually start a program. CreateProcess function (Windows)
Edit
CMD doesn't use the registry for it's own stuff. Those registry entries are for programs other than CMD.
CMD main goal is to be MS Dos 5 compatible while enhancing it, it will correctly run most DOS batch files. It was written by IBM engineers working on OS/2 NOT Windows.
Edit 2
The core of your problem is that you are attempting to write programs as if you are a user typing to operate a computer.
As a programmer you don't make assumptions. The easiest way to not take assumptions is to specify full paths to what you want. Your batch file shouldn't care what the current directory is. EG In CMD there is a current directory per drive for compatibility with MSDos 5 (and programs in a console tend to share them but don't have to). In Windows there is one current directory per program. The default current directory has changed over the years.
The only time you should work with the current directory is if you are writing a batchfile for a user to use. EG If you type dir it does the current directory, a batchfile meant to be a general command should work the same way.

FSO DeleteFolder() method not working

I have a program in HTA and all the auxiliary files are in the same folder, a subfolder of the AppData folder. I created an uninstaller HTA which uninstalls the program by simply removing the folder with FSO DeleteFolder() method. I converted it to an executable with HtaEdit. (If you don't know this program, it doesn't matter). What the executable does is that it creates an HTA in a temporary folder (along with the auxiliary files) and runs it. The problem is that when it does the DeleteFolder() method, an error message comes up saying "denied access". I don't think that it's an administrator problem since it's in the current user's AppData folder. When I try deleting another folder that way, it works just fine. I think that there are usually problems deleting the folder containing an HTA file which is being run, but the HTA file isn't in the folder I'm trying to delete but in a temporary folder. However, it's been called by an executable in the folder I'm trying to delete.
I'm using VBScript, but it does the same thing if I use JavaScript.
You can't delete a folder from within the same folder as long as there's still something holding an open handle to the folder or something inside it. For example, the following code will usually delete the parent folder of a VBScript:
Set fso = CreateObject("Scripting.FileSystemObject")
dir = fso.GetParentFolderName(WScript.ScriptFullName)
fso.DeleteFolder(dir)
or, in case of an HTA (which doesn't have a WScript object):
Set fso = CreateObject("Scripting.FileSystemObject")
htaPath = Replace(oHTA.CommandLine, """", "") '<HTA:APPLICATION ID="oHTA" ...>
dir = fso.GetParentFolderName(htaPath)
fso.DeleteFolder(dir)
These work, because the script interpreter reads the entire script into memory when the script is launched, so no open handle to the file remains.
However, the deletion of the folder will fail with a "permission denied" error if the folder is the current working directory of the script process, because in that situation there still is an open handle to the folder. The same applies if, for instance, the folder is open in Explorer or a command prompt.
You can check for open handles with handle.exe or Process Explorer.

Unable to copy files using COPY on Windows 2003 Server with long name and special characters

I have thousands of files in a batch file which I need to copy so I prepare a batch file containing copy command as mentioned below. A few files fail to copy with the message
"The system cannot find the file specified." These entries come from a database.
copy "G:\csdata\maximo\ATTACHMENTS\MM#2103806321038064-4’’&6’’X4’’X1500N-LINECHOKEVALVEMOD-4CPC.msg" g:\sample /Y
copy "G:\csdata\maximo\ATTACHMENTS\Re-doPR70072095withaddinganotheritem21037549TAPE&HEADER-ASSY#THAB2317-70M–QTY2EA.msg" g:\sample /Y
As alternative to this, I then used VB script as mentioned below but when a file is missing at OS level the script stops, It should continue to copy next file instead:
Dim FSO
Set FSO = CreateObject("Scripting.FileSystemObject")
FSO.CopyFile "G:\csdata\maximo\ATTACHMENTS\FW91536140-WF3VB4754RPLPASSING18”-VB505LLHDRVLV.msg", "g:\sample\"
FSO.CopyFile "G:\csdata\maximo\ATTACHMENTS\FW18VALVEFORLLPF1359361065881.msg", "g:\sample\"
please advise what is the best possible way?
Maximo may allow you to upload/attach files that have characters that are more difficult to process in a batch file. For example, the double quote as part of the file name may confuse the COPY command into thinking that you want to copy G:\csdata\maximo\ATTACHMENTS\MM#2103806321038064-4 rather than the full file name.

VBS script (VBScript) errors 800A0035 and/or 800A004C only on the first execution of the script

I am pretty new to all this VBS stuff because basically all I need to do is to make one simple VBS script, which I have possibly written, however, my problem is that it gives me 800A0035 or 800A004C error when I execute it for the first time on a particular PC, as soon as I execute it for the second time, it runs just OK and does what it is supposed to do. Incidentally, on my own computer it works OK even on the first execution.
I know that the errors have something to do with the wrong paths but I have checked my script several times and I am 100% positive that they are correct.
Here is the script:
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.MoveFile "rar.bat" , "rarp.bat"
'HideBat.vbs
CreateObject("Wscript.Shell").Run "rarp.bat", 0, True
What the script is supposed to do is to rename the rar.bat file to rarp.bat and run that batch file (rarp.bat) without popping up the command prompt. What the batch file does is not relevant, I guess, but anyway, it just runs WinRAR.
The rar.bat file and the VBS script are in the same folder, that's why I have used relative paths in the script. I cannot use absolute paths because I need to run the script on several computers.
I have read somewhere on the internet that by default VBS script first looks for the files in C:\Windows\System32 when relative paths are used. I have even tried using absolute paths in the script but it didn't work either. Here is how I need them to look like: %systemdrive%\users\%username%\appdata\roaming\rar.bat but this simply didn't work in the VBS script.
I really think that what I need is really a simple script but apparently it's pretty hard to get it working properly. I will be very grateful to those who help me.
Thank you a lot in advance.
Regards.
The only way your script - at least the part published - can give an error is by not finding the source file for renaming, you should have added full script and error message to be sure.
I suppose this is caused by a security setting on your pc that are more forgiving than on the rest of the pc's, eg UAC ? On the other pc's, try to put the files in a map like c:\test and then run it again after checking that the file rar.bat does exist in the same map. Do you have the same credentials (admin) on the other pc's ?
If you just want to run the bat file hidden, why the renaming ?
how do you download the bat ? and how then is invoked the script ? could be a timing issue that the second time is no longer a problem. In that case check in your script if the file is allready there and do a sleep in a loop while it doesn't
If you want to use the absolute path you could try this
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
Set WshSysEnv = WshShell.Environment("PROCESS")
path = WshSysEnv("USERPROFILE") & "\appdata\roaming\rar.bat"
wscript.echo path
objFSO.MoveFile path , "rarp.bat"
CreateObject("Wscript.Shell").Run "rarp.bat", 1, True

Resources