powershell - tutorial - Try/catch no parece tener un efecto
powershell tutorial (6)
Agregar "-EA Stop" resolvió esto para mí.
Soy nuevo en powershell, y estoy tratando de agregar el manejo de errores a través de declaraciones try / catch, pero parece que en realidad no captan el error. Esto es powershell v2 CP3.
$objComputer = $objResult.Properties;
$strComputerName = $objComputer.name
write-host "Checking machine: " $strComputerName
try
{
$colItems = get-wmiobject -class "Win32_PhysicalMemory" -namespace "root/CIMV2" -computername $strComputerName -Credential $credentials
foreach ($objItem in $colItems)
{
write-host "Bank Label: " $objItem.BankLabel
write-host "Capacity: " ($objItem.Capacity / 1024 / 1024)
write-host "Caption: " $objItem.Caption
write-host "Creation Class Name: " $objItem.CreationClassName
write-host
}
}
Catch
{
write-host "Failed to get data from machine (Error:" $_.Exception.Message ")"
write-host
}
finally
{ }
Cuando falla en contactar una máquina específica, la recibo en la consola, y no en mi mensaje de captura limpia:
Get-WmiObject : The RPC server is
unavailable. (Exception from HRESULT:
0x800706BA) At Z:/7.0 Intern
Programvare/Powershell/Get memory of
all computers in AD.ps1:25 char:34
+ $colItems = get-wmiobject <<<< -class "Win32_PhysicalMemory"
-namespace "root/CIMV2" -computername $strComputerName -Credential
$credentials
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject],
COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Esta es mi solución. Cuando Set-Location falla, arroja un error que no termina y que no es visto por el bloque catch. Agregar -ErrorAction Stop es la forma más fácil de evitar esto.
try {
Set-Location "$YourPath" -ErrorAction Stop;
} catch {
Write-Host "Exception has been caught";
}
Pude duplicar tu resultado al intentar ejecutar una consulta WMI remota. La excepción lanzada no es capturada por Try / Catch, ni una trampa la atrapará, ya que no es un "error de terminación". En PowerShell, hay errores de terminación y no terminantes. Parece que Try / Catch / Finally y Trap solo funcionan con errores de terminación.
Está registrado en la variable automática de $ error y puede probar este tipo de errores que no terminan mirando los $? variable automática, que le permitirá saber si la última operación tuvo éxito ($ true) o falló ($ false).
A partir de la aparición del error generado, parece que el error se devuelve y no se envuelve en una excepción atrapable. A continuación se muestra un rastro del error generado.
PS C:/scripts/PowerShell> Trace-Command -Name errorrecord -Expression {Get-WmiObject win32_bios -ComputerName HostThatIsNotThere} -PSHost
DEBUG: InternalCommand Information: 0 : Constructor Enter Ctor
Microsoft.PowerShell.Commands.GetWmiObjectCommand: 25857563
DEBUG: InternalCommand Information: 0 : Constructor Leave Ctor
Microsoft.PowerShell.Commands.GetWmiObjectCommand: 25857563
DEBUG: ErrorRecord Information: 0 : Constructor Enter Ctor
System.Management.Automation.ErrorRecord: 19621801 exception =
System.Runtime.InteropServices.COMException (0x800706BA): The RPC
server is unavailable. (Exception from HRESULT: 0x800706BA)
at
System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at System.Management.ManagementScope.InitializeGuts(Object o)
at System.Management.ManagementScope.Initialize()
at System.Management.ManagementObjectSearcher.Initialize()
at System.Management.ManagementObjectSearcher.Get()
at Microsoft.PowerShell.Commands.GetWmiObjectCommand.BeginProcessing()
errorId = GetWMICOMException errorCategory = InvalidOperation
targetObject =
DEBUG: ErrorRecord Information: 0 : Constructor Leave Ctor
System.Management.Automation.ErrorRecord: 19621801
Un trabajo para su código podría ser:
try
{
$colItems = get-wmiobject -class "Win32_PhysicalMemory" -namespace "root/CIMV2" -computername $strComputerName -Credential $credentials
if ($?)
{
foreach ($objItem in $colItems)
{
write-host "Bank Label: " $objItem.BankLabel
write-host "Capacity: " ($objItem.Capacity / 1024 / 1024)
write-host "Caption: " $objItem.Caption
write-host "Creation Class Name: " $objItem.CreationClassName
write-host
}
}
else
{
throw $error[0].Exception
}
Si desea que try / catch funcione para todos los errores (no solo para los errores de terminación), puede finalizar manualmente todos los errores configurando ErrorActionPreference.
try {
$ErrorActionPreference = "Stop"; #Make all errors terminating
get-item filethatdoesntexist; # normally non-terminating
write-host "You won''t hit me";
} catch{
Write-Host "Caught the exception";
Write-Host $Error[0].Exception;
}finally{
$ErrorActionPreference = "Continue"; #Reset the error action pref to default
}
Alternativamente ... puede hacer su propia función catchcatch que acepte scriptblocks para que sus try catch calls no sean tan kludge. Tengo el mío verdadero / falso en caso de que necesite verificar si hubo un error ... pero no tiene que ser así. Además, el registro de excepciones es opcional, y se puede tener en cuenta en la captura, pero siempre me encontré llamando a la función de registro en el bloque catch, así que lo agregué a la función try catch.
function log([System.String] $text){write-host $text;}
function logException{
log "Logging current exception.";
log $Error[0].Exception;
}
function mytrycatch ([System.Management.Automation.ScriptBlock] $try,
[System.Management.Automation.ScriptBlock] $catch,
[System.Management.Automation.ScriptBlock] $finally = $({})){
# Make all errors terminating exceptions.
$ErrorActionPreference = "Stop";
# Set the trap
trap [System.Exception]{
# Log the exception.
logException;
# Execute the catch statement
& $catch;
# Execute the finally statement
& $finally
# There was an exception, return false
return $false;
}
# Execute the scriptblock
& $try;
# Execute the finally statement
& $finally
# The following statement was hit.. so there were no errors with the scriptblock
return $true;
}
#execute your own try catch
mytrycatch {
gi filethatdoesnotexist; #normally non-terminating
write-host "You won''t hit me."
} {
Write-Host "Caught the exception";
}
También es posible establecer la preferencia de acción de error en cmdlets individuales, no solo para todo el script. Esto se hace usando el parámetro ErrorAction (alisa EA) que está disponible en todos los cmdlets.
Ejemplo
try
{
Write-Host $ErrorActionPreference; #Check setting for ErrorAction - the default is normally Continue
get-item filethatdoesntexist; # Normally generates non-terminating exception so not caught
write-host "You will hit me as exception from line above is non-terminating";
get-item filethatdoesntexist -ErrorAction Stop; #Now ErrorAction parameter with value Stop causes exception to be caught
write-host "you won''t reach me as exception is now caught";
}
catch
{
Write-Host "Caught the exception";
Write-Host $Error[0].Exception;
}
Editar: como se indica en los comentarios, la siguiente solución se aplica solo a PowerShell V1.
Vea esta publicación en el blog sobre "Aventuras técnicas de Adam Weigert" para obtener detalles sobre cómo implementar esto.
Ejemplo de uso (copiar / pegar desde el blog de Adam Weigert):
Try {
echo " ::Do some work..."
echo " ::Try divide by zero: $(0/0)"
} -Catch {
echo " ::Cannot handle the error (will rethrow): $_"
#throw $_
} -Finally {
echo " ::Cleanup resources..."
}
De lo contrario, tendrá que usar la captura de excepciones .