Melihat skrip Get-WebFile di PoshCode, http://poshcode.org/3226 , saya perhatikan alat aneh yang ini:
$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return
Apa alasannya dibandingkan dengan yang berikut ini?
$URL_Format_Error = [string]"..."
Throw $URL_Format_Error
Atau lebih baik lagi:
$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error
Seperti yang saya pahami, Anda harus menggunakan Write-Error untuk kesalahan yang tidak berhenti, dan Lempar untuk mengakhiri kesalahan, jadi menurut saya Anda tidak boleh menggunakan Write-Error diikuti oleh Return. Apakah ada perbedaan?
powershell
error-handling
powershell-2.0
Bill Barry
sumber
sumber
return
tidak tidak kembali ke pemanggil dalamprocess
blok fungsi (lanjutan); sebagai gantinya, ia melanjutkan ke objek input berikutnya dalam pipa. Memang, ini adalah skenario khas untuk menghasilkan kesalahan yang tidak berhenti: jika memproses objek input lebih lanjut masih dimungkinkan.Throw
menghasilkan galat pemutusan skrip , yang tidak sama dengan galat pemutusan pernyataan yang dipicu, misalnya, olehGet-Item -NoSuchParameter
atau1 / 0
.Jawaban:
Write-Error
harus digunakan jika Anda ingin memberi tahu pengguna tentang kesalahan yang tidak penting. Secara default yang dilakukannya hanyalah mencetak pesan kesalahan dalam teks merah pada konsol. Itu tidak menghentikan pipa atau loop dari melanjutkan.Throw
di sisi lain menghasilkan apa yang disebut terminating error. Jika Anda menggunakan lemparan, pipa dan / atau loop saat ini akan dihentikan. Bahkan semua eksekusi akan dihentikan kecuali jika Anda menggunakan strukturtrap
atautry/catch
untuk menangani kesalahan terminating.Ada satu hal ke catatan, jika Anda menetapkan
$ErrorActionPreference
untuk"Stop"
dan menggunakanWrite-Error
itu akan menghasilkan kesalahan terminating .Dalam skrip yang ditautkan dengan kami temukan ini:
Sepertinya penulis fungsi itu ingin menghentikan eksekusi fungsi itu dan menampilkan pesan kesalahan di layar tetapi tidak ingin seluruh skrip berhenti dijalankan. Penulis skrip bisa menggunakan
throw
namun itu berarti Anda harus menggunakantry/catch
ketika memanggil fungsi.return
akan keluar dari ruang lingkup saat ini yang dapat berupa fungsi, skrip, atau blok skrip. Ini digambarkan dengan kode:Output untuk keduanya:
Satu gotcha di sini digunakan
return
denganForEach-Object
. Itu tidak akan merusak pemrosesan seperti yang mungkin diharapkan.Informasi lebih lanjut:
$ErrorActionPreference
: about_Preference_Variablestry/catch
: about_Try_Catch_Finallytrap
: about_Trapthrow
: about_Throwreturn
: about_Returnsumber
return
.Perbedaan utama antara cmdlet Write-Error dan kata kunci throw di PowerShell adalah bahwa yang pertama hanya mencetak beberapa teks ke aliran kesalahan standar (stderr) , sedangkan yang terakhir benar-benar menghentikan pemrosesan perintah atau fungsi yang sedang berjalan, yang kemudian ditangani oleh PowerShell dengan mengirimkan informasi tentang kesalahan ke konsol.
Anda dapat mengamati perilaku yang berbeda dari keduanya dalam contoh yang Anda berikan:
Dalam contoh ini
return
kata kunci telah ditambahkan untuk secara eksplisit menghentikan eksekusi skrip setelah pesan kesalahan dikirim ke konsol. Dalam contoh kedua, di sisi lain,return
kata kunci tidak diperlukan karena penghentian secara implisit dilakukan olehthrow
:sumber
[System.Management.Automation.ErrorRecord]
instance, yang secara default dikumpulkan dalam$Error
koleksi otomatis ($Error[0]
berisi kesalahan terbaru). Bahkan jika Anda hanya menggunakanWrite-Error
dengan string , string itu akan dibungkus dalam sebuah[System.Management.Automation.ErrorRecord]
instance.Penting : Ada 2 jenis kesalahan penghentian , yang sayangnya dikonfigurasikan oleh topik bantuan saat ini :
pernyataan- kesalahan yang memudar , seperti yang dilaporkan oleh cmdlet dalam situasi tertentu yang tidak dapat dipulihkan dan dengan ekspresi di mana pengecualian .NET / kesalahan runtime PS terjadi; hanya pernyataan yang diakhiri, dan eksekusi skrip berlanjut secara default .
script -terminating errors (lebih akurat: runspace-terminating ), baik dipicu oleh
Throw
atau dengan meningkatkan salah satu dari jenis kesalahan lainnya melalui preferensi-tindakan-variabel / nilai parameterStop
.Kecuali tertangkap, mereka menghentikan runspace saat ini (utas); yaitu, mereka menghentikan tidak hanya skrip saat ini, tetapi semua peneleponnya juga, jika berlaku).
Untuk ikhtisar komprehensif penanganan kesalahan PowerShell, lihat masalah dokumentasi GitHub ini .
Sisa dari posting ini berfokus pada kesalahan non-terminasi vs pernyataan-terminasi .
Untuk melengkapi jawaban membantu yang ada dengan fokus pada inti pertanyaan: Bagaimana Anda memilih apakah akan melaporkan statement- terminating atau non-terminating error ?
Pelaporan Kesalahan Cmdlet berisi panduan bermanfaat; izinkan saya mencoba ringkasan pragmatis :
Gagasan umum di balik kesalahan non-terminating adalah untuk memungkinkan pemrosesan "toleran-kesalahan" dari set input besar : kegagalan untuk memproses subset objek input tidak boleh (secara default) membatalkan proses - berpotensi berjalan lama - secara keseluruhan , memungkinkan Anda untuk memeriksa kesalahan dan hanya memproses ulang objek yang gagal nanti - seperti yang dilaporkan melalui catatan kesalahan yang dikumpulkan dalam variabel otomatis
$Error
.Laporkan kesalahan NON-TERMINASI , jika cmdlet / fungsi lanjutan Anda:
$PSCmdlet.WriteError()
untuk melaporkan kesalahan yang tidak berakhir (Write-Error
, sayangnya, tidak menyebabkan$?
diatur ke$False
dalam ruang lingkup penelepon - lihat masalah GitHub ini ).$?
memberi tahu Anda apakah perintah terbaru melaporkan setidaknya satu kesalahan non-terminasi.$?
menjadi$False
dapat berarti bahwa setiap subset objek input (tidak kosong) tidak diproses dengan benar, mungkin seluruh set.$ErrorActionPreference
dan / atau parameter cmdlet umum-ErrorAction
dapat memodifikasi perilaku kesalahan yang tidak berhenti (hanya) dalam hal perilaku output kesalahan dan apakah kesalahan yang tidak berhenti harus ditingkatkan ke script yang menghapus script .Laporkan kesalahan PENGAKHIRAN PERNYATAAN dalam semua kasus lainnya .
$PSCmdlet.ThrowTerminatingError()
untuk menghasilkan kesalahan penghentian pernyataan.Throw
kata kunci menghasilkan kesalahan penghentian skrip yang membatalkan seluruh skrip (secara teknis: utas saat ini ).try/catch
Pawang atautrap
pernyataan dapat digunakan (yang tidak dapat digunakan dengan kesalahan yang tidak berhenti ), tetapi perhatikan bahwa bahkan kesalahan pemutusan pernyataan secara default tidak mencegah sisa skrip agar tidak berjalan. Seperti halnya kesalahan non-terminasi ,$?
mencerminkan$False
jika pernyataan sebelumnya memicu kesalahan terminasi-pernyataan.Sayangnya, tidak semua cmdlet inti PowerShell sendiri sesuai dengan aturan ini :
Meskipun tidak mungkin gagal,
New-TemporaryFile
(PSv5 +) akan melaporkan kesalahan non-terminasi jika gagal, meskipun tidak menerima input pipa dan hanya menghasilkan satu objek output - ini telah diperbaiki setidaknya dari PowerShell [Core] 7.0, namun: lihat GitHub ini masalah .Resume-Job
Bantuan menyatakan bahwa meneruskan jenis pekerjaan yang tidak didukung (seperti pekerjaan yang dibuat denganStart-Job
, yang tidak didukung, karenaResume-Job
hanya berlaku untuk pekerjaan alur kerja) menyebabkan kesalahan penghentian, tetapi itu tidak berlaku pada PSv5.1.sumber
Write-Error
memungkinkan konsumen fungsi untuk menekan pesan kesalahan dengan-ErrorAction SilentlyContinue
(sebagai alternatif-ea 0
). Sementarathrow
membutuhkan atry{...} catch {..}
Untuk menggunakan coba ... tangkap dengan
Write-Error
:sumber
Tambahan untuk jawaban Andy Arismendi :
Apakah Write-Error menghentikan proses atau tidak tergantung pada
$ErrorActionPreference
pengaturan.Untuk skrip non-sepele,
$ErrorActionPreference = "Stop"
adalah pengaturan yang disarankan untuk gagal cepat.(dari http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/ )
Namun, itu membuat
Write-Error
panggilan berakhir.Untuk menggunakan Write-Error sebagai perintah non-terminating terlepas dari pengaturan lingkungan lainnya, Anda dapat menggunakan parameter umum
-ErrorAction
dengan nilaiContinue
:sumber
Jika pembacaan kode Anda benar maka Anda benar. Mengakhiri kesalahan harus digunakan
throw
, dan jika Anda berurusan dengan tipe .NET maka akan sangat membantu untuk juga mengikuti konvensi pengecualian .NET.sumber