Powershell: Catch/try/finally: inny blok catch dla różnych rodzajów exception

18-lis-2016

Obsługę  błędów można realizować w powershell korzystając z intrukcji try/catch/finally. Często do obsługi błędu wystarczy konstrukcja:

try
{
    GWMI Win32_bios -ComputerName 'blablacomp'-ea Stop
}
catch
{
    echo "general exception"
}

Ale zdarza się, że z jakiegoś powodu w bloku try znajduje się kilka instrukcji, które mogły spowodować błąd i w zależności od tego jaki błąd został napotkany będzie należało wykonać inną czynność w bloku catch.

Oto przykład takiej konstrukcji:

try
{
   del c:\temp\blablabla.txt -ea stop
   GWMI Win32_bios -ComputerName 'blablacomp'-ea Stop
}
catch [System.Runtime.InteropServices.COMException]
{
   echo "com exception"
}
catch [System.Management.Automation.ItemNotFoundException]
{
   echo "file not found exception"
}
catch
{
   echo "general exception"
}

Tym razem, jeśli dojdzie do błędu, to w zależności od tego jaki to błąd, zostanie uruchomiona inna sekcja catch. Nazwy w nawiasach kwadratowych są nazwami typów różncyh rodzajów wyjątków zgłaszanych przez  uruchamiane w bloku try polecenia. Jeśli doszło by do niewymienionego tutaj błedu to wykonany zostanie standardowy blok catch

Pozostaje tylko jeden duży problem. Skąd u licha wziąć wykaz możliwych do spotkania exception? Szczerze mówiąc nie wiem… może nawet nie ma miejsca w którym wszystkie byłyby spisane, ale jeśli już masz jakiś błąd to na pewno uda ci się ustalić jaki to exception. Zastosuj poniższą metodę:

Najpierw sprowokuj błąd, np tak:

gwmi win32_bios -ComputerName 'asf'

Na ekranie wyświetlił się jakiś komunikat o błędzie ale ciągle nie ma tam poszukiwanej informacji, za to jest ona w zmiennej $Error[0]. Dlatego w kolejnym kroku przejrzyj właściwości tej zmiennej, np. tak:

$Error[0] | fl * -Force

Na ekranie zobaczysz coś podobnego:

writeErrorStream : True
PSMessageDetails :
Exception : System.Runtime.InteropServices.COMException (0x800706BA): The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
at System.Management.ThreadDispatch.Start()
at System.Management.ManagementScope.Initialize()
at System.Management.ManagementObjectSearcher.Initialize()
at System.Management.ManagementObjectSearcher.Get()
at Microsoft.PowerShell.Commands.GetWmiObjectCommand.BeginProcessing()
TargetObject :
CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
ErrorDetails :
InvocationInfo : System.Management.Automation.InvocationInfo
ScriptStackTrace : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {0, 0}

Podkreślona część to właśnie informacja o rodzaju zgłoszonego wyjątku Oto kolejny przykład:

del c:\ajdahsdhaO

$Error[0] | fl * -Force

i wynik:

writeErrorStream : True
PSMessageDetails :
Exception : System.Management.Automation.ItemNotFoundException: Cannot find path 'C:\ajdahsdhaO’ because it does not exist.
at System.Management.Automation.LocationGlobber.ExpandMshGlobPath(String path, Boolean allowNonexistingPaths, PSDriveInfo drive,
ContainerCmdletProvider provider, CmdletProviderContext context)
at System.Management.Automation.LocationGlobber.ResolveDriveQualifiedPath(String path, CmdletProviderContext context, Boolean
allowNonexistingPaths, CmdletProvider& providerInstance)
at System.Management.Automation.LocationGlobber.GetGlobbedMonadPathsFromMonadPath(String path, Boolean allowNonexistingPaths,
CmdletProviderContext context, CmdletProvider& providerInstance)
at Microsoft.PowerShell.Commands.RemoveItemCommand.ProcessRecord()
TargetObject : C:\ajdahsdhaO
CategoryInfo : ObjectNotFound: (C:\ajdahsdhaO:String) [Remove-Item], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
ErrorDetails :
InvocationInfo : System.Management.Automation.InvocationInfo
ScriptStackTrace : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {0, 1}

Znasz lepszą metodę? Podziel się z nami!

Komentarze są wyłączone

Autor: Rafał Kraik