Я хочу, щоб мій скрипт PowerShell зупинився, коли будь-яка команда, яку я запускаю, не виходить (як set -e
у баші). Я використовую як команди Powershell ( New-Object System.Net.WebClient
), так і програми ( .\setup.exe
).
Я хочу, щоб мій скрипт PowerShell зупинився, коли будь-яка команда, яку я запускаю, не виходить (як set -e
у баші). Я використовую як команди Powershell ( New-Object System.Net.WebClient
), так і програми ( .\setup.exe
).
Відповіді:
$ErrorActionPreference = "Stop"
отримає вам частину шляху туди (тобто це чудово підходить для cmdlets).
Однак для EXE вам потрібно буде перевірити $LastExitCode
себе після кожного виклику EXE і визначити, не вдалося це чи ні. На жаль, я не думаю, що PowerShell може тут допомогти, оскільки в Windows, EXE не надто послідовні щодо того, що є кодом виходу "успіх" або "збій". Більшість дотримується стандарту UNIX 0, що свідчить про успіх, але не всі. Ознайомтеся з функцією CheckLastExitCode в цій публікації блогу . Ви можете вважати його корисним.
throw "$exe failed with exit code $LastExitCode"
де $ exe - це лише шлях до EXE
Ви повинні мати змогу досягти цього, використовуючи оператор $ErrorActionPreference = "Stop"
на початку своїх сценаріїв.
Настройка за замовчуванням - $ErrorActionPreference
це Continue
, тому ви бачите, що ваші сценарії продовжують працювати після помилок.
На жаль, через помилкові командлети типу New-RegKey та Clear-Disk , жоден із цих відповідей недостатній. На даний момент я зупинився на наступних рядках у верхній частині будь-якого сценарію повноважень, щоб підтримувати свій розум.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
і тоді будь-який власний дзвінок отримує таке лікування:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Ця схема рідного дзвінка повільно стає для мене достатньо поширеною, що я, мабуть, повинен розглянути варіанти, щоб зробити її більш стислою. Я все ще є новичком, тому пропозиції вітаються.
Потрібно дещо інше обробка помилок для функцій shellhell і для виклику exe, і ви повинні бути впевнені, щоб повідомити абоненту вашого сценарію, що він не вдався. Спираючись на Exec
бібліотеку Psake, скрипт, який має структуру внизу, зупинятиметься на всіх помилках і може використовуватися як базовий шаблон для більшості сценаріїв.
Set-StrictMode -Version latest
$ErrorActionPreference = "Stop"
# Taken from psake https://github.com/psake/psake
<#
.SYNOPSIS
This is a helper function that runs a scriptblock and checks the PS variable $lastexitcode
to see if an error occcured. If an error is detected then an exception is thrown.
This function allows you to run command-line programs without having to
explicitly check the $lastexitcode variable.
.EXAMPLE
exec { svn info $repository_trunk } "Error executing SVN. Please verify SVN command-line client is installed"
#>
function Exec
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
[Parameter(Position=1,Mandatory=0)][string]$errorMessage = ("Error executing command {0}" -f $cmd)
)
& $cmd
if ($lastexitcode -ne 0) {
throw ("Exec: " + $errorMessage)
}
}
Try {
# Put all your stuff inside here!
# powershell functions called as normal and try..catch reports errors
New-Object System.Net.WebClient
# call exe's and check their exit code using Exec
Exec { setup.exe }
} Catch {
# tell the caller it has all gone wrong
$host.SetShouldExit(-1)
throw
}
Exec { sqlite3.exe -bail some.db "$SQL" }
, -bail
викликає помилку, оскільки вона намагається інтерпретувати її як параметр Cmdlet? Зберігати речі в лапки, схоже, не виходить. Будь-які ідеї?
Невелика зміна відповіді від @alastairtree:
function Invoke-Call {
param (
[scriptblock]$ScriptBlock,
[string]$ErrorAction = $ErrorActionPreference
)
& @ScriptBlock
if (($lastexitcode -ne 0) -and $ErrorAction -eq "Stop") {
exit $lastexitcode
}
}
Invoke-Call -ScriptBlock { dotnet build . } -ErrorAction Stop
Ключові відмінності тут:
Invoke-Command
)-ErrorAction
поведінку від вбудованих командлетівInvoke-Call { dotnet build $something }
& @ScriptBlock
і, & $ScriptBlock
здається, роблять те саме. Чи не вдалося Google , що різниця в даному випадку
Я прийшов сюди шукати те саме. $ ErrorActionPreference = "Стоп" вбиває мою оболонку негайно, коли я швидше побачу повідомлення про помилку (паузу), перш ніж воно закінчиться. Відпадання моєї партії чутливості:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Я виявив, що це працює майже однаково для мого конкретного сценарію ps1:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Перенаправлення stderr
на, stdout
здається, також виконує трюк без будь-яких інших команд / скриптів-обгортків, хоча я не можу знайти пояснення, чому це працює таким чином ..
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Це виведе наступне, як очікувалося (команда aws s3 ...
повертається $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
працює для добре сприйнятих програм (які повертають 0 на успіх)?