Saya ingin skrip PowerShell saya berhenti ketika salah satu perintah yang saya jalankan gagal (seperti set -e
dalam bash). Saya menggunakan perintah Powershell ( New-Object System.Net.WebClient
) dan program ( .\setup.exe
).
Saya ingin skrip PowerShell saya berhenti ketika salah satu perintah yang saya jalankan gagal (seperti set -e
dalam bash). Saya menggunakan perintah Powershell ( New-Object System.Net.WebClient
) dan program ( .\setup.exe
).
Jawaban:
$ErrorActionPreference = "Stop"
akan membuat Anda menjadi bagian dari perjalanan ke sana (yaitu ini berfungsi bagus untuk cmdlets).
Namun untuk EXE Anda harus memeriksa $LastExitCode
diri Anda sendiri setelah setiap pemanggilan exe dan menentukan apakah itu gagal atau tidak. Sayangnya saya tidak berpikir PowerShell dapat membantu di sini karena pada Windows, EXEs tidak terlalu konsisten pada apa yang merupakan kode keluar "sukses" atau "kegagalan". Sebagian besar mengikuti standar UNIX 0 yang menunjukkan keberhasilan tetapi tidak semua melakukannya. Lihat fungsi CheckLastExitCode di posting blog ini . Anda mungkin menemukan itu berguna.
throw "$exe failed with exit code $LastExitCode"
mana $ exe hanyalah jalan menuju EXE.
Anda harus dapat mencapai ini dengan menggunakan pernyataan $ErrorActionPreference = "Stop"
di awal skrip Anda.
Pengaturan defaultnya $ErrorActionPreference
adalah Continue
, itulah sebabnya Anda melihat skrip Anda terus terjadi setelah kesalahan terjadi.
Sayangnya, karena cmdlets bermasalah seperti New-RegKey dan Clear-Disk , tidak ada jawaban yang cukup. Saat ini saya telah menetapkan baris berikut di bagian atas skrip PowerShell untuk menjaga kewarasan saya.
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction']='Stop'
dan lalu panggilan asli apa pun yang mendapatkan perawatan ini:
native_call.exe
$native_call_success = $?
if (-not $native_call_success)
{
throw 'error making native call'
}
Pola panggilan asli itu perlahan-lahan menjadi cukup umum bagi saya sehingga saya mungkin harus mencari opsi untuk membuatnya lebih ringkas. Saya masih seorang pemula yang tangguh, jadi saran dipersilahkan.
Anda perlu penanganan kesalahan yang sedikit berbeda untuk fungsi PowerShell dan untuk memanggil exe, dan Anda harus memastikan untuk memberi tahu penelepon skrip Anda bahwa ia telah gagal. Membangun di atas dari Exec
perpustakaan Psake, skrip yang memiliki struktur di bawah ini akan berhenti pada semua kesalahan, dan dapat digunakan sebagai templat dasar untuk sebagian besar skrip.
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" }
, yang -bail
menyebabkan kesalahan karena mencoba untuk menafsirkannya sebagai parameter Cmdlet? Membungkus barang dengan tanda kutip sepertinya tidak berhasil. Ada ide?
Sedikit modifikasi pada jawaban dari @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
Perbedaan utama di sini adalah:
Invoke-Command
)-ErrorAction
perilaku dari built in cmdletsInvoke-Call { dotnet build $something }
& @ScriptBlock
dan & $ScriptBlock
tampaknya melakukan hal yang sama. Belum dapat Google perbedaan apa dalam kasus ini
Saya datang ke sini mencari hal yang sama. $ ErrorActionPreference = "Stop" membunuh shell saya segera ketika saya lebih suka melihat pesan kesalahan (jeda) sebelum itu berakhir. Mengalami kepekaan batch saya:
IF %ERRORLEVEL% NEQ 0 pause & GOTO EOF
Saya menemukan bahwa ini berfungsi hampir sama untuk skrip ps1 khusus saya:
Import-PSSession $Session
If ($? -ne "True") {Pause; Exit}
Mengarahkan kembali stderr
ke stdout
tampaknya juga melakukan trik tanpa pembungkus perintah / script lainnya meskipun saya tidak dapat menemukan penjelasan mengapa itu bekerja seperti itu ..
# test.ps1
$ErrorActionPreference = "Stop"
aws s3 ls s3://xxx
echo "==> pass"
aws s3 ls s3://xxx 2>&1
echo "shouldn't be here"
Ini akan menampilkan yang berikut seperti yang diharapkan (perintah aws s3 ...
kembali $LASTEXITCODE = 255
)
PS> .\test.ps1
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied
==> pass
$ErrorActionPreference = "Stop"
bekerja untuk program yang berperilaku baik (yang mengembalikan 0 pada keberhasilan)?