about_Error_Handling

Краткое описание

Описывает типы ошибок в PowerShell и механизмы их обработки.

Длинное описание

PowerShell различает три категории ошибок:

  • Неустранимые ошибки
  • Завершающие инструкции ошибки
  • Завершающие ошибки скрипта

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

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

Типы ошибок

Неустранимые ошибки

Неустранимая ошибка сообщает о проблеме, но не останавливает конвейер. Команда продолжает обрабатывать последующие входные объекты. Неустранимые ошибки создаются следующими:

  • Write-Error Командлет
  • $PSCmdlet.WriteError() Метод в расширенных функциях
  • Командлеты, которые сталкиваются с восстанавливаемыми сбоями в отдельных входных объектах

По умолчанию PowerShell отображает сообщение об ошибке и продолжает выполнение.

# Non-terminating error: the pipeline continues after the failure
'file1.txt', 'noSuchFile.txt', 'file3.txt' | ForEach-Object {
    Get-Content $_ -ErrorAction Continue
}

В этом примере Get-Content сообщает об ошибке noSuchFile.txt , не завершающейся, а затем продолжает обработку file3.txt.

Неисключающие ошибки не активируются catch или trap по умолчанию.

Завершающие инструкции ошибки

После завершения инструкции ошибка останавливает выполнение текущей инструкции (конвейера), но выполнение продолжается на следующей инструкции в скрипте. Завершающие инструкции ошибки создаются следующими:

  • $PSCmdlet.ThrowTerminatingError() Метод в расширенных функциях и скомпилированных командлетах
  • Ошибки подсистемы, такие как CommandNotFoundException (вызов команды, которая не существует) и ParameterBindingException (недопустимые аргументы параметров)
  • Вызовы метода .NET, которые вызывают исключения, например [int]::Parse('abc')
# Statement-terminating error: Get-Item fails, but the next statement runs
Get-Item -Path 'C:\NoSuchFile.txt'
Write-Output 'This still runs'

Завершающие инструкции ошибки могут быть пойманы try/catch и trap.

Замечание

.ThrowTerminatingError() не обращается к параметру -ErrorAction (за исключением Break значения, которое вводит отладчик). $ErrorActionPreference Однако применяется к завершающим ошибкам операторов через обработчик уровня инструкции обработчика. Например, может подавлять завершающуюся ошибку оператора, $ErrorActionPreference = 'SilentlyContinue' чтобы скрипт продолжался в следующей инструкции. Этот -ErrorAction параметр не может сделать. Дополнительные сведения см. в разделе "Асимметрия $ErrorActionPreference".

Завершающие ошибки скрипта

Завершающаяся ошибка скрипта удаляет весь стек вызовов. Выполнение останавливается полностью, если ошибка не перехватывается блоком или try/catch операторомtrap. Завершающие скрипты ошибки создаются следующими:

  • Ключевое слово throw
  • Синтаксические ошибки анализа (синтаксические ошибки, которые препятствуют компиляции скрипта)
  • Неустранимые ошибки , вызванные-ErrorAction Stop или $ErrorActionPreference = 'Stop' неоконцентными контекстами. Дополнительные сведения см. в разделе "Как работает эскалация".
  • Некоторые критические сбои двигателя
# Script-terminating error: throw unwinds the call stack
function Test-Throw {
    throw 'Critical failure'
    Write-Output 'This never runs'
}

Test-Throw
Write-Output 'This never runs either (unless caught)'

Ключевое throw слово по умолчанию создает ошибку, завершающая скрипт. Однако $ErrorActionPreference подавляться, throw если задано SilentlyContinue значение или Ignore. При вызове расширенной функции с -ErrorAction SilentlyContinueпараметром преобразуется в локальное $ErrorActionPreference значение области, поэтому он также подавляет throw внутри этой функции.

Замечание

Даже с $ErrorActionPreference = 'Ignore'тем, что throw этот параметр все еще записывает запись в $Error. Значение Ignore запрещает $Error запись только для неисключающих ошибок.

Это важно

Термины , завершающие и завершающиескрипт , описывают область влияния, а не серьезность ошибки. Завершающаяся ошибка оператора останавливает одну инструкцию. Завершающаяся ошибка скрипта останавливает весь скрипт и его вызывающие. Оба могут быть пойманы try/catch.

Ошибки внешней программы

Внешние (собственные) программы не участвуют непосредственно в системе ошибок PowerShell. Они сообщают о сбое с помощью кода выхода, отличного от нуля, который PowerShell хранит в автоматической переменной $LASTEXITCODE .

git clone https://example.com/nonexistent.git 2>$null
if ($LASTEXITCODE -ne 0) {
    Write-Error "git failed with exit code $LASTEXITCODE"
}

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

  • Задает значение $?$false
  • Не создает вход ErrorRecord$Error
  • Не активирует или не активирует catchtrap

PowerShell 7.3 добавила экспериментальную переменную $PSNativeCommandUseErrorActionPreferenceпредпочтения, которая стала стабильной функцией в версии 7.4. При установке этой переменной это значение $trueвызывает ненулевой код выхода, который выдает неисключаемую ошибку , сообщение которой указывает конкретный код выхода (a NativeCommandExitException). Эта ошибка учитывается $ErrorActionPreferenceтаким образом, чтобы задать ее для Stop распространения ошибки на завершающую ошибку скрипта, с помощью которую можно пойматьtry/catch.

Переменные состояния ошибки

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

$?

Содержит, $true если последняя операция завершилась успешно, и $false если она вызвала какую-либо ошибку (не завершающаяся или завершающаяся). Для собственных $? команд устанавливается на основе кода выхода: $true для кода 0выхода, $false в противном случае.

Get-Item -Path 'C:\NoSuchFile.txt' 2>$null
$?  # False

$Error

Объект ArrayList , в который хранятся последние записи об ошибках, с последней ошибкой по индексу 0. Список содержит до $MaximumErrorCount записей (по умолчанию 256).

Все конечные ошибки добавляются в $Error. Для прекращения ошибок отключает отображение, Ignore но по-прежнему записывает ошибку $Error. Все неустранимые добавляются $Error , если -ErrorAction Ignore не используется для неисключающих ошибок, что предотвращает отображение и запись.

$LASTEXITCODE

Содержит код выхода последней запущенной собственной программы. Значение 0 обычно указывает на успешность. Любое ненулевое значение указывает на сбой. Эта переменная не влияет на ошибки командлетов PowerShell.

Управление поведением ошибки

Общий -ErrorAction параметр

Общие -ErrorAction параметры переопределяются $ErrorActionPreference для одной команды. Он определяет, как PowerShell реагирует на неисключающие ошибки из этой команды.

Ценность Поведение
Continue Отображение ошибки и продолжение (по умолчанию)
SilentlyContinue Отключить отображение, добавить в $Error, продолжить
Ignore Отключение отображения и не добавление в $Error
Stop Эскалация до конца ошибки (см. инструкции по эскалации)
Inquire Запрос пользователя на принятие решения
Break Введите отладчик

-ErrorAction не изменяет поведение ошибок, $PSCmdlet.ThrowTerminatingError()создаваемых . Эти ошибки всегда завершаются оператором независимо от предпочтений вызывающего объекта.

Переменная $ErrorActionPreference

Переменная $ErrorActionPreference предпочтения применяется ко всем командам в текущей области и дочерних областях. Он принимает те же значения, что -ErrorActionи .

$ErrorActionPreference = 'Stop'
# All non-terminating errors in this scope now become terminating
Write-Error 'This now throws'   # Generates ActionPreferenceStopException

Если -ErrorAction задано в команде, она имеет приоритет $ErrorActionPreference над этой командой.

Как работает эскалация

Если -ErrorAction Stop или $ErrorActionPreference = 'Stop' в действительности, PowerShell преобразует неисключающие ошибки в завершающие ошибки с помощью следующего механизма:

  1. Командлет вызывает WriteError() внутреннее сообщение об ошибке, не завершающейся.
  2. Модуль проверяет действующие ErrorAction предпочтения команды.
  3. Так как предпочтительный параметр, Stopподсистема создает ActionPreferenceStopException исходную запись об ошибке.
  4. Если вы поймали catch, исходная информация об ошибке доступна через $_.Exception.ErrorRecord.

Область эскалации ошибки зависит от контекста:

  • В не расширенных сценариях, функциях или блоках скриптов параметр $ErrorActionPreference = 'Stop' преобразуется в ошибку , завершающая скрипт . Ошибка распространяется на стек вызовов.
  • В расширенных функциях и блоках скриптов (с [CmdletBinding()]) ошибка остается завершающим оператором. Выполнение продолжается в следующей инструкции после вызова.
  • Передача -ErrorAction Stop в расширенную функцию имеет тот же эффект, что и настройка $ErrorActionPreference = 'Stop' внутри нее, так как -ErrorAction преобразуется в локальное $ErrorActionPreference значение области.

Примеры эскалации

  • NON-advanced: завершение скрипта ("after" не печатается)

    & {
        param()
        $ErrorActionPreference = 'Stop'
        1/0  # Divide by zero error
    } 2>$null
    'after'
    
  • ADVANCED: завершение инструкции ("after" ВЫПОЛНЯЕТ печать)

    & {
        [CmdletBinding()]
        param()
        $ErrorActionPreference = 'Stop'
        1/0  # Divide by zero error
    } 2>$null
    'after'
    
  • Без -ErrorAction Stop: без конца, catch не выполняется

    try {
        Write-Error 'This is non-terminating'
        Write-Output 'Execution continues'
    } catch {
        Write-Output "Caught: $_"   # Not reached
    }
    
  • С : -ErrorAction Stopпереросло на завершение

    try {
        Write-Error 'This becomes terminating' -ErrorAction Stop
    } catch {
        Write-Output "Caught: $_"   # Reached
    }
    

Перераскрытые ошибки могут быть пойманы по исходному типу исключений. Подсистема распаковывает ActionPreferenceStopException базовое исключение:

try {
    Get-Item -Path 'C:\NoSuchFile.txt' -ErrorAction Stop
} catch [System.Management.Automation.ItemNotFoundException] {
    Write-Output "File not found: $($_.Exception.Message)"
}

$ErrorActionPreference Асимметрия

Параметр -ErrorAction и $ErrorActionPreference переменная ведут себя по-разному с ошибками конца. Важно понимать эту асимметрию:

  • -ErrorAction влияет только на неустранимые ошибки. При вызове $PSCmdlet.ThrowTerminatingError()-ErrorAction командлета параметр игнорируется (за исключением Breakтого, что входит в отладчик). Ошибка всегда возникает.

  • $ErrorActionPreference влияет как на завершающие, так и завершающие инструкции ошибки. Обработчик ошибок уровня инструкции считывает $ErrorActionPreference (не -ErrorAction параметр) и может подавлять завершающееся сообщение об ошибке при значении SilentlyContinue или Ignore.

function Test-Asymmetry {
    [CmdletBinding()]
    param()
    $er = [System.Management.Automation.ErrorRecord]::new(
        [System.InvalidOperationException]::new('test error'),
        'TestError',
        [System.Management.Automation.ErrorCategory]::InvalidOperation,
        $null
    )
    $PSCmdlet.ThrowTerminatingError($er)
}

# -ErrorAction SilentlyContinue does NOT suppress the error:
Test-Asymmetry -ErrorAction SilentlyContinue   # Error is still thrown

# $ErrorActionPreference DOES suppress the error:
$ErrorActionPreference = 'SilentlyContinue'
Test-Asymmetry   # Error is silently suppressed, script continues
$ErrorActionPreference = 'Continue'

Это важно

$ErrorActionPreference Не удается отключить ошибки, для которых задано SuppressPromptInInterpreter значение true. Они всегда распространяются независимо от переменной предпочтения. Ниже приведены примеры ошибки этого типа:

  • ActionPreferenceStopException от -ErrorAction Stop эскалации
  • Ошибки в методах класса PowerShell
  • PipelineStoppedException

Управление ошибками

try/catch/finally

Используется try/catch/finally для обработки завершающих инструкций и завершающихся сценарием ошибок. При возникновении ошибки в блоке try PowerShell выполняет поиск соответствующего catch блока. Блок finally всегда выполняется независимо от того, произошла ли ошибка.

try {
    $result = Get-Content -Path 'data.txt' -ErrorAction Stop
}
catch [System.Management.Automation.ItemNotFoundException] {
    Write-Warning 'Data file not found, using defaults.'
    $result = 'default'
}
catch {
    Write-Warning "Unexpected error: $_"
}
finally {
    Write-Verbose 'Cleanup complete.' -Verbose
}

try Внутри блока подсистема задает внутренний флаг, который приводит к неисключающим ошибкам, вызванным -ErrorAction Stop эскалацией или $ErrorActionPreference = 'Stop' распространением в catch блок. Это разработано поведение, а не особый случай.

Полные сведения о синтаксисе см. в about_Try_Catch_Finally.

trap

Оператор trap обрабатывает завершающие ошибки на уровне области. При возникновении ошибки в любой точке включающей области trap блок выполняется.

  • По умолчанию (нет break или continue): отображается ошибка, и выполнение продолжается в следующей инструкции после ошибки.
  • continue в ловушке: подавляет сообщение об ошибке и возобновляет работу в следующей инструкции.
  • break в ловушке: ошибка распространяется на родительскую область.
trap [System.Management.Automation.CommandNotFoundException] {
    Write-Warning "Command not found: $($_.TargetObject)"
    continue
}

NonsenseCommand   # Trap fires, execution continues
Write-Output 'This runs because the trap used continue'

Полные сведения о синтаксисе см. в about_Trap.

Создание отчетов об ошибках в функциях и сценариях

При написании функций и скриптов выберите механизм создания отчетов об ошибках, соответствующий серьезности сбоя.

Без конца — использование Write-Error

Используется Write-Error , когда функция может продолжить обработку других входных данных. Это подходит для функций конвейера, которые обрабатывают несколько объектов и сталкиваются с ошибками в отдельных элементах.

function Test-Path-Safe {
    [CmdletBinding()]
    param([Parameter(ValueFromPipeline)][string]$Path)
    process {
        if (-not (Test-Path $Path)) {
            Write-Error "Path not found: $Path"
            return
        }
        $Path
    }
}

Замечание

В расширенных функциях (с [CmdletBinding()]) используйте $PSCmdlet.WriteError() вместо Write-Error того, чтобы убедиться, что $? он правильно задан $false в области вызывающего объекта. Командлет Write-Error не всегда задан $? правильно.

Завершение инструкции — использование $PSCmdlet.ThrowTerminatingError()

Используйте $PSCmdlet.ThrowTerminatingError() , когда функция не может продолжаться вообще, но вызывающий должен решить, как обработать сбой. Это рекомендуемый подход в расширенных функциях.

function Get-Config {
  [CmdletBinding()]
  param([string]$Path)

  if (-not (Test-Path $Path)) {
    $er = [System.Management.Automation.ErrorRecord]::new(
      [System.IO.FileNotFoundException]::new("Config file not found: $Path"),
      'ConfigNotFound',
      [System.Management.Automation.ErrorCategory]::ObjectNotFound,
      $Path
    )
    $PSCmdlet.ThrowTerminatingError($er)
  }

  Get-Content $Path | ConvertFrom-Json
}

После того как ошибка покидает функцию, вызывающий объект обрабатывает его как неисключаемую ошибку по умолчанию. Вызывающий объект может перерасти его с -ErrorAction Stopпомощью .

Завершение скрипта — использование throw

Используйте throw , если восстановление невозможно, и весь скрипт должен остановиться.

$config = Get-Content 'config.json' -ErrorAction SilentlyContinue |
    ConvertFrom-Json

if (-not $config) {
    throw 'Cannot proceed without a valid configuration file.'
}

Какой механизм следует использовать

  • При обработке нескольких входных данных, в которых некоторые могут завершиться ошибкой, использовать Write-Error или $PSCmdlet.WriteError().
  • Если функция не может продолжаться, используйте $PSCmdlet.ThrowTerminatingError() и позвольте вызывающему объекту решить, как его обрабатывать.
  • Если весь скрипт должен немедленно остановиться, используйте throw.

Сводка типов ошибок

В следующих таблицах приведены сведения о свойствах и поведении различных типов ошибок в PowerShell.

Неисключающая ошибка

Неустранимые ошибки можно создать Write-Error или $PSCmdlet.WriteError().

Атрибут Описание
Область воздействия Конвейер продолжается
Поймали catch Нет (если только не перераспределено)
Поймали trap Нет (если только не перераспределено)
Добавлено в $Error Да (если Ignoreне )
Задает значение $?$false Да
Затронуты -ErrorAction Да
Затронуты $ErrorActionPreference Да

Ошибка конца инструкции

Завершающие инструкции ошибки могут создаваться с помощью ThrowTerminatingError()ошибок подсистемы, исключений методов .NET или -ErrorAction Stop в расширенных контекстах.

Атрибут Описание
Область воздействия Текущая инструкция останавливается; Скрипт продолжается
Поймали catch Да
Поймали trap Да
Добавлено в $Error Да
Задает значение $?$false Да
Затронуты -ErrorAction Нет (Break только)
Затронуты $ErrorActionPreference Да (может подавлять)

Ошибка прекращения скрипта

Завершающие скрипты ошибки могут создаваться с помощью throwошибок синтаксического анализа или -ErrorAction Stop в не расширенных контекстах.

Атрибут Описание
Область воздействия Отмена стека вызовов
Поймали catch Да
Поймали trap Да
Добавлено в $Error Да
Задает значение $?$false Да
Затронуты -ErrorAction Нет
Затронуты $ErrorActionPreference throw: Да (может подавлять)
Затронуты $ErrorActionPreference Эскалация: зависит от контекста

См. также