Magic Quadrant™ para la gestión de acceso privilegiado 2025: Netwrix reconocida por cuarto año consecutivo. Descarga el informe.

Plataforma
Centro de recursosBlog
Guía de manejo de errores con PowerShell Try-Catch

Guía de manejo de errores con PowerShell Try-Catch

Mar 9, 2025

El manejo de errores en PowerShell utiliza bloques Try-Catch-Finally para gestionar errores terminantes y no terminantes, asegurando que los scripts permanezcan confiables en ejecución desatendida. Try encierra el código de riesgo, Catch responde a excepciones y Finally limpia recursos. Con opciones como -ErrorAction, $ErrorActionPreference, y $Error, los administradores pueden imponer un manejo estricto, capturar mensajes de error detallados y automatizar la recuperación. Este enfoque reduce el tiempo de inactividad, previene la pérdida de datos y permite una escritura de scripts resistente a gran escala.

Introducción al manejo de errores en PowerShell

Muchos scripts de PowerShell están diseñados para ejecutarse sin supervisión, por lo que es esencial asegurarse de que puedan manejar los errores de manera eficiente. Un manejo adecuado de errores ayuda a prevenir una amplia variedad de problemas, desde operaciones incompletas y tiempo de inactividad del sistema hasta pérdida de datos. El manejo de errores debe tener en cuenta tanto los errores terminales, que detienen la ejecución del script, como los errores no terminales, que permiten que el script continúe ejecutándose pero pueden afectar el resultado.

Uno de los mecanismos más útiles para el manejo de errores en PowerShell es el bloque Try-Catch-Finally. El bloque Try contiene código que podría generar una excepción. Si eso sucede, el control se transfiere al bloque Catch, que maneja el error tomando medidas como omitir un archivo problemático o una entrada inválida, así como registrar el evento. El bloque Finally siempre se ejecuta, realizando tareas de limpieza como cerrar archivos, liberar recursos o registrar información. Por ejemplo, crear mensajes de error detallados para Try Catch en PowerShell puede permitirte tomar las acciones apropiadas para resolver los problemas.

Este documento ofrece una inmersión profunda en los bloques Try-Catch-Finally. A lo largo del camino, también cubriremos algunos otros métodos de manejo de errores en PowerShell, incluyendo el uso del parámetro ErrorAction para controlar cómo los cmdlets responden a los errores y utilizando la variable $Error para almacenar el historial de errores.

¿Qué son los errores en PowerShell?

Los errores son eventos que pueden afectar el flujo normal de ejecución de un script o detenerlo por completo. Las causas comunes de errores incluyen sintaxis incorrecta, archivos faltantes, permisos insuficientes o recursos no disponibles. Hay dos tipos principales de errores, errores terminales y errores no terminales.

Errores Terminales: Errores Críticos que Detienen el Script

Los errores terminales detienen inmediatamente la ejecución del script a menos que se manejen adecuadamente. Estos errores ocurren cuando PowerShell se encuentra con un problema del que no puede recuperarse, como un error de sintaxis, llamar a una variable o archivo que no existe, o falta de permisos suficientes para realizar la operación solicitada.

Por ejemplo, el script a continuación intenta obtener el archivo users.txt:

      Get-Content C:\users.txt | Get-ADUser -Properties name | Select-Object -Property SamAccountName,name
      

Si este archivo no existe en la ubicación especificada o la cuenta que ejecuta el script no tiene permisos para acceder a él, el script generará un error terminal, deteniendo la operación del script como se muestra aquí:

Image

Errores no terminales: Errores que permiten que el script continúe

Los errores no terminales en PowerShell son errores que no detienen la ejecución del script. Estos errores son comúnmente generados por cmdlets que intentan procesar múltiples objetos, donde un fallo no necesariamente detiene todo el script.

Por ejemplo, supongamos que ejecutamos el script utilizado en el ejemplo anterior pero ahora el archivo sí existe y tenemos permisos para acceder a él. Sin embargo, no tenemos conectividad con un controlador de dominio. En este caso, el primer comando se ejecutará y obtendrá el contenido del archivo. No obstante, el siguiente comando fallará, generando errores no terminales para cada uno de los tres objetos en el archivo.

Image

Ahora supongamos que se restaura la conectividad del controlador de dominio, pero un objeto en el archivo tiene un nombre de usuario inválido. Ejecutar el script generará el error no terminante mostrado a continuación para el objeto, pero los otros objetos serán procesados por el script.

Image

Dónde se almacenan los errores: la variable $Error

$Error es un arreglo automático que almacena los errores recientes encontrados durante la ejecución del script, lo que lo hace muy útil para depurar y solucionar problemas del script. El error más reciente se almacena en el índice [0].

Por ejemplo, cuando el siguiente script intenta buscar un archivo inexistente, recupera el error resultante de $Error y lo muestra con un mensaje amigable:

      # trying to get a file which doesn't exist, and an error is generated.

Get-Item "C:\file44.txt"

# Display a message along with the last error.

Write-Host "Oops! Something went wrong Here's the error: $($Error[0])"
      
Image

Comprender los bloques Try, Catch y Finally

Una buena manera de manejar los errores suavemente es implementar bloques de Try-Catch-Finally.

¿Qué es Active Directory?

Descargar eBook


Try Block: Donde reside el código potencialmente propenso a errores

El bloque Try encierra el código que podría producir un error. Por ejemplo, el siguiente script está diseñado para detener el proceso del Notepad. El bloque Try detendrá ese proceso si está en ejecución, pero si no está en ejecución, la ejecución saltará al bloque Catch evitando que el script se bloquee.

      try {

    # Attempt to stop a process that may not be running

    Stop-Process -Name "Notepad" -ErrorAction Stop

    # If no error occurs, this line will execute

    Write-Host "Notepad process stopped successfully."

}

catch {

    # Handle the error gracefully

    Write-Host "Oops! Could not stop the process. Error: $($_.Exception.Message)"

}
      
Image

Bloque Catch: Manejando errores cuando ocurren

El bloque Catch se utiliza para manejar las excepciones que ocurren en el bloque Try. En el siguiente ejemplo de PowerShell Try Catch, el script solicita al usuario que ingrese un número, divide 10 por ese número e imprime el resultado. Sin embargo, si el número ingresado es 0, el intento de división resultará en un error, ya que no es posible dividir por cero. En ese caso, el bloque Catch se ejecutará e imprimirá un mensaje de error en lugar de un número.

      try {

    $number = [int](Read-Host "Enter a number")

    Write-Output "Result: $(10 / $number)"

}

catch {

    Write-Output "Error: Invalid input or division by zero!"

}

finally {

    Write-Output "Program execution completed."

}
      
Image

Bloque Finally: Código que siempre se ejecuta, haya o no un error

El bloque Finally siempre se ejecutará independientemente de si se lanzó una excepción.

For instance, the following script defines an array with just three elements but attempts to print the fifth element; this exception is handled in the Catch block, which prints an error. However, the Finally block is also executed, so an additional message is printed.

      try {

    # Define an array

    $numbers = @(1, 2, 3)

    # Access an invalid index using a .NET method that throws an exception

    $value = $numbers.GetValue(5) 

    Write-Host "Value: $value"

}

catch [System.IndexOutOfRangeException] {

    # Handle the specific exception

    Write-Host "Error: Index out of range exception caught."

}

finally {

    # This block always executes

    Write-Host "Execution completed."

}
      
Image

Ejemplo avanzado: Uso de múltiples bloques Catch para diferentes tipos de excepciones

Un script puede incluir múltiples bloques de Catch para manejar diferentes tipos de excepciones, permitiendo un manejo de errores más granular. De hecho, el marco de trabajo .Net proporciona un conjunto rico de tipos de mensajes de excepción de PowerShell Try Catch que incluyen los siguientes:

  • System.DivideByZeroException — Se produce al intentar dividir cualquier número por cero
  • System.FormatException — Surge al intentar convertir una entrada no numérica en un número
  • System.ArgumentNullException — Ocurre cuando un argumento pasado es nulo pero nunca debería ser nulo
  • System.IO.IOException — Se lanza cuando ocurre un error de E/S

Por ejemplo, el siguiente script solicita al usuario que ingrese dos números, los convierte a formato entero, divide el primer número por el segundo y muestra el resultado. El primer bloque Catch maneja la posibilidad de que la entrada del usuario no pueda convertirse en formato entero, y el segundo bloque Catch maneja la posibilidad de intentar dividir por cero.

      try {

    # Prompt user for first input

    $num1 = Read-Host "Enter the first number"

    $num1 = [int]$num1  # Convert to integer (may cause FormatException)

    # Prompt user for second input

    $num2 = Read-Host "Enter the second number"

    $num2 = [int]$num2  # Convert to integer (may cause FormatException)

    # Perform division (may cause DivideByZeroException)

    $result = $num1 / $num2

    # Print result

    Write-Host "Result: $result"

}

catch [System.FormatException] {

    # Handling invalid input error

    Write-Host "Error: Please enter only numeric values!"

}

catch [System.DivideByZeroException] {

    # Handling division by zero error

    Write-Host "Error: Cannot divide by zero!"

}

catch {

    # Handling unexpected errors

    Write-Host "An unexpected error occurred: $_"

}

finally {

    # Code that always runs

    Write-Host "Execution completed."

}
      
Image

Técnicas avanzadas de manejo de errores


Para crear scripts más robustos y mantenibles, considere usar las siguientes técnicas de manejo de errores en combinación con los bloques de PowerShell Try and Catch:

  • Utilice $ErrorActionPreference = “Stop” para asegurarse de que todos los errores se traten como terminales, lo que facilita su captura.
  • Utilice -ErrorAction Stop en comandos individuales para permitir un control más detallado sin afectar al script completo.
  • Utilice $_.Exception.Message y $PSItem para acceder a los detalles del error.

Capturando Excepciones Específicas


El siguiente script está diseñado para convertir la entrada del usuario en un entero y luego ejecutar un comando. El primer bloque Catch maneja la posibilidad de una entrada de usuario inválida, y el segundo maneja intentos de ejecutar un comando inválido. Si ocurre alguna excepción, el script imprime un mensaje personalizado.

      try {

    # Attempt to convert user input to an integer (may throw FormatException)

    $number = Read-Host "Enter a number"

    $number = [int]$number 

    # Try running a non-existent command (may throw CommandNotFoundException)

    NonExistent-Command 

}

catch [System.FormatException] {

    Write-Host "Error: Invalid input. Please enter a valid number."

}

catch [System.Management.Automation.CommandNotFoundException] {

    Write-Host "Error: Command not found. Please check the command name."

}

catch {

    Write-Host "An unexpected error occurred: $_"

}

finally {

    Write-Host "Execution completed."

}
      
Image

Usando $_.Exception.Message y $PSItem para acceder a los detalles del error

Para acceder a los detalles del error dentro de un bloque Catch, puedes utilizar las siguientes variables:

  • $_.Exception.Message proporciona un mensaje de error de PowerShell claro y fácil de usar, con solo la parte relevante del error.Try Catch
  • $PSItem contiene el objeto de error completo, incluyendo el tipo de error, la fuente y el seguimiento de la pila.

El siguiente script ilustra la diferencia en la salida proporcionada por estas variables:

      try {

    # Attempt to open a non-existent file

    Get-Content "C:\File1.txt" -ErrorAction Stop

}

catch {

    # Using $_.Exception.Message to get detailed error information

    Write-Host "Error occurred: $($_.Exception.Message)"

    # Using $PSItem (same as $_) to display full error details

    Write-Host "Full Error Details: $PSItem"

}

finally {

    Write-Host "Execution completed."

}
      
Image

Uso de declaraciones Trap

Una declaración de Trap define el código que se ejecuta cuando ocurre un error específico, independientemente de dónde en el script ocurra el error. Como resultado, proporciona un mecanismo para manejar errores en un nivel más alto (global) que los bloques individuales de PowerShell Try-Catch.

El siguiente script utiliza Try-Catch en PowerShell para manejar la posibilidad de un intento de división por cero. La instrucción Trap capturará cualquier otro error que pueda ocurrir, que en este caso es usar el cmdlet Get-Item con un archivo que no existe.

      # Global error handler using trap

trap {

    Write-Host "Global Error Handler (trap): $_"

    continue  # Allows the script to continue execution

}

function Test-TryCatch {

    try {

        Write-Host "Inside Try Block"

        1 / 0  # This will cause a division by zero error

        Write-Host "This line will not execute due to the error above."

    } catch {

        Write-Host "Caught in Try-Catch: $_"

    }

}

Write-Host "Before function call"

Test-TryCatch

Write-Host "After function call"

# Triggering another error outside try-catch to see if trap works

Write-Host "Triggering an error outside Try-Catch"

Get-Item "C:\NonExistentFile.txt" -ErrorAction Stop  # Force a terminating error

Write-Host "Script completed"
      

Manejo de errores no terminales en PowerShell

Catch blocks are designed to handle terminating errors; since non-terminating errors don’t stop script execution, they don’t trigger Catch block. However, we can convert non-terminating errors into terminating errors using the -ErrorAction Stop parameter. This parameter forces the script to treat non-terminating error as terminating errors, which will allow Catch blocks to handle them appropriately.

Supongamos que ejecutamos el siguiente script pero la carpeta a la que intenta acceder no existe. El bloque Try utiliza -ErrorAction Stop para convertir este error no terminante en un error terminante de modo que será manejado por el bloque Catch.

      $directoryPath = "C:\NonExistentFolder"

try {

    Write-Host "Checking if directory exists..."

    Get-ChildItem -Path $directoryPath -ErrorAction Stop  # Force a terminating error if the directory doesn't exist

    Write-Host "Directory found."

} catch {

    Write-Host "Error: The directory '$directoryPath' was not found."

}
      
Image

Mejores prácticas para usar Try-Catch en PowerShell

Para maximizar la claridad, eficiencia y mantenibilidad de su código, elabore cuidadosamente su bloque de manejo de errores. En particular, PowerShell Try-Catch debe usarse solo para excepciones genuinas. Limitar el código en el bloque Try a solo aquellas operaciones que podrían lanzar una excepción facilita la identificación de la fuente de las excepciones y la depuración del script. En otros casos, considere declaraciones if-else o switch.

Otras prácticas recomendadas clave incluyen las siguientes:

  • Asegúrate de que el código dentro del bloque Try siga el principio de responsabilidad única, lo que significa que cada fragmento de código realiza una tarea específica.
  • Utiliza bloques Catch separados para manejar diferentes tipos de excepciones.
  • Siempre incluya un bloque Finally para limpiar el código y liberar recursos.

El siguiente script ilustra algunas de estas mejores prácticas. Utiliza una declaración if con test-path para verificar si un archivo existe antes de intentar acceder a él. Si el archivo no existe, el error se muestra utilizando la declaración else. El bloque Try-Catch se utiliza solo para leer el contenido del archivo; si el script encuentra un error como falta de permisos, el bloque Catch manejará la excepción y mostrará un mensaje de error.

      # Define the path to the file

$filePath = "D:\NonExistentFile.txt"

# Check if the file exists

if (Test-Path -Path $filePath) {

    try {

        # Try to read the file contents

        $fileContents = Get-Content -Path $filePath -ErrorAction Stop

        Write-Host "File contents: $fileContents"

    }

    catch {

        # Handle any exceptions that occur while reading the file

        Write-Host "Error: Unable to read the file. Exception Message: $_"

    }

} else {

    # If the file does not exist, display an error message

    Write-Host "Error: The file does not exist."

}
      
Image

PowerShell Try-Catch y Continuación de Script

Usando instrucciones Continue

Cuando un script encuentra un error dentro de un bloque de Try-Catch, el comportamiento predeterminado es que el script maneje la excepción en el bloque de Catch y deje de ejecutarse. Sin embargo, hay escenarios en los que queremos continuar la ejecución después de manejar el error, como cuando se procesa un lote de archivos o se prueban conexiones a múltiples servidores.

Para asegurar que un único fallo no detenga toda la iteración, utilice una declaración de Continue. Por ejemplo, el siguiente script prueba la conexión de múltiples servidores; la declaración de Continue garantiza que la ejecución continuará incluso si ocurre un error en un servidor.

      # List of server names (replace with actual server names or IPs)

$servers = @("lhehost9", "lhehost11", "lhehost10")

foreach ($server in $servers) {

    try {

        Write-Host "Attempting to connect to $server..."

        # Simulating a remote connection (Replace with actual connection command)

        Test-Connection -ComputerName $server -Count 2 -ErrorAction Stop

        Write-Host "Successfully connected to $server.`n"

    } catch {

        Write-Host "Error: Failed to connect to $server. Skipping to next server...`n"

        continue  # Continue to the next server in the loop

    }

}

Write-Host "Script execution completed."
      
Image

Usando la variable $ErrorActionPreference

Otra forma de forzar la continuación de la ejecución de un script después de un error es usar la variable $ErrorActionPreference. Mientras que los bloques Try-Catch permiten un manejo de errores localizado, $ErrorActionPreference es una configuración global que controla la respuesta de PowerShell ante errores no terminales.

Ya vimos que puedes configurar $ErrorActionPreference en “Detener” para asegurar que todos los errores sean tratados como terminales y así facilitar su detección. Sin embargo, esta variable tiene configuraciones adicionales, incluyendo Continuar (el predeterminado), SilentlyContinue, Inquire y Ignore. Al elegir la configuración para esta variable, puedes definir cómo se gestionan los errores en todo el script.


Bloque Finally en PowerShell: Asegurando la Limpieza de Recursos

Como se mencionó anteriormente, el bloque Finally se ejecuta después de los bloques Try y Catch, independientemente de si ocurrió un error durante la ejecución del script. A menudo se utiliza para procesos de limpieza como cerrar archivos, terminar conexiones y liberar recursos.

Por ejemplo, el siguiente script abre un archivo y escribe “hello world” en él. Si ocurre un error, el bloque Catch imprimirá un mensaje. En cualquier caso, el bloque Finally se asegurará de que el flujo del archivo esté cerrado para evitar cualquier fuga de recursos.

      try {

    $filePath = "D:\Office\Backup\eventviewer_logs.txt"

    $fileStream = [System.IO.StreamWriter]::new($filePath)

    $fileStream.WriteLine("Hello, World!")

}

catch {

    Write-Host "An error occurred: $_"

}

finally {

    if ($fileStream) {

        $fileStream.Close()

        Write-Host "File stream closed successfully."

    }

}
      

Handling Multiple Errors in PowerShell
Variables that Store and Count Errors

PowerShell proporciona dos variables que son bastante útiles para auditar y depurar scripts que encuentran múltiples excepciones:

  • $Error mantiene un listado de los errores encontrados durante una sesión.
  • $Error.count proporciona el número total de errores registrados en la sesión actual.

Para un seguimiento preciso, puede ser necesario limpiar la lista de errores de vez en cuando durante una sesión. Usar $Error.clear() eliminará todos los errores almacenados.


Usando bloques Try-Catch anidados para manejar múltiples errores

El siguiente script incluye dos bloques anidados de Try-Catch para manejar dos errores potenciales diferentes, intentar dividir por cero e intentar acceder a un archivo inexistente:

      try {

    Write-Host "Starting First try block..."

    try {

        Write-Host "Attempting to divide by zero..."

        $result = 1 / 0  # This will cause a divide-by-zero exception

    }

    catch [System.DivideByZeroException] {

        Write-Host "Inner catch: Division by zero error occurred"

        throw "Re-throwing error to outer try block"

    }

    try {

        Write-Host "Accessing a file that doesn't exist..."

        Get-Content -Path "C:\File1.txt" -ErrorAction Stop

    }

    catch [System.IO.FileNotFoundException] {

        Write-Host "Inner catch: File not found error occurred"

    }

}

catch {

    Write-Host "Outer catch: Handling an error from inner blocks - $($_.Exception.Message)"

}

finally {

    Write-Host "Executing final block for cleanup..."

}
      
Image

Mensajes de error y depuración en PowerShell

Accediendo a información detallada de errores

Cuando ocurren errores durante la ejecución de un script, simplemente saber que ocurrió un error no es suficiente; necesitamos información detallada para diagnosticar y solucionar el problema. Como se mencionó anteriormente, la variable $Error mantiene un arreglo de registros de errores, con el error más reciente en $Error[0]. Las propiedades específicas del error incluyen Exception, CategoryInfo, InvocationInfo y ScriptStackTrace.

La propiedad ScriptStackTrace es invaluable porque proporciona el detalle de la pila de llamadas, mostrando la secuencia de llamadas a funciones y ubicaciones de scripts que condujeron al error. Para acceder a esta información detallada del error más reciente, utilice $Error[0].ScriptStackTrace.

Proporcionando mensajes de error personalizados

Mostrar mensajes de error significativos y fáciles de usar mejora la usabilidad y depuración del script. Los mensajes personalizados pueden proporcionar a los usuarios una idea de lo que salió mal y, a veces, ayudarles a corregir el error, como por ejemplo arreglando una ruta de archivo incorrecta, nombre de proceso incorrecto o permisos insuficientes.

Para mostrar mensajes personalizados, podemos usar Write-host o write-error en un bloque Catch. Incluye $_.Exception.message para proporcionar detalles adicionales.

Por ejemplo, cuando ocurre un error (división por cero) durante la ejecución del siguiente script, se imprime una notificación detallada en la consola y se envía por correo electrónico al administrador:

      $SMTPServer = "lvkex.ca.lo"

$SMTPPort = 587

$From = "aadministrator@ca.lo"

$To = "administrator@ca.lo"

$Subject = "PowerShell Script Error Alert"

try {

    Write-Host "Executing script..."  

    # Simulate an error (divide by zero)

    $result = 1 / 0 

}

catch {

    # Capture actual error message details

    $ErrorMessage = @"

An error occurred in the PowerShell script.

Message: $($_.Exception.Message)

Script: $($MyInvocation.ScriptName)

Line: $($_.InvocationInfo.ScriptLineNumber)

Date: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")

"@

    # Log error to console and send email

    Write-Host "An error occurred. Sending email notification..."

    Send-MailMessage -SmtpServer $SMTPServer -Port $SMTPPort -From $From -To $To -Subject $Subject -Body $ErrorMessage

}

}
      
Image

Casos de uso comunes para PowerShell Try-Catch

Updating User Profiles in Bulk While Handling Errors in Data Entry

Administrators often use a PowerShell to automatically update user information in Active Directory based on a csv file. Since the input file might contain invalid data, it’s important to use Try-Catch to handle and log errors.

The following script imports a csv file containing a list of users and iterates through it to update their descriptions in AD. It prints the results on the console and records any errors in a log file.

      # Define file paths

$CsvFile = "C:\Members (7).csv"

$LogFile = "C:\logs.txt"

# Import CSV

$Users = Import-Csv -Path $CsvFile

foreach ($User in $Users) {

    try {

        # Attempt to find the user in AD using CN or SamAccountName

        $ADUser = Get-ADUser -LDAPFilter "(cn=$($User.cn))" -Properties SamAccountName, Description -ErrorAction SilentlyContinue

        if ($ADUser -eq $null) {

            # Log missing users

            $ErrorMessage = "$(Get-Date): User '$($User.cn)' not found in AD."

            Write-Host $ErrorMessage

            Add-Content -Path $LogFile -Value $ErrorMessage

            continue  # Skip to the next user

        }

        # Define new description

        $NewDescription = "Test update on $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"

        # Update AD user description

        Set-ADUser -Identity $ADUser.SamAccountName -Description $NewDescription -ErrorAction Stop

        # Log success

        Write-Host "Updated: $($ADUser.SamAccountName) - New Description: $NewDescription"

    }

    catch {

        # Capture and log errors

        $ErrorMessage = "$(Get-Date): Error updating $($User.cn) ($($ADUser.SamAccountName)) - $($_.Exception.Message)"

        Write-Host $ErrorMessage

        Add-Content -Path $LogFile -Value $ErrorMessage

    }

}
      
Image

Handling Issues with Server or Network Connections

Try-Catch blocks are also useful for handling server and network connection issues. For example, the following script illustrates how to test the connection to a server, once with the correct name and once with incorrect name:

      # Define server details

$Server = "ada1.adatum.local"

$LogFile = "C:\log.txt"

try {

    # Check if the server responds to a ping

    $PingTest = Test-NetConnection -ComputerName $Server

    if (-not $PingTest.PingSucceeded) {

        throw "Server $Server is not responding to ping."

    }

    # Check RDP connectivity (port 3389)

    $RDPTest = Test-NetConnection -ComputerName $Server -Port 3389

    if (-not $RDPTest.TcpTestSucceeded) {

        throw "Server $Server is reachable but RDP port 3389 is not open."

    }

    # If both checks pass

    Write-Host "Server $Server is reachable, and RDP is accessible."

}

catch {

    # Capture and log the error

    $ErrorMessage = "$(Get-Date): Error connecting to server $Server - $($_.Exception.Message)"

    Write-Host $ErrorMessage

    Add-Content -Path $LogFile -Value $ErrorMessage

}
      
Image

Conclusion

Try-Catch-Finally blocks are an invaluable tool for handling errors in PowerShell scripts. By combining them with mechanisms such as the ErrorAction parameter and the $ErrorActionPreference and $Error variables, you can create robust scripts that run smoothly even when unexpected issues arise. As a result, you can automate tasks with confidence that you will not suffer problems like incomplete operation, system downtime or data loss.

FAQ

Why isn’t my PowerShell try-catch catching errors?


The most common reason try-catch blocks don’t work is that you’re dealing with non-terminating errors. PowerShell has two types of errors: terminating (which stop execution) and non-terminating (which display a message but continue running). Try-catch only catches terminating errors by default.

To catch non-terminating errors, add -ErrorAction Stop to the command inside your try block. This forces PowerShell to treat the error as terminating:

      try {
    Get-ChildItem "C:\NonExistent" -ErrorAction Stop
} catch {
    Write-Host "Caught the error!"
}
      

Without -ErrorAction Stop, the error message displays but your catch block never executes.

Another issue is scope-related. If you’re calling functions or external scripts from within your try block, errors from those might not bubble up correctly. Make sure the function or script you’re calling also uses proper error handling, or use $ErrorActionPreference = "Stop" at the beginning of your script to change the default behavior globally. Remember that changing the global preference affects all commands in your script, so use it carefully in production environments.


How do you fix PowerShell try-catch still showing error messages?

Even with proper try-catch implementation, you might still see error messages because PowerShell displays them before the catch block processes them. This happens with non-terminating errors that become terminating through -ErrorAction Stop. The error appears in the console, then gets caught by your handler.

To suppress the error display completely, use -ErrorAction SilentlyContinue combined with checking $? (the automatic success variable) or $Error[0] for the most recent error:

      Get-ChildItem "C:\NonExistent" -ErrorAction SilentlyContinue
if (!$?) {
    Write-Host "Command failed silently"
}
      

This approach gives you control over error detection without visible error messages.

For a cleaner solution, capture the error information in your catch block and decide how to handle it. Use $_.Exception.Message to get the error details, then log or display them according to your needs. This way, you control exactly what users see:

      try {
    Get-ChildItem "C:\NonExistent" -ErrorAction Stop
} catch {
    Write-Warning "Directory access failed: $($_.Exception.Message)"
}

      

This approach is especially important in enterprise environments where error messages need to be user-friendly and logged appropriately.

How do you handle PowerShell try-catch with non-terminating errors?

Non-terminating errors require special handling because they don’t trigger catch blocks by default. The most reliable approach is using -ErrorAction Stop on individual commands where you want to catch errors. This converts non-terminating errors to terminating ones that your try-catch can handle.

For functions that generate multiple non-terminating errors, consider setting $ErrorActionPreference = "Stop" at the function level, then reset it afterward:

      function Test-Function {
    $ErrorActionPreference = "Stop"
    try {
        # your commands here
    } catch {
        # error handling
    } finally {
        $ErrorActionPreference = "Continue"
    }
}
      

An alternative approach uses the -ErrorVariable parameter to capture errors without stopping execution. Run your command with -ErrorVariable myErrors -ErrorAction SilentlyContinue, then check if $myErrors has any content. This method lets you handle errors after command completion without interrupting the flow:

      Get-ChildItem "C:\*" -ErrorVariable problems -ErrorAction SilentlyContinue
if ($problems) {
    Write-Host "Found $($problems.Count) errors to review"
}
      

This pattern works well for bulk operations where you want to collect all problems before deciding how to respond.

What’s the difference between ErrorAction Stop and SilentlyContinue in try-catch?

ErrorAction Stop converts non-terminating errors into terminating errors that immediately halt execution and trigger your catch block. Use this when you want your try-catch to handle the error and you can’t continue if the command fails. It’s the most common choice for critical operations where failure should stop the process.

ErrorAction SilentlyContinue suppresses error messages and allows execution to continue, but errors don’t trigger catch blocks. The error still occurs and gets added to $Error, but no visible error message appears, and your script keeps running. This option is useful when you expect some operations to fail and want to handle them through conditional logic rather than exception handling.

The key difference in try-catch scenarios is control flow. With Stop, your catch block runs and you decide what happens next. With SilentlyContinue, you need to check success manually using $?, $Error, or -ErrorVariable. For security-focused operations, Stop provides better error visibility and handling, ensuring that access failures or security violations don’t go unnoticed. In enterprise environments, explicit error handling through try-catch with ErrorAction Stop creates better audit trails and more predictable script behavior.


How do you use try-catch with PowerShell loops and continue execution?

In loops, try-catch behavior depends on where the error occurs and what you want to happen next. To continue processing remaining items after an error, place the try-catch inside the loop and use continue in the catch block:

      foreach ($item in $items) {
    try {
        Process-Item $item -ErrorAction Stop
    } catch {
        Write-Warning "Failed to process $item"
        continue
    }
}
      

This skips the failed item and moves to the next one.

If you want to retry failed operations, combine try-catch with a retry counter:

      foreach ($item in $items) {
    $retries = 0
    do {
        try {
            Process-Item $item -ErrorAction Stop
            break
        } catch {
            $retries++
            if ($retries -ge 3) {
                Write-Error "Failed after 3 attempts: $item"
                break
            }
            Start-Sleep 1
        }
    } while ($retries -lt 3)
}

      

This pattern is valuable for network operations or resource-intensive tasks that might fail temporarily.

For collecting both successes and failures, use arrays to track results:

      $successful = @()
$failed = @()
foreach ($item in $items) {
    try {
        Process-Item $item -ErrorAction Stop
        $successful += $item
    } catch {
        $failed += @{Item=$item; Error=$_.Exception.Message}
    }
}
      

This approach provides complete visibility into bulk operations, which is essential for data processing, user management, or system administration tasks where you need to report on both successes and failures to stakeholders.

Compartir en

Aprende más

Acerca del autor

Asset Not Found

Tyler Reese

VP de Gestión de Producto, CISSP

Con más de dos décadas en la industria de la seguridad de software, Tyler Reese conoce íntimamente los desafíos de identidad y seguridad que evolucionan rápidamente a los que se enfrentan las empresas hoy en día. Actualmente, se desempeña como director de producto para el portafolio de Netwrix Identity and Access Management, donde sus responsabilidades incluyen evaluar tendencias del mercado, establecer la dirección de la línea de productos IAM y, finalmente, satisfacer las necesidades de los usuarios finales. Su experiencia profesional abarca desde la consultoría de IAM para empresas Fortune 500 hasta trabajar como arquitecto empresarial de una gran compañía de venta directa al consumidor. Actualmente posee la certificación CISSP.