2009-07-17 17 views
49

Soy nuevo en powershell, y estoy tratando de agregar el manejo de errores a través de las declaraciones try/catch, pero parece que en realidad no captan el error. Esto es powershell v2 CP3.Probar/captura no parece tener un efecto

$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 no logra contactar con una máquina específica, me sale esto en la consola, y no mi mensaje de toma 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

+0

@EKS He actualizado mi respuesta con una solución. –

Respuesta

54

Pude duplicar el 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 sin terminación 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 detectable. 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 alrededor de 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 
    } 
+0

Actualizado con una solución. –

+45

Usted puede hacer que los errores que no terminan sean lanzados usando: -ErrorAction "Stop" (o -EA "Stop" para abreviar) – JasonMArcher

+4

@JasonMArcher - ¡Lo tiene! Establecer $ ErrorActionPreference para 'Detener' como funcionaría también, pero tendría un efecto global. –

1

Editar: Como se indica en el comentarios, la siguiente solución se aplica solo a PowerShell V1.

Consulte this blog post on "Technical Adventures of 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..." 
} 

lo contrario tendrá que utilizar exception trapping.

+2

http://blogs.msdn.com/powershell/archive/2009/06/17/traps-vs-try-catch.aspx Pr esto debería existir en V2. – EKS

+1

Try/Catch/Finally no existe en V1 de PowerShell, pero está en V2. –

+1

Ah, por supuesto, mi error. – bernhof

48

Si desea try/catch para trabajar por todos los errores (no sólo los errores de terminación) se puede hacer de forma manual todos los errores que termina configurando la 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 ... usted puede hacer su propia función TryCatch que acepte scriptblocks para que sus llamadas intento de captura no son 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"; 
    } 
+0

Intentando usar ":: Try divide by zero: $ (0/0)" (y no usa get-item filethatdoesntexist;). Entonces no capta esa excepción – Kiquenet

12

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; 
} 
4

agregó que "-EA Stop" resolvieron este para mí.

2

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"; 
} 
Cuestiones relacionadas