Kuasai penanganan error di PowerShell: pahami perbedaan error terminating dan non-terminating, bangun blok try-catch-finally yang solid, pilih throw atau Write-Error, atur perilaku lewat variabel otomatis, dan terapkan praktik terbaik untuk skrip yang siap produksi.

Di episode 11 kalian menguasai regular expressions — pola teks untuk menyaring, memvalidasi, dan mengekstrak data. Tapi ada satu fakta yang tidak bisa dihindari: sebaik apa pun pola kalian, skrip tetap bisa gagal. File hilang, server mati, permission ditolak. Pertanyaan yang benar bukan apakah skrip akan error, melainkan bagaimana kalian meresponsnya.
Episode ini membahas error handling secara menyeluruh: error terminating versus non-terminating, anatomi error record dan exception, blok try/catch/finally, memilih throw atau Write-Error, mengendalikan perilaku lewat $ErrorActionPreference dan -ErrorAction, serta riwayat error di $Error.
Bayangkan kalian mengirim karton berisi sepuluh paket lewat kurir. Ada dua jenis kegagalan yang berbeda. Yang pertama: satu paket di dalam karton penyok — kurir mencatatnya, tapi tetap mengantarkan sembilan paket lainnya. Yang kedua: alamat seluruh karton salah — pengiriman berhenti total.
Dua kegagalan itu persis memetakan dua tipe error di PowerShell:
Get-Content untuk beberapa file di mana salah satunya tidak bisa dibuka. Perintah tidak berhenti; ia menampilkan error dan tetap membaca file lain.throw, atau exception .NET seperti membagi angka dengan nol. Tanpa penanganan, skrip berhenti di titik itu.Kenapa pembagian ini penting? Karena blok try/catch hanya menangkap error terminating dengan andal. Error non-terminating biasanya "bocor" melewati try/catch tanpa tertangkap — inilah sumber kebingungan terbesar. Perhatikan perbedaannya saat dijalankan:
Get-Content file-ada.txt, file-hilang.txt
Write-Host "Baris ini tetap dicetak"throw "Koneksi database gagal"
Write-Host "Baris ini tidak pernah dicetak"Pada contoh pertama, Get-Content menampilkan error untuk file yang hilang, tapi Write-Host tetap dijalankan. Pada contoh kedua, throw menghentikan skrip sehingga baris berikutnya tidak pernah dieksekusi.
Setiap error di PowerShell adalah objek ErrorRecord — bungkusan berisi pesan, kategori error, target objek, dan exception yang mendasarinya. Non-terminating dan terminating sama-sama menghasilkan error record; yang berbeda hanya perilakunya terhadap pipeline.
Exception adalah objek .NET yang terbungkus di dalam record. Properti Exception menyimpan detail penyebab, dan tipe exception-nya — misalnya System.IO.FileNotFoundException — menjadi kunci untuk menangkap error yang spesifik. Cara melihat detailnya: isi variabel otomatis $Error[0] yang selalu menyimpan error terbaru — akan dibahas dalam bentuk kode di bagian bawah episode.
Struktur penanganan error di PowerShell adalah blok try yang membungkus kode berisiko, catch untuk merespons kegagalan, dan finally untuk pembersihan. Bentuk paling dasar:
try {
$isi = Get-Content "/etc/hosts" -ErrorAction Stop
Write-Host "Berhasil membaca $($isi.Count) baris"
}
catch {
Write-Host "Gagal membaca file: $($_.Exception.Message)"
}Di dalam blok catch, variabel otomatis $_ menunjuk ke error record yang sedang ditangani — dari situlah $_.Exception.Message diambil.
Analogikan dengan sistem alarm: satu alarm besar yang berbunyi untuk segala gangguan sulit ditangani karena kita tidak tahu sumber masalahnya. Lebih baik kenali tipe exception-nya satu per satu, lalu biarkan satu catch umum sebagai jaring pengaman terakhir.
try {
$data = Invoke-RestMethod "https://api.contoh.com/data" -ErrorAction Stop
}
catch [System.Net.WebException] {
Write-Host "Masalah jaringan - cek koneksi."
}
catch [System.UnauthorizedAccessException] {
Write-Host "Token tidak valid."
}
catch {
Write-Host "Error tak terduga: $($_.Exception.Message)"
}Urutan catch diperiksa dari atas ke bawah. Tulis blok yang paling spesifik lebih dulu, dan simpan catch tanpa tipe di paling akhir sebagai cadangan.
Blok finally dijalankan selalu, tanpa peduli apakah try sukses atau catch menangkap error. Ini tempat yang tepat untuk pembersihan: menutup koneksi, menghapus file sementara, atau mengembalikan state. Seperti bulu pensil yang tetap terhapus baik hasil tulisan bagus maupun salah.
$file = [System.IO.File]::OpenWrite("/tmp/catatan.txt")
try {
$file.WriteByte(65)
}
catch {
Write-Host "Gagal menulis ke file."
}
finally {
$file.Close()
Write-Host "Handle file ditutup."
}Jika try sukses, catch dilewati; jika error terjadi, catch menanganinya — dan dalam kedua kasus finally tetap berjalan. Tanpa finally, resource yang sedang dibuka akan menggantung menjadi kebocoran.
Terkadang satu level tidak cukup: kalian perlu menangani kegagalan pada tahap tertentu secara lokal, namun tetap membiarkan error yang lebih serius naik ke level atas. Seperti petugas pintu yang menangani tamu biasa, tetapi memanggil keamanan untuk tamu yang membahayakan.
try {
Copy-Item "/data/produksi.db" "/backup/produksi.db" -ErrorAction Stop
try {
Invoke-Sqlcmd -Query "SELECT 1" -ErrorAction Stop
}
catch {
Write-Host "Query gagal, mencoba lagi..."
}
}
catch {
Write-Host "Backup gagal - membatalkan operasi."
throw
}Perhatikan throw tanpa argumen di catch terluar — ia mengirim ulang error yang sedang ditangani ke pemanggil berikutnya. Inilah pola rethrow: catat di lapisan ini, biarkan lapisan atas memutuskan nasib akhir.
Dua cara utama memunculkan error buatan: throw dan Write-Error.
throw menghasilkan error terminating — cocok untuk kode yang memang harus berhenti (fungsi, logika validasi). Ia juga menjadi sarana rethrow di dalam catch.Write-Error menulis error record ke aliran error tanpa menghentikan eksekusi — error bersifat non-terminating. Cocok untuk melaporkan masalah pada satu item namun tetap melanjutkan proses lain.function Test-Port {
param($Port)
if ($Port -lt 1 -or $Port -gt 65535) {
throw "Port $Port di luar rentang 1-65535"
}
Write-Output "Port $Port valid"
}Aturan praktis: gunakan throw untuk kegagalan yang harus menghentikan alur, dan Write-Error untuk kegagalan satu item yang boleh dilewati.
Selain memutuskan di level perintah, kalian bisa mengubah perilaku default error non-terminating di level sesi melalui variabel otomatis $ErrorActionPreference.
| Nilai | Perilaku |
|---|---|
| Continue | Tampilkan error, lanjutkan (default) |
| SilentlyContinue | Sembunyikan error, lanjutkan |
| Stop | Perlakukan semua error sebagai terminating |
| Ignore | Sembunyikan error dan jangan catat ke $Error |
Nilai -ErrorAction pada sebuah perintah (misal Get-Item -ErrorAction SilentlyContinue) selalu menimpa preferensi global untuk satu pemanggilan itu saja. Ignore unik karena error tidak ditampilkan dan tidak direkam ke $Error — paling hemat resource jika kalian memang tidak peduli pada error tersebut.
Important
Jangan pernah mengeset $ErrorActionPreference = "Stop" tanpa alasan di skrip produksi. Perubahan global ini membuat perintah-perintah lain ikut berperilaku terminating — termasuk yang awalnya aman. Akibatnya, satu file yang tidak ada bisa menghentikan seluruh pipeline. Jika hanya butuh error terminating pada satu perintah, gunakan -ErrorAction Stop secara eksplisit, atau batasi perubahan di dalam sebuah blok kecil dan kembalikan nilai sebelumnya.
Sesi PowerShell menyimpan seluruh riwayat error ke variabel otomatis $Error, yang berupa daftar. Konvensinya: $Error[0] selalu berisi error terbaru, $Error[1] yang lebih lama, dan seterusnya — indeks berjalan mundur dari waktu.
Get-Item file-tidak-ada.txt -ErrorAction SilentlyContinue
$Error.Count
$Error[0].Exception.Message
$Error.Clear()
$Error.Count$Error.Clear() mengosongkan riwayat — berguna di awal tes atau skrip agar hanya error dari sesi tersebut yang dihitung.
Praktik yang bisa kalian terapkan hari ini:
-ErrorAction Stop bila ingin try/catch menangkap error dari cmdlet — tanpa itu, mayoritas error cmdlet bersifat non-terminating dan lolos dari catch.catch dari tipe paling spesifik ke catch umum paling akhir.finally untuk resource — file, koneksi, session — agar tidak bocor saat terjadi error.$ErrorActionPreference = "Stop" secara global di skrip produksi.Episode ini mengubah error dari musuh yang misterius menjadi kejadian yang terkendali: kalian kini memahami error terminating yang menghentikan eksekusi versus non-terminating yang hanya melaporkan; membedah error record dan exception; membangun try/catch/finally dengan penangkapan exception spesifik, finally untuk pembersihan, dan try-catch bersarang dengan pola rethrow; memilih throw atau Write-Error sesuai konteks; mengendalikan perilaku global lewat $ErrorActionPreference dan parameter -ErrorAction; serta membaca riwayat error dengan $Error.
Poin kunci yang dibawa pulang:
try/catch hanya menangkap error terminating — tambahkan -ErrorAction Stop bila perlu.finally dijamin berjalan, di situlah pembersihan resource.catch dari exception spesifik ke umum.$Error[0] adalah error terbaru; $Error.Clear() membersihkan riwayat.Skrip yang tahan banting adalah skrip yang tahu harus berbuat apa saat segalanya salah. Di episode 13 kita mengorganisasi kode kalian ke dalam unit yang bisa dibagikan: PowerShell Modules — script module, manifest, PowerShell Gallery, hingga cara membuat modul kalian sendiri. Sampai jumpa di episode 13!