如何在不使用任何外部工具的情况下下载包含批处理文件的文件?

npo*_*aka 17 .net wsh batch-file jscript

首先澄清这个问题的目的是HTTP(s)下载.对于FTP,我可能会问(并回答)另一个问题.以下是一些类似的问题 - 但我希望更加准确.

除了排除外部工具,我希望解决方案适用于最广泛类型的Windows机器(包括仍然有足够大份额的XP,Win2003,Vista).另外,作为WSH可能的选项之一,我不喜欢使用临时文件和所有要打包在单个.bat文件中的东西(jscript和vbscript都可以).

什么是可能的方法.

  1. 使用BITSADMIN的 "纯"批处理解决方案- 每台Windows机器上都有一个命令行实用程序.它不是很方便,但它是唯一一个不应该使用其他脚本语言的选项.
  2. 使用WSH - 可能有三种方法 - WinHTTP,MSXML2.XMLHTTP ,InternetExlorer.Application - 它们都是可访问的ActiveX对象,按照我喜欢的顺序排列.WinHTTP和MSXML2.XMLHTTP的功能非常相似,但WinHTTP的声誉是更稳定.InternetExlorer.Application实际上只是可以通过ActiveX对象访问的Internet Explorer,一些UI元素是不可避免的(是吗?)所以我会跳过这个.
  3. 使用.NET - 可以使用Jscript.net创建一个包含所有三个默认.NET编译器(Jscript.net,VB.Net,C#)的混合批处理文件,没有冗余错误消息,所以我更喜欢它.如果我们忽略这样一个事实,即编译的.exe所有代码都在一个文件中,所以根据我的说法,这符合要求:-).使用.NET我们可以使用System.Net.WebClient或System.Net.HttpWebRequest(WebClient)依赖它)或
    System.Web.HttpRequest,但是现在我只发布System.Net.WebClient解决方案.这里也可以使用WSH访问更多相同的ActiveX对象.所以有很多方法可以下载文件与.Net.May将来我会更新我的答案.无论如何只有Webclient是专门为下载而设计的.
  4. 使用powershell - 与.NET具有相同的可能性,但是你可以在所有机器上安装的机会较少.所以我也会跳过这个.

npo*_*aka 35

答案.所有脚本都应该使用.bat/ .cmdextensions 保存,并且可以直接用作批处理脚本.

1)Certutuil:

certutil.exe -urlcache -split -f "https://download.sysinternals.com/files/PSTools.zip" pstools.zip
Run Code Online (Sandbox Code Playgroud)

可以滥用CertUtil命令从Internet下载文件.默认情况下可以在Windows中使用Vista.For WinXP Server 2003管理工具是必需的.

2) Bitsadmin:

最简单的方法来使用它

bitsadmin /transfer myDownloadJob /download /priority normal http://downloadsrv/10mb.zip c:\10mb.zip
Run Code Online (Sandbox Code Playgroud)

或者(如果要添加凭据,代理等,最终将需要此功能)

   @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
Run Code Online (Sandbox Code Playgroud)

3) - WinHttp和WSH (SSL /证书和代理选项从未经过测试......).是一个使用WinHttpRequest的现成脚本.它可以执行所有的http请求,也可以用于下载文件(不是太大的文件).如果需要,还可以添加自己的身份验证头.

call winhhtpjs.bat https://example.com/files/some.zip -saveTo c:\somezip.zip 
Run Code Online (Sandbox Code Playgroud)

4) MSXML2.XMLHTTP和WSH (更好地使用WinHTTP)(SSL /证书和代理选项从未经过测试......)

@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();
Run Code Online (Sandbox Code Playgroud)

5) .NET和webclient (这里没有SSL选项.会尝试添加它.Poxy选项从未经过测试)

@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();
Run Code Online (Sandbox Code Playgroud)

  • `bitsadmin` 可以用来下载网页上的每个文件吗? (2认同)
  • @The WSH JScript 有多个问题。`WScript` 区分大小写,-saveTo 用作未命名参数,`XMLHTTPObj` 有时拼错为 `WinHTTPObj`。我还建议您使用 `WScript.ScriptName` 来简化直接 cscript 调用。 (2认同)
  • 不要忘记powershell命令`(New-Object Net.WebClient).DownloadFile('Source, Dest')`。适用于 powershell v2,未测试 v1。它是唯一可以在 PS 和 CMD 这么低的操作系统上下载文件的脚本。 (2认同)
  • @npocmaka嗨,那么,我可以从文件中仅获取最后修改日期,而不是使用您的答案/代码下载它们吗?不管怎样,谢谢,对不起我的/en... (2认同)
  • 我发现我需要“/dynamic”开关。例如:`bitsadmin /transfer myDownloadJob /dynamic /download /priority foreground https://github.com/microsoft/vscode-cpptools/releases/latest/download/cpptools-win32.vsix %USERPROFILE%\Downloads\cpptools-win32。 VSIX` (2认同)