Неправильное выполнение блока перехвата в PowerShell - PullRequest
0 голосов
/ 19 мая 2018

Я разработчик на C #, и иногда PowerShell просто сводит меня с ума.

У меня есть следующий код:

$script:ErrorActionPreference = 'Stop'

try {
    # Some code here
}
catch [Microsoft.PowerShell.Commands.WriteErrorException] {
    # Print error messages (without stacktrace)
    Write-Host -ForegroundColor Red $_.Exception.Message
    exit 1
}
catch [System.Management.Automation.RuntimeException] {
    # A thrown string
    Write-Host -ForegroundColor Red $_.Exception.Message
    Write-Host -ForegroundColor Red $_.ScriptStackTrace
    exit 1
}
catch {
    # Print proper exception message (including stack trace)
    Write-Host -ForegroundColor Red "$($_.Exception.GetType().Name): $($_.Exception.Message)"
    Write-Host -ForegroundColor Red $_.ScriptStackTrace
    exit 1
}

Идея в основном:

  1. Если исключение происходит от вызова Write-Error, используйте первый блок перехвата.
  2. Если строка выбрасывается напрямую, используйте второй блок перехвата.
  3. Для любого другого исключения используйте последний блок catch.

Теперь моя проблема с Write-Error и первым блоком catch:

  • Если я вызываю Write-Error в блоке try, выполняется второй блок catch (даже если должен выполняться первый).
  • Если я удаляю второй блок перехвата, а затем вызов Write-Error, используется правильный (первый) блок перехвата.

Почему это так?

Я проверил, WriteErrorExceptionи RuntimeException наследуют друг от друга: они не наследуют (оба наследуют от SystemException, но это не должно иметь значения).

Я также проверил, что это поведение сэмав PowerShell 5.1 и PowerShell Core (6.0).

1 Ответ

0 голосов
/ 19 мая 2018

Write-Error не выдаст завершающую ошибку по умолчанию, но с ErrorActionPreference будет установлено Stop, как вы упомянули.Однако это изменяет исключение, выданное на ActionPreferenceStopException, которое действительно наследует RuntimeException

Вы все еще можете поймать WriteErrorException без предложения RuntimeException, поскольку запись внутренней ошибки дляActionPreferenceStopException содержит WriteErrorException

Вы можете понять, что я имею в виду, выполнив следующее:

Write-Error 'this is a test' -ErrorAction Stop
$error[0].ErrorRecord.Exception.GetType()
# IsPublic IsSerial Name                        BaseType
# -------- -------- ----                        --------
# True     True     WriteErrorException         System.SystemException

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

Чтобы обойти это, вам нужно либо сгенерировать более конкретное исключение, либо проверить $_ в предложении RuntimeException.Вот последнее

$script:ErrorActionPreference = 'Stop'

try {
    # Some code here
}
catch [Microsoft.PowerShell.Commands.WriteErrorException] {
    # Print error messages (without stacktrace)
    Write-Host -ForegroundColor Red $_.Exception.Message
    exit 1
}
catch [System.Management.Automation.RuntimeException] {
    if ($_.Exception -is [Microsoft.PowerShell.Commands.WriteErrorException]) {
        # Print error messages (without stacktrace)
        Write-Host -ForegroundColor Red $_.Exception.Message
        exit 1
    }

    # A thrown string
    Write-Host -ForegroundColor Red $_.Exception.Message
    Write-Host -ForegroundColor Red $_.ScriptStackTrace
    exit 1
}
catch {
    # Print proper exception message (including stack trace)
    Write-Host -ForegroundColor Red "$($_.Exception.GetType().Name): $($_.Exception.Message)"
    Write-Host -ForegroundColor Red $_.ScriptStackTrace
    exit 1
}

Вы также можете добавить туда предложение ActionPreferenceStopException и проверить для $_.

Редактировать: На самом деле, если вы не на самом деле хотите использовать Write-Error, вам было бы лучше просто вызвать исключение, похожее на то, как в C #.Поэтому вместо Write-Error используйте:

throw [System.InvalidOperationException]::new('This is my message')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...