Downloading large files with VBScript
Downloading (well doing anything really) is a pain with VBScript, but recently, while writing a script to download, install and update apps from the net, I discovered that the MSXML2.XMLHTTP COM object can't download large files. Well, it isn't necessarily large files that break it, but files that take a while to download. There seems to be an in-built timeout, and once that has been exceeded, it will cut the connection.
The only evidence of this is the status code - it will return 0.
Turns out you need to use MSXML2.ServerXMLHTTP in order to set timeouts to a longer period. The relevant sub-routine is setTimeouts. Note this doesn't seem to be a timeout in the traditional sense - this timeout value specifies how long the entire response can take, not how long to wait if there is no response from the server.
Below is some code that wraps all this in a neat function.
Function Download ( ByVal strUrl, ByVal strDestPath, ByVal overwrite ) Dim intStatusCode, objXMLHTTP, objADOStream, objFSO Set objFSO = CreateObject("Scripting.FileSystemObject") ' if the file exists already, and we're not overwriting, quit now If Not overwrite And objFSO.FileExists(strDestPath) Then WScript.Echo "Already exists - " & strDestPath Download = True Exit Function End If WScript.Echo "Downloading " & strUrl & " to " & strDestPath ' Fetch the file ' need to use ServerXMLHTTP so can set timeouts for downloading large files Set objXMLHTTP = CreateObject("MSXML2.ServerXMLHTTP") objXMLHTTP.open "GET", strUrl, false objXMLHTTP.setTimeouts 1000 * 60 * 1, 1000 * 60 * 1, 1000 * 60 * 1, 1000 * 60 * 7 objXMLHTTP.send() intStatusCode = objXMLHTTP.Status If intStatusCode = 200 Then Set objADOStream = CreateObject("ADODB.Stream") objADOStream.Open objADOStream.Type = 1 'adTypeBinary objADOStream.Write objXMLHTTP.ResponseBody objADOStream.Position = 0 'Set the stream position to the start 'If the file already exists, delete it. 'Otherwise, place the file in the specified location If objFSO.FileExists(strDestPath) Then objFSO.DeleteFile strDestPath objADOStream.SaveToFile strDestPath objADOStream.Close Set objADOStream = Nothing End If Set objXMLHTTP = Nothing Set objFSO = Nothing WScript.Echo "Status code: " & intStatusCode & VBNewLine If intStatusCode = 200 Then Download = True Else Download = False End If End Function