How can I download a file with batch file without

2019-01-02 16:08发布

问题:

First to clarify this question is aimed to HTTP(s) download .For FTP may be I'll ask (and answer) another question. Here are some similar questions - but I want to be more precise .

Besides excluding external tools I want the solution(s) to be applicable for the widest possible types of windows machines (including XP,Win2003,Vista which still have big enough share). Also as WSH is one of the possible options I prefer no using of temp files and everything to be packed in a single .bat file (which is possible with both jscript and vbscript).

What are possible approaches.

  1. "Pure" batch solution with BITSADMIN - a command line utility available on every windows machine .It's not pretty convenient but is an/the only option where no other scripting language should be used.
  2. Using WSH - Three approaches are possible - WinHTTP , MSXML2.XMLHTTP ,InternetExlorer.Application - all of them are accessible ActiveX objects in order of how I prefer them.WinHTTP and MSXML2.XMLHTTP are pretty similar in their capabilities but WinHTTP has a reputation of more stable.InternetExlorer.Application is in fact just the Internet explorer accessible through ActiveX object and some UI elements are unavoidable (are they?) so I'll skip this one.
  3. Using .NET - It's possible to create a hybrid batch file with all the three default .NET compilers (Jscript.net , VB.Net , C#) with Jscript.net there is no redundant error messages so I'll prefer it.If we ignore the fact that there's a compiled .exe all the code is in one file ,so according to me this fits in the requirements :-) .With .NET we can use System.Net.WebClient or System.Net.HttpWebRequest (the WebClient relies on it) or
    System.Web.HttpRequest , but for now I'll post only System.Net.WebClient solution.And even more same ActiveX objects accessible with WSH are available here too.So there are really many ways to dowanload a file with .Net.May be in the future I'll update my answer.Anyway only the Webclient is especially designed for download.
  4. Using powershell - has same possibilities as .NET but with less chances to be installed on all machines you can meet.So I'll skip this one too.

回答1:

The answers.All scripts should be saved with .bat/.cmd extensions and can be used directly as batch scripts.

1) Certutuil:

certutil.exe -urlcache -split -f "https://download.sysinternals.com/files/PSTools.zip" pstools.zip

CertUtil command can be abused to download a file from internet.Available by default in windows since Vista.For WinXP Server 2003 Administration Tools are needed.

2) Bitsadmin :

simplest possible way to use it

bitsadmin /transfer myDownloadJob /download /priority normal http://downloadsrv/10mb.zip c:\10mb.zip

Or (you eventually will need this if you want to add credentials , proxy and etc.)

   @echo off
    setlocal

    :: uses bitsadmin utility to download a file
    :: bitsadmin is not available in winXP Home edition
    :: the only way to download a file with 'pure' batch
   :download

    if "%2" equ "" (
      call :help
      exit /b 5
   )

   if "%1" equ "" (
      call :help
      exit /b 6
   )
    set url=%~1
    set file=%~2
    rem ----
    if "%~3" NEQ "" (
        set /A timeout=%~3
    ) else (
        set timeout=5
    )

    bitsadmin /cancel download >nul
    bitsadmin /create /download download >nul 
    call bitsadmin /addfile download "%url%" "%CD%\%file%" >nul
    bitsadmin /resume download >nul 
    bitsadmin /setproxysettings download AUTODETECT >nul

    set /a attempts=0
    :repeat
    set /a attempts +=1
    if "%attempts%" EQU "10" (
        echo TIMED OUT
        endlocal
        exit /b 1
    )
    bitsadmin /info download /verbose | find  "STATE: ERROR"  >nul 2>&1 && endlocal &&  bitsadmin /cancel download && echo SOME KIND OF ERROR && exit /b 2
    bitsadmin /info download /verbose | find  "STATE: SUSPENDED" >nul 2>&1 && endlocal &&  bitsadmin /cancel download &&echo FILE WAS NOT ADDED && exit /b 3
    bitsadmin /info download /verbose | find  "STATE: TRANSIENT_ERROR" >nul 2>&1 && endlocal &&  bitsadmin /cancel download &&echo TRANSIENT ERROR && exit /b 4
    bitsadmin /info download /verbose | find  "STATE: TRANSFERRED" >nul 2>&1 && goto :finishing 

   w32tm /stripchart /computer:localhost /period:1 /dataonly /samples:%timeout%  >nul 2>&1
    goto :repeat
    :finishing 
    bitsadmin /complete download >nul
    echo download finished
    endlocal
   goto :eof

   :help
   echo %~n0 url file [timeout]
   echo.
   echo  url - the source for download
   echo  file - file name in local directory where the file will be stored
   echo  timeout - number in seconds between each check if download is complete (attempts are 10)
   echo.
   goto :eof

3) - WinHttp and WSH (SSL/certificate and Proxy options have been never tested ...). Here's a ready to use script that uses WinHttpRequest .It can perform whole range of http requests and can be used for downloading of files too (not too big files).If you need you can also add your own authentication headers.

call winhhtpjs.bat https://example.com/files/some.zip -saveTo c:\somezip.zip 

4) MSXML2.XMLHTTP and WSH (better use WinHTTP)(SSL/certificate and Proxy options have been never tested ...)

@if (@X)==(@Y) @end /* JScript comment
    @echo off

    rem :: the first argument is the script name as it will be used for proper help message
    cscript //E:JScript //nologo "%~f0" "%~nx0" %*

    exit /b %errorlevel%

@if (@X)==(@Y) @end JScript comment */

// used resources
//http://www.codeproject.com/Tips/506439/Downloading-files-with-VBScript
//http://blogs.msdn.com/b/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
//https://msdn.microsoft.com/en-us/library/ie/ms535874(v=vs.85).aspx
//https://msdn.microsoft.com/en-us/library/aa923283.aspx
//https://msdn.microsoft.com/en-us/library/ms759148(v=vs.85).aspx
//https://msdn.microsoft.com/en-us/library/ms759148(v=vs.85).aspx
//https://msdn.microsoft.com/en-us/library/ms760236(v=vs.85).aspx
//http://stackoverflow.com/questions/20712635/providing-authentication-info-via-msxml2-serverxmlhttp
//https://msdn.microsoft.com/en-us/library/ms763680(v=vs.85).aspx
//https://msdn.microsoft.com/en-us/library/ms757849(v=vs.85).aspx
//http://fm4dd.com/programming/shell/microsoft-vbs-http-download.htm
//http://stackoverflow.com/questions/11573022/vba-serverxmlhttp-https-request-with-self-signed-certificate
//http://www.qtcentre.org/threads/44629-Using-XMLHttpRequest-for-HTTPS-Post-to-server-with-SSL-certificate

// global variables and constants
var ARGS = WScript.Arguments;
var scriptName=ARGS.Item(0);

var url="";
var saveTo="";

var user=0;
var pass=0;

var proxy=0;
var bypass="";
var proxy_user=0;
var proxy_pass=0;

var certificate=0;

var force=true;

//ActiveX objects
//Use the right version of MSXML
/*var progIDs = [ 'Msxml2.DOMDocument.6.0', 'Msxml2.DOMDocument.5.0', 'Msxml2.DOMDocument.4.0', 'Msxml2.DOMDocument.3.0', 'Msxml2.DOMDocument' ]
for (var i = 0; i < progIDs.length; i++) {
    try {
        var XMLHTTPObj = new ActiveXObject(progIDs[i]);
    }catch (ex) {       
    }
}

if typeof  XMLHTTPObj === 'undefined'{
    WScript.Echo ("You are using too ancient windows or you have no installed IE");
    WScript.Quit(1);
}*/

var XMLHTTPObj = new ActiveXObject("MSXML2.XMLHTTP");
var FileSystemObj = new ActiveXObject("Scripting.FileSystemObject");
var AdoDBObj = new ActiveXObject("ADODB.Stream");


function printHelp(){
    WScript.Echo(scriptName + " - downloads a file through HTTP");
    WScript.Echo(scriptName + " url localfile [-force yse|no] [-user username -password password] [-proxy proxyserver:port -bypass bypass_list]");
    WScript.Echo("                          [-proxyuser proxy_username -proxypassword proxy_password] [-certificate certificateString]");
    WScript.Echo("-force  - decide to not or to overwrite if the local exists");
    WScript.Echo("proxyserver:port - the proxy server");
    WScript.Echo("bypass- bypass list can be \"\" if you don't need it");
    WScript.Echo("proxy_user , proxy_password - credentials for proxy server");
    WScript.Echo("user , password - credentials for the server");
    WScript.Echo("certificate - location of SSL certificate");
    WScript.Echo("Example:");
    WScript.Echo(scriptName +" http://somelink.com/somefile.zip c:\\somefile.zip -certificate \"LOCAL_MACHINE\\Personal\\My Middle-Tier Certificate\"");    
}

function parseArgs(){
    //
    if (ARGS.Length < 3) {
        WScript.Echo("insufficient arguments");
        printHelp();
        WScript.Quit(43);
    }
    url=ARGS.Item(1);
    saveTo=ARGS.Item(2);

    if(ARGS.Length % 2 != 1) {
        WScript.Echo("illegal arguments");
        printHelp();
        WScript.Quit(44);
    }

    for (var i=3;i<ARGS.Length-1;i=i+2){
        if(ARGS.Item(i).toLowerCase=="-force" && ARGS.Item(i+1)=='no'){
            force=false;
        }

        if(ARGS.Item(i).toLowerCase=="-user"){
            user=ARGS.Item(i+1);
        }

        if(ARGS.Item(i).toLowerCase=="-password"){
            pass=ARGS.Item(i+1);
        }

        if(ARGS.Item(i).toLowerCase=="-proxy"){
            proxy=ARGS.Item(i+1);
        }

        if(ARGS.Item(i).toLowerCase=="-bypass"){
            bypass=ARGS.Item(i+1);
        }

        if(ARGS.Item(i).toLowerCase=="-proxyuser"){
            proxy_user=ARGS.Item(i+1);
        }

        if(ARGS.Item(i).toLowerCase=="-proxypassword"){
            proxy_pass=ARGS.Item(i+1);
        }

        if(ARGS.Item(i).toLowerCase=="-certificate"){
            certificate=ARGS.Item(i+1);
        }
    }
}

function existsItem(path){
    return FileSystemObj.FolderExists(path)||FileSystemObj.FileExists(path);
}

stripTrailingSlash = function(path){
    while (path.substr(path.length - 1,path.length) == '\\') {
        path=path.substr(0, path.length - 1);
    }
    return path;
}

function deleteItem(path){
    if (FileSystemObj.FileExists(path)){
        FileSystemObj.DeleteFile(path);
        return true;
    } else if (FileSystemObj.FolderExists(path) ) {
        FileSystemObj.DeleteFolder(stripTrailingSlash(path));
        return true;
    } else {
        return false;
    }
}

function writeFile(fileName,data ){
    AdoDBObj.Type = 1;       
    AdoDBObj.Open();
    AdoDBObj.Position=0;
    AdoDBObj.Write(data);
    AdoDBObj.SaveToFile(fileName,2);
    AdoDBObj.Close();   
}

function download( url,file){
    if (force && existsItem(file)){
        if(!deleteItem(file)){
            WScript.Echo("Unable to delete "+ file);
            WScript.Quit(8);
        }
    }else if (existsItem(file)){
        WScript.Echo("Item " + file + " already exist");
        WScript.Quit(9);
    }



    if (proxy!=0 && bypass !="") {
        //https://msdn.microsoft.com/en-us/library/ms760236(v=vs.85).aspx
        XMLHTTPObj.setProxy(SXH_PROXY_SET_DIRECT,proxy,bypass);
    } else if (proxy!=0) {
        XMLHTTPObj.setProxy(SXH_PROXY_SET_DIRECT,proxy,"");
    }



    if (proxy_user!=0 && proxy_pass!=0 ) {
        //https://msdn.microsoft.com/en-us/library/ms763680(v=vs.85).aspx
        XMLHTTPObj.setProxyCredentials(proxy_user,proxy_pass);
    }

    if(certificate!=0) {
        //https://msdn.microsoft.com/en-us/library/ms763811(v=vs.85).aspx
        WinHTTPObj.setOption(3,certificate);
    }

    if (user!=0 && pass!=0){
        //https://msdn.microsoft.com/en-us/library/ms757849(v=vs.85).aspx
         XMLHTTPObj.Open('GET',url,false,user,pass);
    } else {
        XMLHTTPObj.Open('GET',url,false);
    }



    XMLHTTPObj.Send();
    var status=XMLHTTPObj.Status

    switch(status){
        case 200:
            WScript.Echo("Status: 200 OK");
            break;
        case 401:
            WScript.Echo("Status: 401 Unauthorized");
            WScript.Echo("Check if correct user and password were provided");
            WScript.Quit(401);
            break;
        case 407:
            Wscript.Echo("Status:407 Proxy Authentication Required");
            Wscript.Echo("Check if correct proxy user and password were provided");
            WScript.Quit(407);
            break;
        default:
            Wscript.Echo("Status: "+status);
            WScript.Echo("Try to help yourself -> https://en.wikipedia.org/wiki/List_of_HTTP_status_codes");
            WScript.Quit(status);
    }
    writeFile(file,XMLHTTPObj.ResponseBody);
}

function main(){
    parseArgs();
    download(url,saveTo);
}
main();

5) .NET and webclient (Here's no SSL option.Will try to add it. Poxy options have never been tested)

@if (@X)==(@Y) @end /* JScript comment
@echo off
setlocal

for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

::if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
::)

 %~n0.exe %*

endlocal & exit /b %errorlevel%


*/

//todo SSL Support
//todo Better help message
//todo check if local file exists


import System;
import System.Net.WebClient;
import System.Net.NetworkCredential;
import System.Net.WebProxy;
import System.Uri;
import System.Security.Cryptography.X509Certificates;

var arguments:String[] = Environment.GetCommandLineArgs();

var url=0;
var toFile=0;
var force=true;

var user=0;
var password=0;

var proxy=0;
var bypass=0;
var proxy_user=0;
var proxy_pass=0;

var certificate=0;

function printHelp(){
    Console.WriteLine(arguments[0] + "download from url to a file");
    Console.WriteLine(arguments[0] + "<url> <file> [-user user -password password] [-proxy proxy] [-proxy_user proxy.user -proxy_pass proxy.pass]");

}

function parseArgs(){

    if (arguments.length < 3) {
        Console.WriteLine("Wrong arguments");
        printHelp();
        Environment.Exit(1);
    }

    if (arguments.length %2 != 1) {
        Console.WriteLine("Wrong number arguments");
        printHelp();
        Environment.Exit(2);    
    }

    url=arguments[1];
    toFile=arguments[2];

    for (var i=3;i<arguments.length-1;i=i+2){
        var arg=arguments[i].ToLower();
        switch (arg){
            case  "-user" :
                user=arguments[i+1];
                break;
            case "-password" :
                password=arguments[i+1];
                break;
            case "-proxy" :
                proxy=arguments[i+1];
                break;
            case "-proxy_user" :
                proxy_user=arguments[i+1];
                break;
            case "-proxy_pass" :
                proxy_pass=arguments[i+1];
                break;
            case "-bypass" :
                bypass=[arguments[i+1]];
                break;
            /*case "-certificate" :
                certificate=arguments[i+1];
                break;*/
            default:
                Console.WriteLine("Invalid argument "+ arguments[i]);
                printHelp();
                Environment.Exit(3);
        }
    }

}

function download(){
    var client:System.Net.WebClient = new System.Net.WebClient();

    if (user!=0 && password!=0){
        client.Credentials=new System.Net.NetworkCredential(user, password);
    }

    if (proxy!=0){
        var webproxy =new System.Net.WebProxy();
        webproxy.Address=new Uri(proxy);
        if (proxy_user!=0 && proxy_pass!=0){
            webproxy.Credentials=new System.Net.NetworkCredential(proxy_user,proxy_pass);
        }
        webproxy.UseDefaultCredentials =false;

        if (bypass!=0){
            webproxy.BypassList=bypass;
            webproxy.BypassProxyOnLocal = false;
        }
        client.Proxy=webproxy;
    }

    try {
        client.DownloadFile(arguments[1], arguments[2]);
    } catch (e) {
        Console.BackgroundColor = ConsoleColor.Green;
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("\n\nProblem with downloading " + arguments[1] + " to " + arguments[2] + "Check if the internet address is valid");
        Console.ResetColor();
        Environment.Exit(5);
    }
}

 parseArgs();
 download();


标签: