Долго запускается консоль PowerShell или PS1 скрипты

На разных компьютерах периодически встречаю проблему очень долгого запуска консоли PowerShell, вплоть до нескольких минут. Это влияет как на запуск самой командной оболочки powershell.exe/pwsh.exe, так и на время выполнения PowerShell скриптов, которые стартуют через GPO или по расписанию через планировщик задач Windows. В этой статье мы рассмотрим, как обнаружить возможные причины медленного запуска консоли PowerShell и уменьшить время загрузки оболочки.

Типовые причины, из-за которых PowerShell может долго загружаться

  • Наличие пользовательских функций в файлах профилей PowerShell, которые загружается при каждом запуске процесса powershell.exe
  • Большое количество установленных модулей, которые загружаются автоматически
  • Большой файл с историей команд PowerShell, который загружается модулем PSReadLine
  • Медленная работа (конфликты/повреждения) компонентов .NET Framework, которая вызывает существенное замедление загрузку PowerShell и модулей

Для измерения времени запуска процесса PowerShell можно использовать командлет Measure-Command. Время загрузки оболочки в обычном режиме можно проверить командой:

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

измерить время запуска PowerShell процесса

Команда выведет время, которое потребовалось на загрузку процесса powershell и выполнения простой команды.

PowerShell при запуске может писать время, затраченное на загрузку.

Loading personal and system profiles took XXXXX ms

powershell: Loading personal and system profiles took

В этом примере видно, что процессу PowerShell потребовалось 12 секунд на загрузку. Что довольно много. Такое сообщение автоматически выводится, если время загрузки профилей PowerShell превысило 500 мс.

Это указывает на то, что в файлах профилей PowerShell загружается какой-то медленный код, который каждый раз отрабатывает при старте процесса.

Проверьте, насколько быстрее PowerShell загрузится без профилей. Для этого запустите процесс оболочки с параметром -noprofile:

powershell.exe -noprofile

или для запуска нового PowerShell Core:

pwsh.exe -noProfile

powershell.exe -noprofile - запуск без профиля

В данном случае видно, что без профилей PowerShell стартовал гораздо быстрее. Профили PowerShell это PS1 файлы, которые используются для настройки окружения пользователи, выполнения определенных команд и загрузки кастомных функций/модулей (подробнее про файлы профилей PowerShell).

По умолчанию в Windows файлы профилей PowerShell не используются (файлы не созданы). Список всех файлов профилей, которые будут загружаться при запуске процесса powershell.exe можно вывести так:

$profile | select *

список используемых профилей PowerShell

Проверьте содержимое всех файлов профилей для пользователя вручную, или выведите его с помощью команд:

Get-Content $PROFILE.AllUsersAllHosts
Get-Content $PROFILE.AllUsersCurrentHost
Get-Content $PROFILE.CurrentUserAllHosts
Get-Content $PROFILE.CurrentUserCurrentHost

В моем случае в пользовательском файле Microsoft.PowerShell_profile.ps1 выполнялись некоторые команды. Проверьте, все ли команды/функции в файле профиля вам нужны, удалите неиспользуемые, оптимизируйте код если возможно.

очистка запускаемого кода в профиле powershell

Другой возможной причиной медленного запуска оболочки PowerShell может быть большое количество установленных модулей. PowerShell автоматически загружает модули, скопированные в следующие папки:

C:\Users\%username%\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules

Их список можно вывести так:

$Env:PSModulePath -split ';'

список автоматически загружаемых модулей

Вывести список загруженных в сессию модулей можно командой:

Get-Module -ListAvailable

Вывести список установленных сторонних модулей:

Get-InstalledModule

Get-InstalledModule

Проверьте, все ли модули из списка вам нужны. Удалите неиспользуемые модули:

Remove-Module -Name BurntToast
Uninstall-Module -Name BurntToast -AllVersions -Force

Модули PowerShell установленные вручную, придется удалять самостоятельно.

Для анализа времени загрузки каждого модуля можно использовать команду:

Measure-Command { Import-Module ModuleName -Force }

Либо массово проверяем время запуска всех модуля:

$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
}
}

найти модули powershell, которые загружаются долго

Посмотрите, какие модули загружаются дольше всего.

Чтобы полностью запретить автоматическую загрузку модулей, нужно добавить в файл профиля строку:

$PSModuleAutoLoadingPreference = 'None'

В этом случае, чтобы загрузить нужный вам модуль вручную нужно будет выполнить команду:

Import-Module [module-name]

Добавьте в файл профиля загрузку следующих базовых модулей:

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

Также есть известная проблема с загрузкой PowerShell модуля для управления инфраструктурой VMware (VMware PowerCLI). Время загрузки модуля на компьютере, на котором отсутствует подключение к Интернету, может занять несколько минут. Проблема в том, что при загрузке модуль пытается проверить внешний список отозванных сертификатов (CRL, Certificate Revocation List). Из-за отсутствия доступа в Интернет этот процесс отваливается по таймауту. Решение – отключить проверку списка отозванных сертификатов. Можно отключить проверку CRL через реестр:

reg add HKLM\SYSTEM\CurrentControlSet\Services\SstpSvc\Parameters /v NoCertRevocationCheck /t REG_DWORD /d 0x00000001 /f

Или в свойства проводника: inetcpl.cpl -> Advanced –> Check for publisher (server) certificate revocation.

отключить проверку списка отозванных сертификатов (CRL)

Часто причиной медленного запуска PowerShell может быть установленный на компьютере антивирус. Можно проверить, какие внешние dll библиотеки и модули загружаются при старте процесса PowerShell.

  1. Откройте cmd.exe и выполните команду: powershell.exe -c "Write-Host $PID;Start-Sleep -s 30"
  2. Команда вернет PID запущенного процесса powershell.exe. Скопируйте его и вставьте в следующую команду в новой сессии PoSh:
    Get-Process | where {$_.Id -eq <YOUR_PID>} | select -ExpandProperty modules
  3. Вы получите список DLL, которые загружаются при запуске процесса powershell.exe. Проверьте, есть ли в списке библиотеки вашего антивируса. Если есть, попробуйте добавить процесс pwsh.exe и powershell.exe в исключения вашего антивируса. список хагружаемых библиотек в powershell

Например, в антивирус Windows Defender можно добавить исключения с помощью PowerShell:

Add-MpPreference -ExclusionProcess "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe","C:\Program Files\PowerShell\7\pwsh.exe"

Если вы подозреваете, что причиной медленного запуска powershell.exe являются медленная работа библиотек .NET Framework, можно скомпилировать все используемые сборки (assemblies) в нативный машинный код с помощью утилиты ngen.exe (Native Image Generator). Это существенно увеличит производительность приложений .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
}
}

ngen.exe - компиляция используемых dot NET сборок

Также для анализа времени запуска PowerShell можно использовать классическую утилиту Process Monitor (https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx). Запустите procmon64.exe , включите фильтр по процессу powershell.exe, запустите консоль и найдите операции, которые вызвали наибольшую задержку.

procmon64 - анализ времени загрузки powershell.exe

В моем примере чтение файла с историей PowerShell команд, который ведет модуль PSReadline заняло около 30 секунд ( C:\Users\sysops\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ ConsoleHost_history.txt ). Как оказалось проблема была вызвана большим размером файла ConsoleHost_history.txt (около 2 Гб). После его очистки, время запуска powershell заметно сократилось.


Предыдущая статья Следующая статья


Комментариев: 0 Оставить комментарий

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Я не робот( Обязательно отметьте)