﻿# 如何修正 PowerShell 執行龜速的元兇 (關閉進度列提示)

PowerShell 有個對開發人員非常不友善的預設值，就是 `$ProgressPreference` 這個偏好設定變數 (Preference Variables)，他的預設值為 `Continue`，也就是 Cmdlet 執行時預設會顯示 Cmdlet 的執行進度 (如果有進度列提示的話)，這個進度列提示雖然很貼心地顯示在命令提示字元上，但卻會導致 Cmdlet 執行速度徹底被拖慢，慢到非常誇張，浪費了我們寶貴的生命。這篇文章就要告訴大家如何設定與調整，以便在日後可以更有效率的執行 PowerShell 命令！

PowerShell 有個很常用的內建 Cmdlet 叫做 `Invoke-WebRequest`，他可以幫我們發出一個 HTTP 要求，從網路上下載一個檔案。我們在 Dockerfile 中經常會使用這個命令來動態下載檔案，還有很多情況都會用到。

> `Invoke-WebRequest` 有個很簡便的別名 `wget`，可以大幅縮短這個 Cmdlet 命令。

這邊我們就快速做一個示範，下載 http://speed.so-net.net.tw/10mb.zip 這個 10MB 的檔案，命令如下：

```ps
Invoke-WebRequest http://speed.so-net.net.tw/10mb.zip
```

下載的過程中，你會看到如下圖的進度條提示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/e9c1c9ff3808cd2a580d-image_3174.png)

為了能夠比較不同設定造成的效能影響，我們先顯示 `$ProgressPreference` 環境變數的值，再透過 [Measure-Command](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/measure-command) 來統計下載過程的執行時間：

```ps
$ProgressPreference
Measure-Command -Expression { Invoke-WebRequest http://speed.so-net.net.tw/10mb.zip }
```

這個下載的過程，總共耗時 `13.1251666` 秒！

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/5fd072d07775107599fa-image_3175.png)

接著，我們將 `$ProgressPreference` 調整為 `SilentlyContinue`，然後重新再執行一次，這次執行就不會再顯示進度列提示，而且執行速度也不會再被命令提示字元的顯示速度給拖累！

```ps
$ProgressPreference = 'SilentlyContinue'
Measure-Command -Expression { Invoke-WebRequest http://speed.so-net.net.tw/10mb.zip }
```

這次下載總共耗時僅 `2.9292511` 秒，速度整體提升 `4.48` 倍之多，而且我才下載 **10MB** 而已，如果今天要下載 **100MB** 或更大的檔案，那速度會差異更大！

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/a319c33228c0cd755867-image_3176.png)

如果你想改回顯示進度列提示的設定，執行以下指令即可改回預設值：

```ps
$ProgressPreference = 'Continue'
```

關於 `$ProgressPreference` 的完整說明，各位可以[參考這裡](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables#progresspreference)。

### 調整 `$progressPreference` 的預設值

要調整每一個 PowerShell 工作階段的預設值，你要先找到一個 `%USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` 檔案，如果檔案不存在，就自己建立一個。

接著再將以下這行複製進去即可：

```ps
$ProgressPreference = 'SilentlyContinue'
```

### 調整 `powershell` 命令的預設值

很多時候我們會需要從 cmd 命令提示字元來執行 powershell 命令，這時你也可以這樣輸入：

```ps
powershell -Command "$ProgressPreference = 'SilentlyContinue'; Test-NetConnection"
```

> 上述 [Test-NetConnection](https://learn.microsoft.com/en-us/powershell/module/nettcpip/test-netconnection) 也是另一個 PowerShell 內建 Cmdlet 命令，主要用來測試目前的網路連接狀況。

### 調整 `Dockerfile` 執行 PowerShell 的預設值

在設計 Windows Container 的 Dockerfile 時，如果要設定 PowerShell 執行，可以考慮使用 [`SHELL`](https://docs.docker.com/engine/reference/builder/#shell) 搭配 [`RUN`](https://docs.docker.com/engine/reference/builder/#run) 命令，即可設定 `docker build` 的過程如何使用 PowerShell 當作預設的 Shell 殼層。

以下是從[這個 vcbuildtools 範例](https://github.com/MicrosoftDocs/Virtualization-Documentation/blob/898cf22aef90fe920ac12c787d70595540374d9f/windows-container-samples/vcbuildtools/Dockerfile)擷取出來的片段，相當的實用：

```dockerfile
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
```

### 相關連結

-   [about\_Preference\_Variables | Microsoft Docs](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables)
-   [Dockerfile reference | Docker Documentation](https://docs.docker.com/engine/reference/builder/)
-   [Measure the run-time of a PowerShell command with Measure-Command – 4sysops](https://4sysops.com/archives/measure-the-run-time-of-a-powershell-command-with-measure-command/)
-   [So-net 連線速度測試](http://searchzone.so-net.net.tw/speedtest/speed02.do)
-   [powershell - Hide progress of Invoke-WebRequest - Stack Overflow](https://stackoverflow.com/questions/18770723/hide-progress-of-invoke-webrequest)
-   [Hide PowerShell Progress Bars > Think PowerShell](https://thinkpowershell.com/hide-powershell-progress-bars/)
