Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Hata işleme, kod yazma söz konusu olduğunda hayatın yalnızca bir parçasıdır. Beklenen davranış için genellikle koşulları denetleyebiliriz ve doğrulayabiliriz. Beklenmeyen durum oluştuğunda özel durum işlemeye döneriz. Diğer kişilerin kodu tarafından oluşturulan özel durumları kolayca işleyebilir veya başkalarının işlemesi için kendi özel durumlarınızı oluşturabilirsiniz.
Not
Bu makalenin özgün sürümü, @KevinMarquette tarafından yazılan blogda yer almıştır. PowerShell ekibi, bu içeriği bizimle paylaştığı için Kevin'e teşekkür ederiz. Lütfen PowerShellExplained.com'daki blogunu inceleyin.
Temel terminoloji
Bu terime geçmeden önce bazı temel terimleri ele almalıyız.
Özel durum
Özel Durum, normal hata işleme sorunu çözemezse oluşturulan bir olay gibidir. Bir sayıyı sıfıra bölmeye çalışmak veya yetersiz bellek, özel durum oluşturan bir şeye örnektir. Bazen kullandığınız kodun yazarı, bazı sorunlar oluştuğunda özel durumlar oluşturur.
Atma ve Yakalama
Bir özel durum oluştuğunda, bir özel durumun oluştuğu söylenilir. Oluşan bir özel durumu işlemek için yakalamanız gerekir. Özel durum oluşturulursa ve bir şey tarafından yakalanmazsa betik yürütülemez.
Çağrı yığını
Çağrı yığını, birbirini çağıran işlevlerin listesidir. Bir işlev çağrıldığında, yığına veya listenin en üstüne eklenir. İşlev çıktığında veya döndürdüğünde, yığından kaldırılır.
Bir özel durum oluştuğunda, bir özel durum işleyicisi tarafından yakalanması için bu çağrı yığını denetlenir.
Sonlandırıcı ve sonlandırılmayan hatalar
Özel durum genellikle sonlandırıcı bir hatadır. Oluşan bir özel durum yakalanmış veya geçerli yürütmeyi sonlandırıyor. Varsayılan olarak, tarafından Write-Error
sonlandırılmayan bir hata oluşturulur ve özel durum oluşturmadan çıkış akışına bir hata ekler.
Bunu işaret ediyorum çünkü Write-Error
ve diğer sonlandırılmayan hatalar tetiklenmiyor catch
.
Özel durum yutma
Bu, yalnızca bunu gizlemeye yönelik bir hata yakaladığınız zamandır. Sorunları gidermeyi çok zorlaştırabileceğinden bunu dikkatli bir şekilde yapın.
Temel komut söz dizimi
PowerShell'de kullanılan temel özel durum işleme söz dizimine hızlı bir genel bakış aşağıda verilmiştir.
Throw
Kendi özel durum olayımızı oluşturmak için anahtar sözcüğüyle throw
bir özel durum oluştururuz.
function Start-Something
{
throw "Bad thing happened"
}
Bu, sonlandırıcı bir hata olan bir çalışma zamanı özel durumu oluşturur. Bir çağrı işlevinde tarafından catch
işlenir veya betikten şöyle bir iletiyle çıkar.
PS> Start-Something
Bad thing happened
At line:1 char:1
+ throw "Bad thing happened"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Bad thing happened:String) [], RuntimeException
+ FullyQualifiedErrorId : Bad thing happened
Yazma Hatası -ErrorAction Durdurma
Bunun varsayılan olarak sonlandırıcı bir hata oluşturmadığından bahsettim Write-Error
. belirtirseniz -ErrorAction Stop
, Write-Error
ile catch
işlenebilen bir sonlandırıcı hata oluşturur.
Write-Error -Message "Houston, we have a problem." -ErrorAction Stop
Lee Dailey'e bu şekilde kullanmayı -ErrorAction Stop
hatırladığınız için teşekkür ederim.
Cmdlet -ErrorAction Stop
Herhangi bir gelişmiş işlevde veya cmdlet'te belirtirseniz -ErrorAction Stop
, tüm Write-Error
deyimleri yürütmeyi durduran veya tarafından catch
işlenebilen sonlandırıcı hatalara dönüştürür.
Start-Something -ErrorAction Stop
ErrorAction parametresi hakkında daha fazla bilgi için bkz. about_CommonParameters. Değişken hakkında $ErrorActionPreference
daha fazla bilgi için bkz . about_Preference_Variables.
Deneyin/Yakalayın
Özel durum işlemenin PowerShell'de (ve diğer birçok dilde) çalışmasının yolu, önce try
kodun bir bölümünü kullanmanız ve hata oluşturması durumunda bunu yapabilirsiniz catch
. Aşağıda hızlı bir örnek verilmiştir.
try
{
Start-Something
}
catch
{
Write-Output "Something threw an exception"
Write-Output $_
}
try
{
Start-Something -ErrorAction Stop
}
catch
{
Write-Output "Something threw an exception or used Write-Error"
Write-Output $_
}
Betik catch
yalnızca sonlandırıcı bir hata olduğunda çalışır. try
doğru yürütülürse, üzerinden catch
atlar. değişkenini kullanarak bloktaki catch
özel durum bilgilerine $_
erişebilirsiniz.
Deneyin/Son Olarak
Bazen bir hatayı işlemeniz gerekmez, ancak yine de bir özel durum oluşursa veya gerçekleşmezse yürütülecek bazı kodlar gerekir. Betik finally
tam olarak bunu yapar.
Şu örneğe göz atın:
$command = [System.Data.SqlClient.SqlCommand]::New(queryString, connection)
$command.Connection.Open()
$command.ExecuteNonQuery()
$command.Connection.Close()
Bir kaynağı her açtığınızda veya kaynağa bağlandığınızda, kaynağı kapatmanız gerekir. ExecuteNonQuery()
özel durum oluşturursa, bağlantı kapatılamaz. Bir bloğun içinde try/finally
aynı kod aşağıdadır.
$command = [System.Data.SqlClient.SqlCommand]::New(queryString, connection)
try
{
$command.Connection.Open()
$command.ExecuteNonQuery()
}
finally
{
$command.Connection.Close()
}
Bu örnekte, bir hata varsa bağlantı kapatılır. Hata yoksa da kapatılır. Betik finally
her seferinde çalışır.
Özel durumu yakalamadığınız için çağrı yığınına yayılmaya devam eder.
Try/Catch/Finally
ve birlikte kullanmak catch
finally
son derece geçerlidir. Çoğu zaman birini veya diğerini kullanırsınız, ancak her ikisini de kullandığınız senaryolar bulabilirsiniz.
$PSItem
Temel bilgileri aradan çıkardığımıza göre, biraz daha derine inebiliriz.
Bloğun catch
içinde, özel durumla ilgili ayrıntıları içeren türünde ErrorRecord
bir otomatik değişken ($PSItem
veya $_
) vardır. Bazı önemli özelliklere hızlı bir genel bakış aşağıda verilmiştir.
Bu örnekler için, içinde bu özel durumu oluşturmak için geçersiz bir yol ReadAllText
kullandım.
[System.IO.File]::ReadAllText( '\\test\no\filefound.log')
PSItem.ToString()
Bu size günlükte ve genel çıktıda kullanmak için en temiz iletiyi verir. ToString()
bir dizenin içine yerleştirilirse $PSItem
otomatik olarak çağrılır.
catch
{
Write-Output "Ran into an issue: $($PSItem.ToString())"
}
catch
{
Write-Output "Ran into an issue: $PSItem"
}
$PSItem.InvocationInfo
Bu özellik, özel durumun oluşturulduğu işlev veya betik hakkında PowerShell tarafından toplanan ek bilgileri içerir. InvocationInfo
Oluşturduğum örnek özel durumdan gelenler aşağıda verilmiştir.
PS> $PSItem.InvocationInfo | Format-List *
MyCommand : Get-Resource
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 5
OffsetInLine : 5
ScriptName : C:\blog\throwerror.ps1
Line : Get-Resource
PositionMessage : At C:\blog\throwerror.ps1:5 char:5
+ Get-Resource
+ ~~~~~~~~~~~~
PSScriptRoot : C:\blog
PSCommandPath : C:\blog\throwerror.ps1
InvocationName : Get-Resource
Buradaki önemli ayrıntılar, Line
kodun ScriptName
ve çağrının ScriptLineNumber
nerede başladığını gösterir.
$PSItem.ScriptStackTrace
Bu özellik, özel durumun oluşturulduğu koda sizi getiren işlev çağrılarının sırasını gösterir.
PS> $PSItem.ScriptStackTrace
at Get-Resource, C:\blog\throwerror.ps1: line 13
at Start-Something, C:\blog\throwerror.ps1: line 5
at <ScriptBlock>, C:\blog\throwerror.ps1: line 18
Yalnızca aynı betikteki işlevlere çağrı yapıyorum, ancak birden çok betik söz konusuysa bu çağrıları izler.
$PSItem.Exception
Bu, oluşan gerçek özel durumdur.
$PSItem.Exception.Message
Bu, özel durumu açıklayan ve sorun giderme sırasında iyi bir başlangıç noktası olan genel iletidir. Çoğu özel durumun varsayılan iletisi vardır, ancak özel durum oluştuğunda özel bir iletiye de ayarlanabilir.
PS> $PSItem.Exception.Message
Exception calling "ReadAllText" with "1" argument(s): "The network path was not found."
Bu aynı zamanda, üzerinde bir ayar yoksa çağrılırken $PSItem.ToString()
döndürülen iletidir ErrorRecord
.
$PSItem.Exception.InnerException
Özel durumlar iç özel durumlar içerebilir. Genellikle çağırdığınız kod bir özel durum yakalar ve farklı bir özel durum oluşturur. Özgün özel durum, yeni özel durumun içine yerleştirilir.
PS> $PSItem.Exception.InnerExceptionMessage
The network path was not found.
Bunu daha sonra özel durumları yeniden oluşturma hakkında konuştuğumda tekrar ziyaret ederim.
$PSItem.Exception.StackTrace
Bu, StackTrace
özel durum için geçerlidir. Yukarıdakini ScriptStackTrace
gösterdim, ancak bu yönetilen koda yapılan çağrılar için.
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean
useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs,
String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32
bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean
checkHost)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean detectEncodingFromByteOrderMarks,
Int32 bufferSize, Boolean checkHost)
at System.IO.File.InternalReadAllText(String path, Encoding encoding, Boolean checkHost)
at CallSite.Target(Closure , CallSite , Type , String )
Bu yığın izlemesini yalnızca olay yönetilen koddan oluşturulduğunda alırsınız. Bu örnekte görebildiğimiz tek şey bu şekilde bir .NET framework işlevini doğrudan çağırıyorum. Genellikle bir yığın izlemesine baktığınızda kodunuzun nerede durup sistem çağrılarının başlayacağını ararsınız.
Özel durumlarla çalışma
Temel söz dizimi ve özel durum özelliklerinden daha fazla özel durum vardır.
Yazılan özel durumları yakalama
Yakaladığınız özel durumlar için seçmeli olabilirsiniz. Özel durumların bir türü vardır ve yakalamak istediğiniz özel durum türünü belirtebilirsiniz.
try
{
Start-Something -Path $path
}
catch [System.IO.FileNotFoundException]
{
Write-Output "Could not find $path"
}
catch [System.IO.IOException]
{
Write-Output "IO error with the file: $path"
}
Özel durum türü, özel durumunuzla eşleşen bir tane bulunana kadar her catch
blok için denetlenir.
Özel durumların diğer özel durumlardan devralabileceğini fark etmek önemlidir. Yukarıdaki örnekte öğesinden FileNotFoundException
IOException
devralınır. Yani eğer IOException
ilk olsaydı, onun yerine çağrılırdı. Birden çok eşleşme olsa bile yalnızca bir catch bloğu çağrılır.
bir olsaydı System.IO.PathTooLongException
, eşleşirdi IOException
ama eğer birimiz InsufficientMemoryException
olsaydı hiçbir şey onu yakalayamaz ve yığının dışına yayılırdı.
Aynı anda birden çok türü yakalama
Aynı catch
deyimle birden çok özel durum türünü yakalamak mümkündür.
try
{
Start-Something -Path $path -ErrorAction Stop
}
catch [System.IO.DirectoryNotFoundException],[System.IO.FileNotFoundException]
{
Write-Output "The path or file was not found: [$path]"
}
catch [System.IO.IOException]
{
Write-Output "IO error with the file: [$path]"
}
Bu eklemeyi önerdiğiniz için Redditor'a u/Sheppard_Ra
teşekkür ederiz.
Türü belirtilen özel durumlar oluşturma
PowerShell'de türü belirtilen özel durumlar oluşturabilirsiniz. Dizeyle çağırmak throw
yerine:
throw "Could not find: $path"
Aşağıdaki gibi bir özel durum hızlandırıcısı kullanın:
throw [System.IO.FileNotFoundException] "Could not find: $path"
Ancak, bu şekilde yaptığınızda bir ileti belirtmeniz gerekir.
Oluşturulacak özel durumun yeni bir örneğini de oluşturabilirsiniz. Sistemde tüm yerleşik özel durumlar için varsayılan iletiler olduğundan, bunu yaptığınızda ileti isteğe bağlıdır.
throw [System.IO.FileNotFoundException]::new()
throw [System.IO.FileNotFoundException]::new("Could not find path: $path")
PowerShell 5.0 veya üzerini kullanmıyorsanız eski New-Object
yaklaşımı kullanmanız gerekir.
throw (New-Object -TypeName System.IO.FileNotFoundException )
throw (New-Object -TypeName System.IO.FileNotFoundException -ArgumentList "Could not find path: $path")
Yazılan bir özel durum kullanarak, siz (veya diğerleri) önceki bölümde belirtildiği gibi türüne göre özel durumu yakalayabilirsiniz.
Yazma Hatası -Özel Durum
Bu tür özel durumları 'a Write-Error
ekleyebiliriz ve yine de catch
özel durum türüne göre hataları ekleyebiliriz. Aşağıdaki örneklerde like kullanın Write-Error
:
# with normal message
Write-Error -Message "Could not find path: $path" -Exception ([System.IO.FileNotFoundException]::new()) -ErrorAction Stop
# With message inside new exception
Write-Error -Exception ([System.IO.FileNotFoundException]::new("Could not find path: $path")) -ErrorAction Stop
# Pre PS 5.0
Write-Error -Exception ([System.IO.FileNotFoundException]"Could not find path: $path") -ErrorAction Stop
Write-Error -Message "Could not find path: $path" -Exception (New-Object -TypeName System.IO.FileNotFoundException) -ErrorAction Stop
Ardından şu şekilde yakalayabiliriz:
catch [System.IO.FileNotFoundException]
{
Write-Log $PSItem.ToString()
}
.NET özel durumlarının büyük listesi
Reddit r/PowerShell
topluluğunun yardımıyla bu gönderiyi tamamlayacak yüzlerce .NET özel durumu içeren bir ana liste derledim.
İlk olarak bu listede durumuma uygun olabilecek özel durumlar için arama yaptım. Temel System
ad alanında özel durumları kullanmayı denemelisiniz.
Özel durumlar nesnelerdir
Çok fazla türlenmiş özel durum kullanmaya başlarsanız, bunların nesne olduğunu unutmayın. Farklı özel durumların farklı oluşturucuları ve özellikleri vardır. için System.IO.FileNotFoundException
FileNotFoundException belgelerine bakarsak bir ileti ve dosya yolu geçirebileceğimizi görürüz.
[System.IO.FileNotFoundException]::new("Could not find file", $path)
Ve bu dosya yolunu kullanıma sunan bir FileName
özelliği vardır.
catch [System.IO.FileNotFoundException]
{
Write-Output $PSItem.Exception.FileName
}
Diğer oluşturucular ve nesne özellikleri için .NET belgelerine başvurmalısınız.
Özel durumu yeniden oluşturma
Bloğunuzda catch
throw
tek yapmanız gereken aynı özel durumsa, bunu yapmayın catch
. Yalnızca gerçekleştiğinde bazı eylemleri işlemeyi veya gerçekleştirmeyi planladığınız bir özel durum oluşturmanız gerekir catch
.
Bir özel durum üzerinde eylem gerçekleştirmek ancak aşağı akışın bununla başa çıkabilmesi için özel durumu yeniden atmak istediğiniz zamanlar vardır. Bir ileti yazabilir veya sorunu keşfettiğiniz yere yakın bir yerde günlüğe kaydedebilir, ancak sorunu yığının daha yukarısına doğru işleyebiliriz.
catch
{
Write-Log $PSItem.ToString()
throw $PSItem
}
İlginç bir şekilde içinden çağrısı throw
catch
yapabilir ve geçerli özel durumu yeniden oluşturur.
catch
{
Write-Log $PSItem.ToString()
throw
}
Kaynak betik ve satır numarası gibi özgün yürütme bilgilerini korumak için özel durumu yeniden atmak istiyoruz. Bu noktada yeni bir özel durum oluşturursak, özel durumun başladığı yeri gizler.
Yeni bir özel durum yeniden oluşturma
Bir özel durum yakalarsanız ancak farklı bir özel durum oluşturmak istiyorsanız, özgün özel durumu yenisinin içine yerleştirmeniz gerekir. Bu, yığının alt kısmındaki birinin buna olarak erişmesine $PSItem.Exception.InnerException
olanak tanır.
catch
{
throw [System.MissingFieldException]::new('Could not access field',$PSItem.Exception)
}
$PSCmdlet.ThrowTerminatingError()
Ham özel durumlar için kullanma throw
konusunda sevmediğim tek şey, hata iletisinin deyimini throw
işaret ettiği ve sorunun bulunduğu yerin çizgi olduğunu gösterdiğidir.
Unable to find the specified file.
At line:31 char:9
+ throw [System.IO.FileNotFoundException]::new()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], FileNotFoundException
+ FullyQualifiedErrorId : Unable to find the specified file.
31. satırda aradığım throw
için betiğimin bozuk olduğunu belirten hata iletisine sahip olmak, betiğinizin kullanıcılarının görmesi için kötü bir iletidir. Onlara yararlı bir şey söylemiyor.
Dexter Dhami bunu düzeltmek için kullanabileceğimi ThrowTerminatingError()
belirtmiş.
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
([System.IO.FileNotFoundException]"Could not find $Path"),
'My.ID',
[System.Management.Automation.ErrorCategory]::OpenError,
$MyObject
)
)
bunun adlı Get-Resource
bir işlevin ThrowTerminatingError()
içinde çağrıldığını varsayarsak, göreceğimiz hata budur.
Get-Resource : Could not find C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework\.NETPortable\v4.6\System.IO.xml
At line:6 char:5
+ Get-Resource -Path $Path
+ ~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Get-Resource], FileNotFoundException
+ FullyQualifiedErrorId : My.ID,Get-Resource
Sorunun kaynağı olarak işlevi nasıl işaret Get-Resource
ettiğinizi görüyor musunuz? Bu, kullanıcıya yararlı bir şey söyler.
bir $PSItem
olduğundan ErrorRecord
, yeniden atmak için bu yöntemi de kullanabiliriz ThrowTerminatingError
.
catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}
Bu, hatanın kaynağını Cmdlet'e değiştirir ve işlevinizin iç öğelerini Cmdlet'inizin kullanıcılarından gizler.
Deneyin sonlandırıcı hatalar oluşturabilir
Kirk Munro bazı özel durumların yalnızca bir try/catch
blok içinde yürütülürken hataları sonlandırdığını belirtir. Bana verdiği ve sıfıra bölme çalışma zamanı özel durumu oluşturan örnek aşağıda verilmiştir.
function Start-Something { 1/(1-1) }
Ardından hatayı oluşturup iletinin çıkışını almaya devam etmek için bu şekilde çağırın.
&{ Start-Something; Write-Output "We did it. Send Email" }
Ancak aynı kodu içine try/catch
yerleştirerek başka bir şey olduğunu görürüz.
try
{
&{ Start-Something; Write-Output "We did it. Send Email" }
}
catch
{
Write-Output "Notify Admin to fix error and send email"
}
Hatanın sonlandırıcı bir hataya dönüştüğünü ve ilk iletinin çıkışını almadığını görüyoruz. Bu kodla ilgili sevmediğim şey, bu kodu bir işlevde kullanabileceğiniz ve birisi kullanıyorsa try/catch
farklı davranabilmesidir.
Bu konuda kendimle ilgili sorunlarla karşılaşmıyordum ama farkında olmak köşeye sıkışan bir durum.
try/catch içinde $PSCmdlet.ThrowTerminatingError()
Bir nüans $PSCmdlet.ThrowTerminatingError()
, Cmdlet'inizde sonlandırıcı bir hata oluşturması ancak Cmdlet'inizden ayrıldıktan sonra sonlandırılmayan bir hataya dönüşmesidir. Bu, hatanın nasıl işleneceğini belirlemek için işlevinizin çağıranın yükünü bırakır. kullanarak veya içinden çağırarak -ErrorAction Stop
bunu sonlandırıcı bir try{...}catch{...}
hataya dönüştürebilirler.
Genel işlev şablonları
Kirk Munro ile yaptığım konuşmada yaptığım son bir yol, her begin
process
end
birini çevreleyip tüm gelişmiş işlevlerini engellemesiydi.try{...}catch{...}
Bu genel catch bloklarında, işlevlerini bırakan tüm özel durumlarla başa çıkmak için kullanan $PSCmdlet.ThrowTerminatingError($PSItem)
tek bir satırı vardır.
function Start-Something
{
[CmdletBinding()]
param()
process
{
try
{
...
}
catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}
}
}
Her şey işlevlerindeki bir try
deyimde olduğundan, her şey tutarlı bir şekilde hareket eder. Bu, son kullanıcıya dahili kodu oluşturulan hatadan gizleyen temiz hatalar da verir.
Tuzak
İstisnaların yönüne try/catch
odaklandım. Ama bu işi bitirmeden önce bahsetmem gereken eski bir özellik var.
, trap
bu kapsamda gerçekleşen tüm özel durumları yakalamak için bir betik veya işleve yerleştirilir. Bir özel durum oluştuğunda içindeki trap
kod yürütülür ve normal kod devam eder. Birden çok özel durum oluşursa, tuzak tekrar tekrar çağrılır.
trap
{
Write-Log $PSItem.ToString()
}
throw [System.Exception]::new('first')
throw [System.Exception]::new('second')
throw [System.Exception]::new('third')
Kişisel olarak bu yaklaşımı hiç benimsemedim ama yönetici veya denetleyici betiklerinde özel durumları ve tüm özel durumları günlüğe kaydeden ve sonra da yürütmeye devam eden değeri görebiliyorum.
Kapanış notları
Betiklerinize uygun özel durum işleme eklemek, bunları daha kararlı hale getirmekle kalmaz, aynı zamanda bu özel durumlarla ilgili sorunları gidermenizi de kolaylaştırır.
Konuşmak throw
için çok zaman harcadım çünkü özel durum işleme hakkında konuşurken temel bir kavramdır. PowerShell, kullanabileceğiniz throw
tüm durumları işleyen bir Write-Error
de verdi. Bu nedenle, bunu okuduktan sonra kullanmanız throw
gerektiğini düşünmeyin.
Bu ayrıntıda özel durum işleme hakkında yazmaya zaman ayırdığıma göre, kodumda hata oluşturmak için kullanmaya Write-Error -Stop
geçeceğim. Ayrıca Kirk'ün tavsiyesini alacağım ve her işlev için özel durum işleyicimi yapacağım ThrowTerminatingError
.
PowerShell