PowerShell文件下载全攻略:Invoke-WebRequest、WebClient与BitsTransfer实战解析
1. 项目概述为什么需要掌握PowerShell下载文件在日常的Windows系统管理、自动化运维甚至是临时的文件抓取任务中我们常常会遇到需要从网络下载文件的情况。对于习惯了图形界面的用户第一反应可能是打开浏览器找到链接点击下载。但对于需要批量处理、集成到脚本中或者在无图形界面的服务器核心Server Core环境下工作的系统管理员和开发者来说掌握命令行下的文件下载能力是一项不可或缺的核心技能。PowerShell作为Windows平台上功能强大的脚本语言和命令行外壳内置了多种用于HTTP/HTTPS/FTP文件下载的cmdlet和.NET类。它们各有侧重有的简单直接有的功能丰富有的则专为后台和大文件传输优化。理解并熟练运用这些方法能让你编写的脚本更健壮、更高效也能在远程管理或自动化部署中游刃有余。本文将深入拆解PowerShell中下载文件的三种主流方法Invoke-WebRequest、System.Net.WebClient以及BitsTransfer模块并结合大量实际场景为你提供从入门到精通的详细指南。2. 三种核心方法深度解析与选型指南面对一个下载任务选择哪种方法并非随意为之。每种方法背后都有其设计哲学和适用场景。盲目选择可能会导致脚本效率低下、功能受限甚至在不支持的环境中运行失败。下面我们从设计初衷、核心特性与适用场景三个维度对它们进行彻底解构。2.1 Invoke-WebRequest面向Web的“瑞士军刀”Invoke-WebRequest别名iwr、curl、wget是PowerShell 3.0引入的cmdlet它被设计成一个全面的HTTP客户端。其核心思想是模拟浏览器行为不仅能获取文件内容还能解析HTML、处理表单、管理Cookie和会话。核心特性丰富的响应对象它返回一个包含状态码、头信息、原始内容流、已解析的HTML DOM等丰富属性的对象让你能对HTTP响应进行精细操作。内置的进度显示默认情况下下载大文件时会显示进度条对用户非常友好。强大的参数集支持-Headers自定义请求头、-Method指定HTTP方法、-Body提交数据、-SessionVariable维持会话状态、-Proxy设置代理等。内容处理灵活可以通过管道将内容传递给其他cmdlet进行处理或者直接保存到文件。适用场景需要解析网页内容、抓取特定数据如提取链接、文本的场景。需要与需要Cookie或会话保持的Web API进行交互。下载文件的同时需要检查HTTP状态码、响应头等元信息。在交互式命令行中执行一次性下载并希望看到进度反馈。选型理由当你需要与Web进行“对话”而不仅仅是“搬运”数据时Invoke-WebRequest是最佳选择。它提供了HTTP协议层面的完整控制。2.2 System.Net.WebClient轻量高效的.NET经典System.Net.WebClient是一个.NET Framework中的类在PowerShell中可以直接通过New-Object创建实例使用。它的设计更偏向于一个简单、直接的网络数据下载器。核心特性接口简洁直观主要方法如.DownloadFile()用于下载到文件.DownloadString()用于下载为文本字符串.DownloadData()用于下载为字节数组功能划分清晰。同步与异步支持除了同步方法还提供了.DownloadFileAsync()等异步方法允许在下载时不阻塞主线程。可配置性可以通过.Headers属性添加请求头通过.Proxy属性设置代理通过.Credentials属性处理认证。无内置进度条默认不显示下载进度需要自己通过事件如.DownloadProgressChanged来实现。适用场景脚本中需要快速、简洁地下载一个已知URL的文件无需复杂交互。需要将下载内容直接作为字符串或字节数组在内存中处理而不先落盘。在PowerShell 2.0等旧版本环境中运行Invoke-WebRequest需要3.0。对执行速度有轻微要求WebClient在某些简单场景下开销略低于Invoke-WebRequest。选型理由如果你追求的是“快、准、稳”地将一个远程文件弄到本地且不需要网页解析等高级HTTP功能WebClient的简洁API会让你感到非常舒适。它是许多传统脚本中的主力下载工具。2.3 BitsTransfer后台智能传输服务BitsTransfer指的是后台智能传输服务它是一个Windows系统服务专注于优化文件传输。在PowerShell中我们通过Import-Module BitsTransfer引入相关cmdlet主要是Start-BitsTransfer。核心特性后台与断点续传这是其最大亮点。传输由系统服务管理即使关闭PowerShell窗口或重启电脑任务也可在后台继续或恢复。网络感知与带宽节制BITS能感知网络成本如按流量计费的网络并自动调整传输行为。可以设置传输优先级和带宽限制。专为大文件与不稳定网络设计非常适合下载操作系统ISO镜像、大型安装包等在网络中断后能从中断处继续无需重头开始。需要管理传输任务下载任务有状态传输中、已暂停、已完成等需要特定的cmdlet如Get-BitsTransferRemove-BitsTransfer进行查询和管理。适用场景下载体积巨大如数GB的文件。网络环境不稳定存在中断风险。希望下载任务在后台静默进行不干扰前台工作且能跨会话持久化。在无人值守的自动化任务如定时更新脚本中下载关键文件。选型理由当你的下载任务关乎“可靠性”和“资源管理”时BitsTransfer是无可争议的王者。它牺牲了一点使用的简便性换来了企业级传输的稳健性。注意BitsTransfer服务默认在Windows系统上运行但在某些精简版或严格锁定的系统上可能被禁用。如果你的脚本需要广泛分发这一点需要确认。3. 核心细节解析与实操要点了解了宏观选型我们深入到每种方法的实操细节中。这里不仅有“怎么做”更有“为什么这么做”以及“怎么做更好”。3.1 Invoke-WebRequest 的进阶用法与坑位指南Invoke-WebRequest功能强大但参数繁多使用不当容易踩坑。基础下载与保存最直接的用法是使用-OutFile参数。# 基本下载 Invoke-WebRequest -Uri https://example.com/file.zip -OutFile C:\Downloads\file.zip # 使用别名 iwr (更简洁) iwr https://example.com/file.zip -OutFile .\file.zip处理需要认证或特殊头信息的网站有些网站会检查User-Agent或者需要登录后的Cookie。# 自定义User-Agent模拟浏览器访问 $headers { User-Agent Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 } iwr -Uri https://some-site.com/data.csv -Headers $headers -OutFile data.csv # 使用会话保存Cookie例如登录后下载 $loginResponse iwr -Uri https://example.com/login -Method Post -Body {usernameuser; passwordpass} -SessionVariable mySession # $mySession 变量现在包含了登录后的会话Cookie iwr -Uri https://example.com/dashboard/report.pdf -WebSession $mySession -OutFile report.pdf跳过SSL/TLS证书验证谨慎使用在开发测试环境遇到自签名证书错误时可以临时跳过检查。生产环境强烈不建议使用。# 该方法仅影响当前PowerShell会话且会降低安全性 [System.Net.ServicePointManager]::ServerCertificateValidationCallback { $true } iwr -Uri https://internal-test.com/file.exe -OutFile file.exe # 操作完成后建议恢复回调 [System.Net.ServicePointManager]::ServerCertificateValidationCallback $null实操心得与避坑进度条与静默模式默认进度条在自动化脚本中可能会产生多余输出。使用-UseBasicParsing参数可以禁用进度条和HTML解析提升速度并减少输出。在PowerShell 6.0 (Core) 及以上版本-UseBasicParsing已废弃默认行为就是基础解析。# PowerShell 5.1 及以下用于静默下载 iwr -Uri $url -OutFile $localPath -UseBasicParsing错误处理默认情况下当HTTP状态码为4xx或5xx时Invoke-WebRequest会抛出异常并终止脚本。使用try-catch块来优雅处理。try { $response iwr -Uri $url -ErrorAction Stop # 处理成功响应 } catch [System.Net.WebException] { Write-Warning 下载失败: $($_.Exception.Message) # 可以检查 $_.Exception.Response.StatusCode 获取具体状态码 }大文件内存问题Invoke-WebRequest会先将响应内容完整加载到内存再写入-OutFile。对于超大文件这可能消耗大量内存。虽然它支持分块传输编码但对于极端情况BitsTransfer是更好的选择。3.2 WebClient 的同步与异步之道WebClient的使用更像是在调用一个封装好的库函数。同步下载这是最常用的方式代码会阻塞直到下载完成。# 创建WebClient对象 $webClient New-Object System.Net.WebClient # 下载到文件 $webClient.DownloadFile(https://example.com/picture.jpg, C:\Downloads\picture.jpg) # 下载为字符串适用于文本文件、JSON、XML API $jsonString $webClient.DownloadString(https://api.example.com/data.json) $content $webClient.DownloadData(https://example.com/binary.bin) # 下载为字节数组 # 记得释放资源虽然不是严格必须但是好习惯 $webClient.Dispose()异步下载与进度监控异步下载不会阻塞脚本执行适合在GUI应用或需要同时执行其他任务的脚本中使用。$webClient New-Object System.Net.WebClient $url https://example.com/largefile.iso $localPath largefile.iso # 注册进度改变事件 Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -Action { param($sender, $e) Write-Progress -Activity 下载中 -Status 进度: -PercentComplete $e.ProgressPercentage } # 注册下载完成事件 Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -Action { param($sender, $e) Write-Host 下载完成 -ForegroundColor Green # 取消事件注册 Get-EventSubscriber | Unregister-Event } # 开始异步下载 $webClient.DownloadFileAsync([Uri]$url, $localPath) # 此时脚本可以继续做其他事情... # 如果要等待下载完成可以循环检查或使用 Wait-Event实操心得与避坑编码问题当使用.DownloadString()下载文本时如果网站编码不是UTF-8可能会出现乱码。WebClient默认使用系统的ANSI代码页。可以通过设置.Encoding属性来指定。$webClient.Encoding [System.Text.Encoding]::UTF8 $content $webClient.DownloadString($url)超时设置WebClient本身没有直接的超时属性。但它的底层操作会遵循System.Net.ServicePointManager的默认设置。对于更精细的控制可以考虑使用System.Net.Http.HttpClient更现代但稍复杂。对象释放在循环中大量创建WebClient对象时显式调用.Dispose()有助于及时释放网络连接资源。使用try-finally块确保释放。$wc $null try { $wc New-Object System.Net.WebClient $wc.DownloadFile($url, $path) } finally { if ($wc -ne $null) { $wc.Dispose() } }3.3 BitsTransfer 的任务管理与策略配置BitsTransfer的使用模式是“启动任务-管理任务”。基础后台下载# 导入模块Windows PowerShell 通常已默认导入但显式导入是好习惯 Import-Module BitsTransfer # 启动一个后台传输任务 Start-BitsTransfer -Source https://example.com/windows.iso -Destination D:\ISOs\windows.iso # 这个命令会立即返回下载在后台由BITS服务进行。查看与管理任务# 查看所有BITS传输任务 Get-BitsTransfer # 查看更详细的任务信息 Get-BitsTransfer | Format-List * # 暂停某个任务通过Job ID Suspend-BitsTransfer -BitsJob JobId # 恢复被暂停的任务 Resume-BitsTransfer -BitsJob JobId # 删除取消某个任务 Remove-BitsTransfer -BitsJob JobId # 等待所有BITS任务完成 Get-BitsTransfer | Complete-BitsTransfer高级配置# 设置作业优先级High / Normal / Low / Foreground Start-BitsTransfer -Source $url -Destination $path -Priority High # 设置作业显示名称便于管理 Start-BitsTransfer -Source $url -Destination $path -DisplayName 月度数据备份包下载 # 设置自定义HTTP请求头 $headers {Custom-Header MyValue} Start-BitsTransfer -Source $url -Destination $path -Headers $headers # 设置传输策略例如仅在非计费网络如以太网下载 Start-BitsTransfer -Source $url -Destination $path -TransferPolicy Unrestricted # TransferPolicy 可选: Unrestricted (默认), NotRoaming, NoSurcharge, Standard (最严格)实操心得与避坑任务持久化与清理BITS任务会持久化在系统中直到被显式完成或删除。一个常见的坑是脚本多次运行创建了大量已完成但未清理的旧任务。务必在脚本末尾或任务完成后进行清理。# 脚本示例下载并完成后清理 $job Start-BitsTransfer -Source $url -Destination $path -Asynchronous # ... 可以做其他事 ... # 等待特定任务完成 while (($job.JobState -eq Transferring) -or ($job.JobState -eq Connecting)) { Start-Sleep -Seconds 5 } Complete-BitsTransfer -BitsJob $job错误处理BITS任务错误不会像普通cmdlet那样直接抛出异常。需要检查任务的.JobState和.LastError属性。$job Start-BitsTransfer -Source $url -Destination $path -ErrorAction SilentlyContinue if ($job.JobState -eq Transferred) { Complete-BitsTransfer -BitsJob $job Write-Host 成功 } else { Write-Error 下载失败最后错误: $($job.LastError.Description) Remove-BitsTransfer -BitsJob $job }代理与认证Start-BitsTransfer支持-ProxyList和-ProxyUsage参数配置代理也支持-Credential参数进行认证但其认证方式可能对某些复杂场景如NTLM协商支持不如前两者灵活。4. 实操过程与核心环节实现现在我们通过几个综合性的实战场景将上述方法融会贯通展示如何根据具体需求选择和组合使用这些工具。4.1 场景一编写健壮的自动化部署脚本下载组件假设你正在编写一个自动化部署脚本需要从内部仓库下载一个.NET Core运行时安装包。要求有进度提示供管理员查看需要重试机制且网络环境一般。分析与选型需要进度提示排除默认无进度的WebClient。需要一定的健壮性但文件大小可能适中几百MBInvoke-WebRequest的内存开销可接受。我们选择Invoke-WebRequest并为其添加重试逻辑。实现代码function Download-FileWithRetry { param( [string]$Url, [string]$OutputPath, [int]$MaxRetries 3, [int]$RetryDelaySeconds 5 ) $retryCount 0 $success $false while (-not $success -and $retryCount -lt $MaxRetries) { try { Write-Host 尝试下载 $Url (第 $($retryCount 1) 次)... -ForegroundColor Cyan # 使用 -UseBasicParsing 避免不必要的HTML解析但保留进度条在PowerShell 5.1中 # 在PowerShell Core中进度条默认显示无需 -UseBasicParsing $progressPreference Continue # 确保进度条显示 Invoke-WebRequest -Uri $Url -OutFile $OutputPath -ErrorAction Stop $progressPreference SilentlyContinue # 恢复静默避免后续命令输出进度 Write-Host 文件已成功下载至: $OutputPath -ForegroundColor Green $success $true break } catch { $retryCount Write-Warning 下载失败: $($_.Exception.Message) if ($retryCount -lt $MaxRetries) { Write-Host 等待 $RetryDelaySeconds 秒后重试... -ForegroundColor Yellow Start-Sleep -Seconds $RetryDelaySeconds # 可选指数退避增加延迟 # $RetryDelaySeconds $RetryDelaySeconds * 2 } else { Write-Error 经过 $MaxRetries 次重试后仍无法下载文件。 throw $_ } } } } # 使用函数 Download-FileWithRetry -Url https://internal-repo.com/dotnet-runtime.exe -OutputPath C:\Installer\dotnet.exe核心环节解析错误处理与重试通过try-catch捕获Invoke-WebRequest可能抛出的异常如网络超时、404错误。通过while循环实现最多3次重试。进度显示控制通过临时修改$progressPreference变量为Continue确保进度条能显示出来。这是一个常用技巧因为有些宿主环境如某些CI/CD平台会默认静默进度。用户体验通过不同颜色的输出清晰告知用户当前状态尝试中、成功、失败、等待重试。4.2 场景二静默、可靠地下载大型ISO镜像文件你需要在一个夜间维护窗口中通过脚本从微软服务器下载一个超过4GB的Windows Server ISO文件。要求必须支持断点续传脚本退出后下载不能中断且不能占用过多前台资源。分析与选型大文件、要求断点续传和后台持久化这是BitsTransfer的典型应用场景。实现代码# 导入模块 Import-Module BitsTransfer $sourceUrl https://software-download.microsoft.com/pr/WinServer2022.iso $destinationPath E:\ServerISOs\WinServer2022.iso $jobName Nightly_ServerISO_Download # 检查是否已有同名或同目标的任务存在避免重复创建 $existingJob Get-BitsTransfer | Where-Object { $_.DisplayName -eq $jobName -or $_.FileList.LocalName -contains $destinationPath } if ($existingJob) { Write-Host 发现已存在的BITS任务: $($existingJob.DisplayName)状态: $($existingJob.JobState) -ForegroundColor Yellow # 可以选择恢复它 # Resume-BitsTransfer -BitsJob $existingJob $downloadJob $existingJob } else { Write-Host 开始创建新的后台下载任务... -ForegroundColor Cyan # 启动后台下载任务 # -TransferType 设为 Download -Priority 设为 Low 避免影响其他网络活动 # -Asynchronous 返回作业对象以便后续跟踪 $downloadJob Start-BitsTransfer -Source $sourceUrl -Destination $destinationPath -DisplayName $jobName -Priority Low -TransferType Download -Asynchronous } Write-Host 后台下载任务已启动。作业ID: $($downloadJob.JobId), 显示名: $($downloadJob.DisplayName) Write-Host 你可以关闭此PowerShell窗口下载将在后台继续。 Write-Host 要检查进度稍后可以运行: Get-BitsTransfer | Where-Object {$_.JobId -eq $($downloadJob.JobId)} | Format-List * # 如果脚本需要等待下载完成例如后续有校验步骤可以循环检查状态 # while ($downloadJob.JobState -in (Connecting, Transferring, Queued)) { # $percent if ($downloadJob.BytesTransferred -gt 0) { # [math]::Round(($downloadJob.BytesTransferred / $downloadJob.BytesTotal) * 100, 2) # } else { 0 } # Write-Progress -Activity 后台下载中 -Status $percent% 完成 -PercentComplete $percent # Start-Sleep -Seconds 10 # } # # if ($downloadJob.JobState -eq Transferred) { # Complete-BitsTransfer -BitsJob $downloadJob # Write-Host 下载已完成并确认。 -ForegroundColor Green # } else { # Write-Error 下载任务处于错误状态: $($downloadJob.JobState) # }核心环节解析任务去重脚本首先检查是否存在同目标或同名的BITS任务避免在脚本意外重新运行时创建重复任务这体现了生产环境脚本的健壮性。后台与异步使用-Asynchronous参数让Start-BitsTransfer立即返回作业对象而实际传输交给BITS服务。这意味着主脚本可以继续执行或直接退出。状态监控与完成注释掉的循环监控部分展示了如何主动等待任务完成。关键在于只有任务状态变为Transferred后使用Complete-BitsTransfer才会将临时文件正式移动到目标路径。如果任务处于Suspended或Error状态则需要相应处理。4.3 场景三快速批量下载一组已知URL的配置文件你需要从一个文件服务器批量下载一批日志配置文件URL列表已知且数量众多上百个。要求速度尽可能快实现简单。分析与选型批量、小文件、无需复杂HTTP交互。WebClient的简洁和轻量在这里有优势。我们可以利用.DownloadFileAsync实现简单的并行下载以提升速度。实现代码# 假设有一个包含URL列表的文本文件 urls.txt每行一个URL $urlList Get-Content -Path .\urls.txt $baseOutputDir C:\Configs\ # 确保输出目录存在 if (-not (Test-Path $baseOutputDir)) { New-Item -ItemType Directory -Path $baseOutputDir -Force | Out-Null } $downloadJobs () $webClients () foreach ($url in $urlList) { if ([string]::IsNullOrWhiteSpace($url)) { continue } # 从URL中提取文件名 try { $uri [Uri]$url $fileName [System.IO.Path]::GetFileName($uri.LocalPath) if ([string]::IsNullOrEmpty($fileName)) { $fileName downloaded_file_$(Get-Random).dat } $outputPath Join-Path $baseOutputDir $fileName } catch { Write-Warning 无效的URL格式: $url跳过。 continue } # 为每个下载创建一个WebClient对象 $webClient New-Object System.Net.WebClient $webClients $webClient # 保存引用以便后续清理 # 创建唯一的事件动作标识符 $eventIdentifier DownloadComplete_$(Get-Random) # 注册完成事件 $job Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -SourceIdentifier $eventIdentifier -Action { param($sender, $e) $global:completedCount Write-Host 后台下载完成一个文件。总计完成: $global:completedCount / $($global:totalCount) -ForegroundColor DarkGray } -Forward $downloadJobs { Client $webClient EventId $eventIdentifier Path $outputPath } # 开始异步下载 Write-Host 启动下载: $fileName $webClient.DownloadFileAsync($uri, $outputPath) } # 初始化计数器 $global:totalCount $downloadJobs.Count $global:completedCount 0 Write-Host 已启动 $totalCount 个异步下载任务。 -ForegroundColor Cyan # 等待所有异步任务完成简单轮询 $allDone $false while (-not $allDone) { $allDone ($global:completedCount -ge $global:totalCount) if (-not $allDone) { Start-Sleep -Milliseconds 500 } } Write-Host 所有文件下载完成 -ForegroundColor Green # 清理取消事件注册并释放WebClient资源 foreach ($job in $downloadJobs) { Unregister-Event -SourceIdentifier $job.EventId -ErrorAction SilentlyContinue $job.Client.Dispose() } Write-Host 资源已清理。 -ForegroundColor Cyan核心环节解析并行化提升效率通过循环为每个URL创建独立的WebClient实例并调用.DownloadFileAsync实现了多个文件同时下载充分利用了网络带宽。事件驱动通知使用Register-ObjectEvent为每个WebClient的DownloadFileCompleted事件注册处理动作。当单个文件下载完成时全局计数器递增并输出日志。资源管理异步操作创建了大量对象和事件订阅。脚本最后通过循环进行统一的清理工作Unregister-Event和.Dispose()这是防止内存泄漏和资源残留的关键步骤。文件名处理从URL中智能提取文件名并处理可能提取失败的情况增加了脚本的容错性。5. 常见问题与排查技巧实录在实际使用中你肯定会遇到各种报错和意外情况。下面是我在多年实践中总结的一些典型问题及其解决方法。5.1 证书验证失败错误问题现象使用Invoke-WebRequest或WebClient访问HTTPS站点时出现类似“基础连接已经关闭: 发送时发生错误。”或“请求被中止: 未能创建 SSL/TLS 安全通道。”的错误。原因分析最常见的原因是系统不信任目标服务器的SSL证书例如自签名证书、证书过期、根证书不在受信任存储中。另外在旧版PowerShell如5.1上访问要求TLS 1.2的现代网站时也可能因默认协议版本过低而出错。解决方案临时忽略证书错误仅限测试环境# 方法1为当前会话添加回调对所有请求生效 add-type using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } [System.Net.ServicePointManager]::CertificatePolicy New-Object TrustAllCertsPolicy # 注意此方法在 .NET Core 版本的 PowerShell 中可能无效。 # 方法2使用 -SkipCertificateCheck 参数 (PowerShell 7.0 及以上) # Invoke-WebRequest -Uri $url -SkipCertificateCheck -OutFile ... # 这是最推荐的在PS Core中的临时方案。启用强加密协议解决TLS版本问题# 在脚本开头执行强制使用 TLS 1.2。这对访问GitHub、Azure DevOps等现代网站至关重要。 [Net.ServicePointManager]::SecurityProtocol [Net.SecurityProtocolType]::Tls12 # 也可以启用多个协议以增加兼容性 # [Net.ServicePointManager]::SecurityProtocol [Net.SecurityProtocolType]::Tls12, [Net.SecurityProtocolType]::Tls11, [Net.SecurityProtocolType]::Tls永久解决方案生产环境将目标站点的根证书或自签名证书导入到运行脚本的计算机的“受信任的根证书颁发机构”存储中。这需要通过MMC控制台或certutil命令完成不属于脚本范畴。5.2 下载速度慢或进度卡住问题现象下载进度条长时间不动或者下载速度远低于网络带宽。排查思路检查源服务器和网络链路使用其他工具如浏览器、curl测试同一URL的速度排除源站限速或网络本身的问题。检查代理设置企业网络可能要求代理。PowerShell命令默认使用系统代理设置。你可以为命令指定代理# Invoke-WebRequest 使用代理 $proxyAddress http://proxy.company.com:8080 $proxy New-Object System.Net.WebProxy($proxyAddress, $true) # true 表示绕过本地地址 $webSession New-Object Microsoft.PowerShell.Commands.WebRequestSession $webSession.Proxy $proxy Invoke-WebRequest -Uri $url -WebSession $webSession -OutFile ... # WebClient 使用代理 $wc New-Object System.Net.WebClient $wc.Proxy New-Object System.Net.WebProxy(http://proxy.company.com:8080, $true)尝试使用BitsTransfer如前所述BITS服务具有智能节流和恢复功能。在拥挤或不稳定的网络中它可能比直接HTTP下载更稳定。尝试用Start-BitsTransfer对比一下速度。检查防病毒软件或安全策略某些安全软件会实时扫描下载的文件这可能严重拖慢下载速度尤其是大量小文件时。尝试临时禁用实时扫描进行测试。5.3 中文路径/文件名乱码问题问题现象下载的文件名中包含中文保存后变成乱码或者从某些网站下载的文本文件内容中文显示为乱码。原因分析这通常是由于字符编码不一致造成的。HTTP响应头中的Content-Disposition可能使用了非UTF-8编码如GBK而PowerShell或系统默认使用UTF-8或ANSI去解析导致错误。解决方案对于文件名乱码Invoke-WebRequestInvoke-WebRequest会尝试从响应头解析文件名。如果解析错误可以手动指定输出文件名。# 忽略服务器建议的文件名自己指定 iwr -Uri $url -OutFile C:\下载\正确文件名.pdf更复杂的情况需要手动解析响应头。可以先用-Headers参数查看原始头信息或者用-SkipHttpErrorCheck和-StatusCodeVariable获取原始响应对象来分析。对于文件内容乱码WebClient.DownloadString明确设置WebClient的编码。$wc New-Object System.Net.WebClient # 假设网站使用GB2312编码 $wc.Encoding [System.Text.Encoding]::GetEncoding(GB2312) $content $wc.DownloadString($url) # 然后可以用正确的编码保存 [System.IO.File]::WriteAllText(output.txt, $content, [System.Text.Encoding]::UTF8)5.4 BitsTransfer 任务状态异常与管理问题现象Get-BitsTransfer看到任务一直处于“Queued”、“Suspended”或“Error”状态无法完成。排查步骤查看详细错误信息$problemJob Get-BitsTransfer | Where-Object {$_.JobState -eq Error} $problemJob | Format-List * # 重点关注 LastErrorTime, LastErrorCode, LastErrorDescription 属性。常见错误及处理BG_E_ERROR_INFORMATION_UNAVAILABLE (0x80200045)通常表示网络问题。检查网络连接尝试Resume-BitsTransfer。BG_E_HTTP_ERROR_XXXHTTP错误如404、403。检查URL是否有效是否有访问权限。需要修复源URL或凭据。任务被策略挂起检查BITS作业的TransferPolicy。如果网络被标记为“计费网络”低优先级的任务可能被自动挂起。可以尝试用-TransferPolicy Unrestricted重新创建任务或在系统设置中调整网络类型。清理卡住的任务对于无法恢复的错误任务直接删除。Get-BitsTransfer | Where-Object {$_.JobState -in (Error, Suspended)} | Remove-BitsTransfer重启BITS服务作为终极手段可以尝试重启后台智能传输服务。Restart-Service -Name BITS -Force # 注意这会暂停所有正在进行的BITS传输重启后它们会自动恢复。5.5 在PowerShell Core (v7) 中的差异点PowerShell Core跨平台版本与传统的Windows PowerShell在下载命令上有一些重要区别混合使用时需特别注意。Invoke-WebRequest别名变化在PSCore中curl和wget是Invoke-WebRequest的别名但它们实际上是调用底层的原生curl或wget命令如果系统存在而不是PowerShell的cmdlet。这可能导致参数不兼容。建议在脚本中始终使用完整的Invoke-WebRequest或别名iwr。-UseBasicParsing参数已废弃在PSCore中Invoke-WebRequest不再内置IE引擎来解析HTML因此-UseBasicParsing参数被废弃且无效。所有请求都使用“基础解析”模式速度更快。-SkipCertificateCheck参数这是PSCore中新增的非常有用的参数用于在测试时忽略SSL证书错误比修改[System.Net.ServicePointManager]::ServerCertificateValidationCallback更安全、更简单。WebClient的可用性System.Net.WebClient在.NET Core/.NET 5中已被标记为过时虽然目前仍可用但微软推荐使用更现代的System.Net.Http.HttpClient。在PSCore中WebClient仍然工作但长远看对于新脚本可以考虑学习HttpClient。BitsTransfer模块不可用BitsTransfer是Windows特有的技术因此在非Windows平台的PowerShell Core上不可用。编写跨平台脚本时应避免依赖它。我个人在实际操作中的体会是没有一种方法是万能的。对于临时的、交互式的小文件下载iwr的便捷性无与伦比。对于集成在脚本中的稳定下载逻辑WebClient的简洁API让我感到可靠。而当面对GB级别的系统镜像或需要在糟糕网络环境下保证交付时BitsTransfer是我唯一的选择。理解它们的差异就像木匠选择不同的凿子根据木料的纹理和要雕刻的细节选用最趁手的那一把才能事半功倍。最后分享一个小技巧在编写需要下载功能的通用脚本时可以在开头做一个简单的功能探测例如尝试Get-Command Start-BitsTransfer -ErrorAction SilentlyContinue如果存在则优先使用BITS否则降级到Invoke-WebRequest这样能让你的脚本在更多环境中优雅运行。