微軟的 Windows PowerShell 提供了許多的 Cmdlet、以及額外的模組,讓他的功能比傳統的命令提示字元(cmd)來的強大不少。
像是透過「Invoke-Webrequest
」(官方文件),就可以直接透下載網路上的檔案,在很多情境下都是很實用的;他的基本使用方法大致上如下:
Invoke-Webrequest -Uri https://github.com/boostorg/boost/archive/refs/tags/boost-1.77.0.zip -OutFile c:tempboost.zip
但是如果有用這個指令來下載大型檔案的話,應該都會發現:他下載的速度真是有夠慢…
<!–more–>
像 Heresy 在這邊明明是在 1Gbps 的內網,但是下載一個不到 200MB 的檔案卻還要等好一陣子,下載速度也僅有不到 20Mbps(還沒有維持在高速…)
有的時候真的會下載到懷疑人生。
而後來才發現,這個問題原來是 PowerShell 為了顯示下載進度造成的。
在 WIndows PoerShell 使用「Invoke-Webrequest
」來下載檔案的時候,他都會浮現一個藍底的對話框,告訴使用者當下已經完成多少資料了。
這種功能在使用者體驗上其實是好的。因為當下載時間久的時候,有狀態在更新,可以有效告訴使用者這個操作還活著、沒有掛掉。
試想,如果執行一個指令後,過個 10 秒、甚至更久的時間,什麼都沒變化,會覺得發生了什麼事呢?
但是問題是,「Invoke-Webrequest
」這邊因為這個進度回報而拖延的時間實在太誇張了…
還好,PowerShell 也有提供參數,可以把這個進度關掉,讓下載速度大幅增加。
這邊要修改的,就是「$ProgressPreference
」這個變數(官方文件);他的選項有下面四種:
- Stop: 不顯示進度條、也不執行指令,會給一個錯誤訊息。
- Inquire: 會在每次更新進度的時候跳出確認選項,詢問要怎麼處理。
- Continue: 顯示進度條、並繼續執行。
- SilentlyContinue: 不顯示進度條、並繼續執行。
他的預設值是「Continue」,而如果不想要看到進度條的話,則是要把它修改成「SilentlyContinue」;修改的指令很簡單,就是:
$ProgressPreference = 'SilentlyContinue'
修改這個參數再去下載的話,基本上就可以發揮網路的全部能力,快速地完成下載了!
Heresy 這邊也用「Measure-Command」(官方文件)來測試過,如果從 HiNet 的測速網站(連結)下載一個 100MB 的檔案,在有顯示進度的情況下,會花掉 85 秒左右。
而如果把進度關閉的話,則只需要 3 秒…這個差異已經接近 30 倍了…
下面就是測試的指令:
Measure-Command -Expression { Invoke-Webrequest http://http.speed.hinet.net/test_100m.zip }
這邊也要提醒一下,這個參數會影響到的 cmdlet 不只是「Invoke-Webrequest
」;其他像是建立壓縮檔的「Compress-Archive」(官方文件)、或是解壓縮的「Expand-Archive」(官方文件)也同樣會受到影響。
而這類型的指令,在關閉進度條的顯示後,也都是會有相當程度的效能提升的!在 Heresy 這邊測試,壓縮檔案的速度在關閉進度條後快了 5 倍左右呢。
但是,如果把進度關掉的話,那執行指令後,就真的完全不知道當下到底進展到哪了。
另外,這個問題主要應該還是發生在 Windows 內建的 PowerShell 5.1 上。如果是在比較新版的 PowerShell Core 7(官方文件),儘管還是有類似形式的進度條,但是速度卻不會被大幅度拖慢,也不太需要這樣處理。
但是比較搞笑的是…好像還沒有什麼方法,可以把比較新的 PowerShell 7.x 設定成預設的 PowerShell、取代掉內建的 5.1 版。