修復:PowerShell 控制台和腳本啟動緩慢

Jacki

我注意到 PowerShell 控制台有時需要很長時間才能打開。此問題出現在不同的計算機上。在某些情況下,PowerShell 可能需要幾分鐘才能加載。這會影響命令 shell 本身(powershell.exe 或 pwsh.exe)的打開以及通過 GPO 或計劃任務中的腳本啟動的登錄 PowerShell 腳本的執行時間。這篇文章解釋瞭如何確定 PowerShell 啟動緩慢的潛在原因並減少加載時間。

以下是 PowerShell 加載時間較長的一些常見原因:

  • 每次 PowerShell.exe 進程啟動時都會加載 PowerShell 配置文件中的用戶定義函數
  • 自動安裝並加載大量 PS 模塊
  • PSReadLine 模塊加載一個包含 PowerShell 命令歷史記錄的巨大文件
  • PowerShell 和模塊加載的顯著減慢是由 .NET Framework 組件中的衝突或損壞引起的。

測量命令cmdlet 可用於測量 PowerShell 進程的加載時間。使用此命令檢查 PowerShell 在正常模式下的加載時間:

powershell -noprofile -ExecutionPolicy Bypass ( Measure-Command { powershell "Write-Host 1" } ).TotalSeconds

建議閱讀:使用任務計劃程序按計劃運行 PowerShell 腳本

該命令將顯示 PowerShell 進程加載和執行一個簡單命令所花費的時間。

當 PowerShell 啟動時,它可能會報告加載所需的時間。

Loading personal and system profiles took XXX ms

正如您在此示例中看到的,PowerShell 進程的加載時間為 12 秒。這是相當多的。如果 PowerShell 配置文件的加載時間過長,則會自動顯示此消息超過500毫秒

這表明 PowerShell 配置文件在每次進程啟動時都執行緩慢的代碼。

比較未加載配置文件時 PowerShell 進程的啟動速度。為此,請使用以下命令運行 shell 進程-無配置文件選項:

powershell.exe -noprofile

或運行 PowerShell Core:

pwsh.exe -noProfile

正如您所看到的,當配置文件未加載時,PowerShell 的啟動速度要快得多。 PowerShell 配置文件是用於配置用戶環境的 PS1 文件。它們還允許用戶運行特定命令並加載自定義功能或模塊。

默認情況下,不使用 PowerShell 配置文件(不創建配置文件)。以下命令顯示 PowerShell 進程啟動時將加載的所有配置文件的列表。

$profile | select *

手動檢查用戶所有配置文件的內容,或使用以下命令顯示它們:
Get-Content $PROFILE.AllUsersAllHosts
Get-Content $PROFILE.AllUsersCurrentHost
Get-Content $PROFILE.CurrentUserAllHosts
Get-Content $PROFILE.CurrentUserCurrentHost

就我而言,一些命令被添加到Microsoft.PowerShell_profile.ps1用戶文件。檢查配置文件以確保所有命令和功能都是必需的。如果可能,刪除不必要的命令並優化代碼。

安裝大量模塊可能是 PowerShell 啟動緩慢的另一個可能原因。 PowerShell 自動從以下文件夾加載模塊:

C:Users%username%DocumentsWindowsPowerShellModules
C:Program FilesWindowsPowerShellModules
C:Windowssystem32WindowsPowerShellv1.0Modules

他們的列表可以顯示如下:

$Env:PSModulePath -split ';'

列出已加載到會話中的 PS 模塊。

Get-Module -ListAvailable

列出已安裝的第三方模塊。

Get-InstalledModule

檢查列表以確定您是否需要所有模塊。卸載任何未使用的 PowerShell 模塊。 :
Remove-Module -Name BurntToast
Uninstall-Module -Name BurntToast -AllVersions -Force

手動安裝的 PowerShell 模塊必須手動卸載。

要分析每個模塊的加載時間,請使用以下命令:

Measure-Command { Import-Module ModuleName -Force }

或者批量檢查所有PS模塊的加載時間:
$modules = Get-InstalledModule| Select-Object -ExpandProperty Name -Unique
foreach ($mod in $modules) {
$time = Measure-Command { Import-Module $mod -Force }
[PSCustomObject]@{
Module = $mod
LoadTimeSec = $time.Totalseconds
}
}

查看哪些模塊加載時間最長。

要防止所有 PS 模塊自動加載,請將以下行添加到配置文件中:

$PSModuleAutoLoadingPreference="None"

在這種情況下,您可以使用以下命令手動加載所需的模塊:

Import-Module [ModuleName]

請務必將以下常用模塊添加到您的配置文件中:

Import-Module Microsoft.PowerShell.Utility
Import-Module Microsoft.PowerShell.Management

加載 VMware 基礎設施管理 PowerShell 模塊時還存在一個已知問題,也稱為VMware PowerCLI。在未連接到 Internet 的計算機上加載該模塊可能需要幾分鐘的時間。問題是,加載時,模塊會嘗試檢查已撤銷證書的外部列表(CRL、證書吊銷列表)。由於缺乏互聯網連接,此過程超時。解決辦法是在 Windows 中禁用 CRL 檢查。您可以通過註冊表禁用 CRL 檢查:

reg add HKLMSYSTEMCurrentControlSetServicesSstpSvcParameters /v NoCertRevocationCheck /t REG_DWORD /d 0x00000001 /f

或者在 Internet 屬性小程序中:inetcpl.cpl->先進的–> 取消勾選該選項檢查發布者(服務器)證書是否吊銷

PowerShell 可能需要很長時間才能啟動的原因通常是計算機上安裝的防病毒軟件。您可以檢查 PowerShell 進程啟動時加載了哪些外部 DLL 和模塊。

  1. 打開cmd.exe並運行命令:powershell.exe -c "Write-Host $PID;Start-Sleep -s 60"
  2. 此命令返回正在運行的 PowerShell.exe 進程的進程 ID (PID)。複製PID並將其粘貼到新 PowerShell 會話中的以下命令中:
    Get-Process | where {$_.Id -eq <YOUR_PID>} | select -ExpandProperty modules
  3. PowerShell 進程啟動時,您將收到加載的 DLL 列表。檢查您的防病毒庫是否已列出。如果是這樣,請嘗試將 pwsh.exe 和 powershell.exe 進程添加到防病毒例外中。

例如,您可以使用以下命令將排除項添加到內置 Windows Defender 防病毒軟件:

Add-MpPreference -ExclusionProcess "C:WindowsSystem32WindowsPowerShellv1.0powershell.exe","C:Program FilesPowerShell7pwsh.exe"

如果您懷疑 PowerShell 啟動緩慢是由 .NET Framework 庫操作緩慢引起的,您可以使用以下命令將所有使用的程序集編譯為本機機器代碼:ngen.exe工具(本機圖像生成器)。這將顯著提高 .NET 應用程序的性能,包括 PowerShell:

$env:PATH = [Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory()
[AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object {
$path = $_.Location
if ($path) {
$name = Split-Path $path -Leaf
Write-Host -ForegroundColor Yellow "`r`nRunning ngen.exe on '$name'"
ngen.exe install $path /nologo
}
}

經典之作過程監控器工具還可以用於分析PowerShell啟動時間。 (https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx)。跑步ProcMon64.exe,對 PowerShell.exe 進程啟用過濾器,打開 PS shell,並識別導致最大延遲的操作。

在我的示例中,讀取 PSReadline 模塊維護的 PowerShell 命令歷史記錄文件大約需要 30 秒。 (C:UsersusernameAppDataRoamingMicrosoftWindowsPowerShellPSReadLineConsoleHost_history.txt)。該問題是由ConsoleHost_history.txt文件大小超過 2 GB。清理歷史文件可以顯著減少 PowerShell 的啟動時間。