Исключение «Неверный дескриптор» (Invalid handle) при выполнении строки [Console]::OutputEncoding = [Text.Encoding]::UTF8 возникает в тот момент, когда PowerShell запущен с перенаправленным или отсутствующим стандартным потоком вывода — например, из планировщика задач, службы, CI/CD-агента или через вызов из другого приложения. В этих условиях у процесса попросту нет настоящего окна консоли, и попытка обратиться к его дескриптору завершается ошибкой.
Проблема особенно часто проявляется в Windows PowerShell 5.1 при запуске скриптов в фоновом режиме, а также при вызове powershell.exe из Python, C# или планировщика заданий с перенаправлением stdout. Ниже разберём, почему возникает исключение, как безопасно задать кодировку и какие обходные пути существуют.
Почему возникает исключение «неверный дескриптор»
Свойство [Console]::OutputEncoding обращается к Win32-функциям, работающим с реальным консольным окном. Когда процесс стартует без консоли (с флагами скрытого окна, из службы или с перенаправленными потоками), дескриптор консоли либо равен нулю, либо указывает на несуществующий объект. Попытка записи в такой дескриптор и порождает исключение.
Типичные сценарии, в которых ошибка воспроизводится стабильно:
- 🕒 запуск скрипта через Планировщик заданий с опцией «Выполнять вне зависимости от входа пользователя»;
- ⚙️ вызов
powershell.exeиз другого процесса с перенаправлениемStandardOutput; - 🤖 выполнение в агентах сборки (Azure DevOps, GitHub Actions, Jenkins);
- 🪟 запуск с параметром
-WindowStyle Hiddenв некоторых конфигурациях; - 📡 удалённые сессии и фоновые задания
Start-Jobбез интерактивной консоли.
⚠️ Внимание: исключение не связано с «битыми» файлами PowerShell или повреждением системы. Это штатная реакция .NET на отсутствие консольного дескриптора — чинить нужно не установку, а способ задания кодировки.
Быстрая диагностика: есть ли консоль у процесса
Прежде чем менять кодировку, стоит проверить, существует ли вообще консольный вывод у текущего процесса. Самый простой способ — обернуть обращение в try/catch и посмотреть, сработает ли оно.
try {
[Console]::OutputEncoding = [Text.Encoding]::UTF8
"Кодировка установлена"
} catch {
"Консоль недоступна: $($_.Exception.Message)"
}
Дополнительно можно проверить, перенаправлен ли вывод, через свойство [Console]::IsOutputRedirected. Если оно возвращает True, то обращение к OutputEncoding почти гарантированно завершится ошибкой — и нужно использовать обходной путь.
Способ 1: безопасная установка кодировки через try/catch
Самое простое решение — не отказываться от OutputEncoding, а сделать его установку отказоустойчивой. Скрипт попытается задать кодировку, а при неудаче продолжит работу без падения.
if (-not [Console]::IsOutputRedirected) {
try {
[Console]::OutputEncoding = [Text.Encoding]::UTF8
} catch {
Write-Verbose "Не удалось задать OutputEncoding: $($_.Exception.Message)"
}
}
Такой подход подходит, когда скрипт должен работать в обоих режимах: интерактивно — с правильным отображением кириллицы, а в фоне — без падения. Обратите внимание: если вывод перенаправлен в файл, кодировку файла нужно контролировать отдельно, через параметры командлета записи.
Способ 2: кодировка через chcp и cmd
Альтернативный путь — задать кодовую страницу консоли командой chcp 65001 (UTF-8) до запуска PowerShell. Это работает, когда консоль существует, но обращение из .NET всё равно вызывает проблемы, либо когда скрипт запускается через cmd.exe-обёртку.
chcp 65001 >nul
powershell.exe -NoProfile -File "C:\Scripts\myscript.ps1"
Внутри самого PowerShell-скрипта вызвать chcp тоже можно — он выполняется как внешняя команда и не обращается к свойству [Console]::OutputEncoding напрямую:
cmd /c "chcp 65001 >nul"
⚠️ Внимание: если процесс запущен вообще без консоли (например, службой), то и chcp не поможет — менять кодировку нужно не консоли, а файла или потока, куда пишется вывод.
Способ 3: управление кодировкой при записи в файл
Когда вывод скрипта всё равно уходит в файл или в вызывающий процесс, гораздо надёжнее задавать кодировку на уровне командлета, а не консоли. У большинства командлетов вывода есть параметр -Encoding.
- 📄
Out-File -FilePath log.txt -Encoding utf8— явная запись в UTF-8; - ✍️
Set-Content -Encoding utf8иAdd-Content -Encoding utf8— для построчной записи; - 📤
$OutputEncoding = [Text.Encoding]::UTF8— переменная, управляющая кодировкой при передаче данных внешним командам через конвейер; её установка не требует консольного дескриптора.
Разница принципиальна: [Console]::OutputEncoding управляет окном консоли, а $OutputEncoding — кодировкой данных, которые PowerShell передаёт внешним программам. Вторая переменная работает в любых условиях, включая фоновые задачи.
Сравнение способов решения
| Способ | Где работает | Ограничения |
|---|---|---|
| try/catch вокруг OutputEncoding | Интерактивная консоль и смешанные сценарии | В фоне кодировка консоли не задаётся |
| chcp 65001 до запуска | Запуск через cmd, bat-обёртки | Бесполезен без консольного окна |
| $OutputEncoding | Любые режимы, включая фоновые | Влияет только на передачу внешним командам |
| -Encoding у Out-File / Set-Content | Запись вывода в файлы | Не меняет отображение в консоли |
Настройка запуска из планировщика заданий
Если ошибка появляется именно в Планировщике заданий, помимо правки скрипта стоит скорректировать и сам вызов. Запускайте задание от имени конкретного пользователя с активной сессией, если скрипту действительно нужна консоль, либо полностью уберите зависимость от консоли, перенаправив вывод в файл журнала.
Пример строки действия задания с записью вывода в лог:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\Scripts\task.ps1" *> "C:\Scripts\task.log"
Оператор *> перенаправляет все потоки (включая ошибки) в файл. Тогда даже если кодировка консоли недоступна, диагностическая информация сохранится, а исключение «неверный дескриптор» не прервет выполнение, если установка OutputEncoding обёрнута в try/catch.
☑️ Проверка скрипта перед запуском в фоне
Особенности PowerShell 7
В PowerShell 7 (на базе современного .NET) поведение несколько отличается: кодировкой по умолчанию для большинства операций является UTF-8 без BOM, и необходимость вручную задавать OutputEncoding возникает реже. Однако само исключение при обращении к несуществующему консольному дескриптору никуда не делось — оно по-прежнему возможно в фоновых сценариях.
Как проверить версию PowerShell
Выполните $PSVersionTable.PSVersion — мажорная версия 5 означает классический Windows PowerShell, 7 и выше — кроссплатформенный PowerShell (ранее PowerShell Core).
Поэтому рекомендации универсальны: независимо от версии делайте установку кодировки отказоустойчивой и не полагайтесь на консоль там, где её может не быть. Главная причина ошибки — отсутствие консольного окна у процесса, а не неправильное значение кодировки.
Часто задаваемые вопросы
Почему ошибка появляется только при запуске из планировщика, а вручную всё работает?
При ручном запуске у процесса есть интерактивная консоль с действительным дескриптором. Планировщик заданий часто запускает процесс без окна консоли, и обращение к [Console]::OutputEncoding завершается исключением «неверный дескриптор».
Чем $OutputEncoding отличается от [Console]::OutputEncoding?
Первая переменная задаёт кодировку данных, передаваемых внешним программам через конвейер, и не требует консоли. Вторая управляет кодировкой отображения в окне консоли и обращается к его системному дескриптору.
Можно ли полностью игнорировать это исключение?
Да, если скрипт корректно работает без установки кодировки консоли — достаточно обернуть строку в try/catch. Но если вывод кириллицы важен, задайте кодировку на уровне записи в файл через параметр -Encoding.
Помогает ли переустановка PowerShell или восстановление системы?
Нет. Исключение — штатная реакция на отсутствие консольного дескриптора, а не признак повреждения компонентов. Решается оно изменением кода скрипта или способа запуска, а не переустановкой.
Как задать UTF-8 для всего скрипта без обращения к консоли?
Установите $OutputEncoding = [Text.Encoding]::UTF8 для внешних команд и указывайте -Encoding utf8 у Out-File, Set-Content и Add-Content. Этого достаточно для корректной работы с кириллицей в фоновых сценариях.