有時候,PowerShell 在還沒準備好使用之前就會出現問題。 啟動問題很難排查,尤其是當你想用 PowerShell 來協助時。 創業主要分為三個階段:
- 程序創建
- PowerShell SessionState 初始化
- 剖面處理
最常見的問題包括:
- 啟動時間長或效能緩慢
- Errors
- 崩潰
啟動序列的步驟
了解 PowerShell 啟動時的步驟很有幫助。 這樣你就能縮小問題發生的範圍。
步驟一:流程建立
流程建立包含幾個步驟:
建立主機視窗
在 Windows 上,主機可以是 Windows 終端機、Windows 控制台主機、Visual Studio Code 或其他任何主機應用程式。 這裡發生的問題通常與 PowerShell 無關,但也極為罕見。
啟動程序主機程序
這裡發生的問題通常是因為執行檔損壞或作業系統本身的問題。
準備 .NET
PowerShell 是基於 .NET 的,需要完全載入。 根據你想開始的 PowerShell 版本,你會選擇完整的 Windows 整合 .NET 框架搭配 Windows PowerShell 5.1,或是 PowerShell 7 內建的新版 .NET。
在首次啟動 PowerShell 時,PowerShell 和 .NET 會執行優化任務。 此優化任務僅執行一次,分別是在安裝後的首次啟動、升級,或快取為空時。 在首次優化期間,啟動時間會更長。 優化過程中失敗可能導致快取損壞。 損壞的 PowerShell 快取可能導致指令發現和模組載入時出現問題。
步驟 2:PowerShell SessionState 初始化
載入 PowerShell 二進位檔並初始化引擎時,需要處理 PowerShell 設定和一些快取資料。
- 程序設定檔:
powershell.config.json以及 JEA 及其他遠端處理場景使用的 PSSession 設定檔。 這些檔案可能包含可能影響語言模式的設定、可用的指令與模組,以及一些政策設定。 - 請檢查群組政策和 Windows 安全政策。 Windows 群組政策可以覆寫
powershell.config.json中的設定。 安全政策可以啟用像 WDAC(Windows Defender 應用程式控制)這類功能,這些功能也能限制可用的語言模式。 - 載入預設模組(Microsoft.PowerShell.Core 與 PSReadLine)以及 PSSession 設定中定義的任何模組與組件。
欲了解更多 PowerShell 安全功能,請參閱以下文章:
步驟 3:剖面處理
最後,PowerShell 會執行可用的設定檔檔案。 個人設定檔腳本的執行順序如下:
- 所有主機 所有使用者
- 目前主機 所有使用者
- 所有主機目前使用者
- 目前主機 當前使用者
備註
遠端工作時不會執行設定檔腳本。
如需有關設定檔的更多資訊,請參閱 about_Profiles。
縮小問題範圍
移除變數並縮小問題發生範圍的範圍很有幫助。 最容易消除的變數是設定檔。 該設定檔通常包含自訂程式碼,尤其是在使用者專屬的設定檔腳本中。
試著在關閉設定檔的情況下執行 PowerShell:
# PS 5.1:
powershell -NoProfile
# PS 7.*:
pwsh -NoProfile
接著你應該看看問題是否與版本有關。 試著在 Windows PowerShell 5.1 和 PowerShell 7 中同時執行你的設定檔。 Windows PowerShell 和 PowerShell 7 會將設定檔存放在不同位置。 你的個人資料可能兩個版本不一樣。 比較這些檔案以了解差異。 你可以試著在 Windows PowerShell 5.1 安裝你的 PowerShell 設定檔。 不過要注意,有些 PowerShell 7 的指令和模組與 Windows PowerShell 5.1 不相容。
你可以在 Windows PowerShell 5.1 中測試你的 PowerShell 7 設定檔,而不必覆蓋現有設定檔。
在未啟用設定檔的情況下啟動 Windows PowerShell 5.1。
手動將 PowerShell 7 的個人設定檔檔案點載到 Windows PowerShell 5.1 會話中。
. $env:USERPROFILE\Documents\PowerShell\Microsoft.PowerShell_profile.ps1請觀察該情況是否發生。
如果問題持續存在,那你就知道問題是剖面外的環境問題。
試著在另一台裝置上執行該設定檔。 如果設定檔在其他裝置上正常運作,那你就知道問題是你原本的裝置特有的。
排除常見的環境問題
啟動時當機
如果 PowerShell 主控台在啟動時當機,尤其是早期且沒有回饋,可能是程序快取損壞。 這是少數能透過清除快取來解決的狀況。 有兩個快取位置可以被清除:
- 使用者快取:
$env:LOCALAPPDATA\Microsoft\Windows\Caches - 系統快取:
$env:windir\System32\Config\SystemProfile\AppData\Local\Microsoft\Windows\Caches
先刪除使用者快取資料夾的內容,然後再嘗試重新啟動 PowerShell。 如果問題持續,請刪除系統快取內容,再嘗試一次。
你可能還需要刪除 PowerShell 分析快取。 您可以在以下地點找到快取檔案:
- Windows PowerShell:
$env:windir\System32\Config\SystemProfile\AppData\Local\Microsoft\Windows\PowerShell - PowerShell 7:
$env:LOCALAPPDATA\Microsoft\PowerShell
僅刪除以下檔案模式:
ModuleAnalysisCache-*StartupProfileData-*
下次啟動 PowerShell 時,快取的資料會被重新建立。
如果問題在 Windows PowerShell 5.1 中持續存在,您可能需要修復 .NET Framework 安裝。 欲了解更多資訊,請參閱 修復 .NET 框架。
排除常見的設定檔問題
本節說明 PowerShell 啟動時常見的問題,以及如何排解這些問題。
設定檔執行時間太長
首先你必須定義 什麼是「太長」。 PowerShell 只是照著腳本指示去做。 檢查所有設定檔路徑。 可能會有多個設定檔腳本被同時執行。 請先檢視程式碼,了解它想做什麼。
判斷延遲發生的位置
如果有適用於 AllUsers 範圍的設定檔程式碼,你可能無法編輯那些檔案。 請與你的系統管理員合作,檢視那些檔案。 對於 CurrentUser 範圍的設定檔腳本,請編輯這些檔案,加入時序訊息,幫助你找出延遲發生的位置。 例如,你可以在個人檔案腳本的不同位置加上以下這行。
Write-Host "$(Get-Date -Format 'HH:mm:ss.fff') | Profile: Step X"減少相依性
減少執行設定檔時需要載入的模組數量。 在設定檔執行後運行
Get-Module,以查看啟動時載入的模組。 預設情況下,PowerShell 會載入 Microsoft.PowerShell.Core 和 PSReadLine 模組。 其他模組則由你的設定檔腳本載入。模組可以透過使用
Import-Module這些模組中定義的指令來明確載入,或透過隱含的方式載入。 考慮啟動時是否需要載入指令或模組。避免在已導向的資料夾中安裝模組
在 Windows 上,很多情況下你的
Documents資料夾可以被導向到網路檔案分享或 OneDrive。 網路檔案存取可能很慢,尤其是在網路擁擠或伺服器負載過重時。 根據 OneDrive 的設定方式,它也可能在設定檔執行時造成延遲或錯誤。你有幾個方法可以減輕這個問題:
- 不要重定向你的
Documents資料夾,但這可能不是你想要的 - 在 OneDrive 裡設定你的
Modules資料夾,讓 它永遠 保存在磁碟裡。 這樣可以避免錯誤和載入延遲。 - 在 AllUsers 範圍安裝模組,該範圍不在使用者設定資料夾中。
- 不要重定向你的
測量實際表現
如果你不知道你的個人檔案運行需要多久,就無法判斷是否太長。 指令
Measure-Command本可以顯示指令或腳本區塊執行所需的時間。PowerShell 開發經理 Steve Lee 有一篇部落格文章,說明如何衡量你的個人檔案效能。 內容包括建立效能基準、如何取得詳細時序資訊,以及優化個人資料的方法。 請參見 優化您的$Profile。
PowerShell 7 在一個孤立的網路中啟動得很慢
在這種情況下,你的 Windows 電腦連接到一個沒有連上網際網路的網路。 對於互動式 PowerShell 會話,PowerShell 會自動載入 PSReadLine 模組。 PSReadLine 是一個有簽名模組。 PowerShell 必須驗證模組的數位簽章。 這種驗證在斷線環境中可能會造成延遲。 為了測試這個理論,請以 非互動 模式啟動 PowerShell 7:
pwsh.exe -noninteractive
如果 PowerShell 在非互動模式下快速啟動,問題很可能是由憑證撤銷清單(CRL)檢查所引起。 作為驗證數位簽章過程的一部分,.NET 執行時會檢查 CRL,以確保簽署憑證仍然有效。 在斷開的環境中,你的電腦無法透過網路存取 CRL。 CRL 檢查的預設逾時時間為 15 秒。 這表示每次 PowerShell 載入已簽署的模組時,超時可能需要長達 15 秒。
針對此問題有三種可能的解決方法:
防火牆或代理豁免
允許直接網路存取以進行 CRL 檢查,可以避免此問題。 在可以控制網路存取的環境中,你可以設定防火牆或代理伺服器,允許存取 CRL URL。 這是最簡單且影響最小的解決方案。 防火牆日誌應該會顯示 PowerShell 嘗試存取的網址。
減少 CRL 逾時
減少 CRL 查詢逾時是可能的,但這樣做有可能導致其他查詢失敗,無法在指定時間內完成。 關於如何更改逾時的細節,請參閱 「管理網路檢索與路徑驗證」。
移除 CRL 檢查
CRL 檢查設定由群組政策管理。 欲了解更多資訊,請參閱 管理受信任出版商。
警告
雖然可以關閉 CRL 檢查,但不建議這麼做。 關閉 CRL 檢查可以防止你實際撤銷被入侵的憑證。
錯誤:無法點源此指令,因為它是以不同的語言模式定義的
PowerShell 可與應用程式控制系統(如 AppLocker 和 Windows Defender Application Control,WDAC)搭配,並自動以 ConstrainedLanguage 模式執行。 限制語言模式會限制一些可能有危險的功能。 不過,有時候你需要 FullLanguage 模式來使用某些指令或功能。 腳本在被政策信任時,可以在 全語言 模式下執行。 信任可透過檔案簽署或其他在 AppLocker 或 WDAC 中設定的政策機制來表示。
當你啟動由應用程式控制管理的 PowerShell 會話時,會出現以下錯誤:
Cannot dot-source this command because it was defined in a different language mode. To invoke this
command without importing its contents, omit the '.' operator.
在應用程式控制下,PowerShell 以 ConstrainedLanguage 模式運行。 此錯誤發生在當你的設定檔腳本被 豁免 或 已簽署 以 全語言 模式運行時。 當 PowerShell 以 ConstrainedLanguage 模式執行時,它無法用 dot-source 程式碼被信任來以 FullLanguage 模式執行。
要解決這個問題,你必須從設定檔腳本中移除豁免或簽名。 如果你需要在配置檔中必須以 FullLanguage 模式執行的程式碼,請將其移動到另一個已豁免或已簽署的腳本檔。 從你的個人環境中執行(不要使用點源方式執行)該腳本檔案。
欲了解更多相關資訊,請參閱 PowerShell 受限語言模式及 Dot-Source 運算子。