Link to home
Create AccountLog in
Avatar of Muskie12
Muskie12

asked on

VBS script to FTP download fails on large files

I have only very basic experience with vbs.

I have the following vbs script which successfully logs into an ftp server and downloads files upto and including 85Meg (in less than 4mins)

However, it fails with SimpleFTPGetFile 12002 Timeouts when attempting to download a 137Meg (approx 6 mins).

Is there a modifcation that can be made to the vbs to allow for a longer timeout so I can download larger files?

set objRoot = GetObject("LDAP://RootDSE")
strDomainPath = objRoot.Get("DefaultNamingContext")

intLenght = len(strDomainPath)
strDomainPath = Left (strDomainPath, intLenght - 26)
intLenght = len(strDomainPath)
strDomainPath = (ucase(right (strDomainPath, intLenght - 3))) & "01"


set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("d:\updates\Driversdownload.log",1,false)

Set objFTP = CreateObject("iFTP.CFTP")
call objFTP.SetModePassive
	objFTP.SetTransferBinary


If objFTP.OpenConnection("ftp.somewhere.ca", "21", "useriD", "Password") Then
	objFTP.SetFTPDirectory("../UPDATES/SOURCE/Drivers")


	If Not objFTP.SimpleFTPGetFile("D:\Updates\Inbox\Drivers_update.exe", "Drivers_update.exe") Then
		objFile.Writeline  "Download error : " & objFTP.GetLastErrorMessage
	else
		objFile.Writeline "Drivers_update.exe download is --- OK"
	end if

else
	objFile.Writeline  "Connection error : " & objFTP.GetLastErrorMessage

End if

Open in new window

Avatar of AlexPace
AlexPace
Flag of United States of America image

Check the documentation for your iFTP.CFTP object.

Also, test downloading the same file using a windows FTP client just to verify that there is not some network-related issue outside your code.
Avatar of Muskie12
Muskie12

ASKER

Unfortunately I don't have any docs on this, I inherited the process. My understanding is that it uses a standard Windows API (WinInet?) for the FTP'g.

I was able to download the file without any problem using IE.
SOLUTION
Avatar of RobSampson
RobSampson
Flag of Australia image

Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
See answer
Actually, maybe there is a setting, called INTERNET_OPTION_RECEIVE_TIMEOUT:
http://msdn.microsoft.com/en-us/library/ms918831.aspx

But I don't know how to use it....it looks like you need to control all aspects of the FTP component, rather that use the iFTP.CFTP object.....

Rob.
Rob,
Unfortunately I do not currently have authority to add another cmd line tool to the client so cannot make use of the coreFTP util.

I would need the exact syntax for the TIMEOUT option you mentioned in order to even try it out as I don't have the vbs skills to figure it out.

I do appreciate the attempts to help though...
I found some base code here:
http://www.tek-tips.com/viewthread.cfm?qid=970319

with an ammendment to that here to add the time out:
http://www.tek-tips.com/viewthread.cfm?qid=1285988

This could work in VBA, but it looks pretty lengthy!!

Would you be willing to try a complete re-write that uses the stanrd inbuilt Microsoft Windows FTP command?  That's a little less intuitive, but can be scripted.

Regards,

Rob.
Hey Rob,

I was hoping, as is often the case with problems I submit to EE, that the solution was going to be a simple tweak but that doesn't seem to be the case this time. I had a look at the links but the base code is too much for me to try to figure out/get working.

I haven't found myself in this position before so am not sure what to do. I want to be fair and let you know I can "get by" for now (the number of clients requiring this is low) so I should offer to withdraw or cancel the question? but on the other hand if its not as much work as I think and you're interested in writing the code, I'd certainly be willing to test it. Its quite possible in my environment that the number of clients will increase to the point where I must find a solution.

Comments?

Regards,
Mike
I can certainly provide VBS code that utilises the built in FTP command.  I already have code in my library for that purpose, so I'll knock it together and post it here soon.

Rob.
SOLUTION
Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
The script fails with an error indicating the CD cmd can't find the folder on the FTP server. I confirmed the exact folder path and then looked in the script but don't see anything specifying Passive mode as it is in the script posted above.

How can I set this to try it?
The DOS command line client does not not support passive mode.

That said, changing directories happens on the FTP control channel rather than on the data channel.  This mean changing directories is not impacted by the choice of active mode vs. passive mode.

Try inserting a forward slash character at the beginning of the value of the strFileToGet variable.
Does it help if you change lines 93 to 99 from this:
	strFTPCommands = strUser & vbCrLf & _
	                              strPass & vbCrLf & _
	                              "debug" & VbCrLf & _
	                              "binary" & vbCrLf & _
	                              "prompt" & VbCrLf & _
	                              "cd """ & strRDir & """" & vbCrLf & _
	                              "lcd """ & strLDir & """" & vbCrLf

Open in new window


to this:
	strFTPCommands = strUser & vbCrLf & _
	                              strPass & vbCrLf & _
	                              "debug" & VbCrLf & _
	                              "binary" & vbCrLf & _
	                              "quote pasv" & vbCrLf & _
	                              "prompt" & VbCrLf & _
	                              "cd """ & strRDir & """" & vbCrLf & _
	                              "lcd """ & strLDir & """" & vbCrLf

Open in new window


Regards,

Rob.
Rob -
No luck despite the fact that the pasv cmd is accepted and a response is returned "entering passive mode" along with port numbers.

Alex -
Yes thx, I just had to apply a prefix of "../" to place myself in the correct directory.
That means that the server supports passive mode and is able to enter passive mode.  The DOS ftp client does not support passive mode.
SOLUTION
Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
Unfortunately, there are no MS Office products installed - the machine is a server with Windows 2003.

Just as a test though, I followed your steps on a Win7 PC that sits on a network that allows active FTP and it worked fine. I then took the xls file and copied it to a user's Win7 PC that sits on a network that allows only passive FTP and the macro failed right away with a "Connection Failed" msg. I couldn't really spend any time troubleshooting though as I was remote controlling a user's PC, I could only go as far as verfying I could login to the FTP server manually from a cmd prompt. The code needs to work on the server though so that's where I'd need to run/troubleshoot.
Does the server allow active mode?  If not, is it possible to get a firewall exception?
There's no chance of a firewall exception - the ftp must occur in passive mode.
If you must have Passive Mode then you can't use anything that uses ftp.exe under the hood.  

Since you mentioned you have VB6 that means you can probably create an instance of the object named "InetCtls.Inet.1" which is the old INet control OCX.  You might need to copy it from the VB6 box to the server or just make a throw-away VB6 app that uses it and then use the package and deployment wizard to make a setup file for the throw-away app, and install THAT on the server ... just as a vehicle to get the OCX installed and registered correctly... Ugly hack for sure but it would probably work.

Another possibility is to use objects installed with Internet Explorer to do the work.  Surely the server has IE right?  See if you can't create an instance of "Msxml2.XMLHTTP" or "Microsoft.XMLHTTP" to do the work.  They should be able to do passive mode FTP.
I didn't mention I had VB6 but I did mention I have very little experience with VBS, lol...so what you're suggesting is way outside my skill set.

Yes the server does have IE and I was able to use it to successfully download the file manually.
Try an internet search on Msxml2.XMLHTTP and FTP.
SOLUTION
Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
As I mentioned above after you first submitted the code, there is no MS Office on the server and that's the machine that I need to run the FTP pull from - I had just run it from a user's PC as a test.

I appreciate your work but I don't know if its worth continuing down that road - unless the code could be consolidated and run as an independant script on the server. On the off-chance that it could be, I'll see if I can find an available PC tomorrow am and re-test with the passive setting.
You could certainly plug it into VB6, since the code wouldn't need much, if any, modification, and then compile it as an EXE, but by the sounds if it you don't have VB6 lying around (since it's seriously old now).

But, it also sounds like you can't do that anyway, since you said you don't have authority to add another command line tool.   This basically removes all possibility of achieving your goal, because there are no native ways to make API calls.

Unless....you can install Microsoft Windows Powershell on the server 2003 box, then you could use something similar to this:
# create the FtpWebRequest and configure it
$ftp = [System.Net.FtpWebRequest]::Create("ftp://localhost/me.png")
$ftp = [System.Net.FtpWebRequest]$ftp
$ftp.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$ftp.Credentials = new-object System.Net.NetworkCredential("anonymous","anonymous@localhost")
$ftp.UseBinary = $true
$ftp.UsePassive = $true
# read in the file to upload as a byte array
$content = [System.IO.File]::ReadAllBytes("C:\me.png")
$ftp.ContentLength = $content.Length
# get the request stream, and write the bytes into it
$rs = $ftp.GetRequestStream()
$rs.Write($content, 0, $content.Length)
# be sure to clean up after ourselves
$rs.Close()
$rs.Dispose()

Open in new window


Regards,

Rob.
There's more Powershell code here that's more complete:
https://github.com/ruslander/Nutshells/blob/master/ftp-ls.ps1

Rob.
Ahh...Powershell may indeed be do-able. I'll start down that road with your links/code. Hopefully today or Monday I'll have an update.
ASKER CERTIFIED SOLUTION
Link to home
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
I can't find anything that might help...it worked for me on some test files, although I only tested 20MB.

You should definately try out Powershell 2.0 though.

This may help:
http://blogs.technet.com/b/bshukla/archive/2010/04/12/ignoring-ssl-trust-in-powershell-system-net-webclient.aspx

But I'm not sure.  This might apply to you, but it doesn't sound like it:
http://support.microsoft.com/kb/962928

At this point, I think you might be best served if you post a new question in the Powershell zone, with your current code.

Regards,

Rob.
Experts - I don't ask a lot of questions in EE and so would appreciate your feedback to this question:

Is there any other way to award points other than marking a comment as a partial or complete solution?

Awarding points is not a concern as I'm a paid subscriber but flagging expert responses as solutions when they weren't (as in this case) seems misleading and I'm thinking solely of the people doing searches for similar problems and finding my question they may wade thru the entire thing only to ultimately discover there was no solution.

Do I understand things correctly or am I missing something?

Comments from Alex re the FTP and his specific suggestion for an internet search led me quickly to the (interesting) bitsadmin tool and of course all your code and Powershell suggestions/links which finally pushed me to jump into PS.

Anyways, appreciate the help gents, I'll wait a day or so for any feedback and then award points.
In my opinion, there are a couple of viable suggestions, even if they are not 100% working, which would be difficult to guarantee anyway, given all sorts of different environments.

My first comment http:#a38025326 offers a perfectly valid solution for most people, who would be able to utilise CoreFTP.

The VBScript solution in comment http:#a38051796 also works for Active FTP connections, so may be useful to some there as well (the same code has been accepted in many other question here on EE).

My VBA code in comment http:#a38060828 works in any Office program, and could also be plugged straight into VB6, and along with comment http:#a38073909 will then work in passive mode as well.

Finally, your Powershell code that you posted in comment http:#a38097453 works perfectly for me.

Don't take what I'm saying as a dig against you, I just feel that there's plenty of options here that won't be misleading for others.  To me, it appears to be more of a limitation of your environment somehow that's causing the issues, although I can't say what that would be as I'm not an FTP expert.

I have requested attention from the Mods to further direct you as to what you can do with this question.

Regards,

Rob.
Hey Rob,

I was waiting til today to close but see that the moderator has already initiated the process so I'll let it continue as recommended.

I may have created the wrong impression with my comment requesting feedback - I check my comments b4 posting but upon review, I think I could have worded it a bit better. Without question there was a lot of worthwhile info provided and the work you did was certainly not lost on me.

My question about whether there is another way to award points has been answered and I appreciate the clear, objective feedback. I have a better understanding now.
Hi Muskie12, that's no problem.  Thanks.

Rob.