Manejo de errores terminantes en PowerShell
Abstract
Al terminar esta lección podrás controlar el flujo con errores terminantes en
PowerShell: promover fallos con ,
capturarlos con -ErrorAction Stop -ErrorAction Stop /try try /
catch catch y devolver salida estructurada en lugar de
texto suelto. Nos centraremos en errores terminantes; los errores
no terminantes aparecerán solo como contraste y los estudiaremos en detalle más
adelante, cuando entremos en el pipeline.
finally finally
También aprenderás un patrón seguro para ejecutar comandos externos: resolver el binario real, ejecutarlo de forma inequívoca, capturar su resultado y elevar fallos con contexto cuando corresponda, para evitar scripts frágiles o dependientes del entorno. El ejercicio final consolida estas ideas implementando un fallback simple entre herramientas, priorizando capacidades reales por sobre suposiciones.
Errores terminantes
En un shell orientado a automatización y pipelines como PowerShell, no todos los fallos deben detener la ejecución. A menudo procesas muchos elementos (archivos, filas, recursos remotos) y necesitas registrar errores por ítem sin abortar el lote completo: estos son errores no terminantes.
En cambio, cuando una operación es crítica (por ejemplo, escribir o borrar datos),
conviene elevar el error a terminante para detener el flujo y manejarlo
explícitamente con /try try .
PowerShell modela esta distinción de forma explícita y proporciona mecanismos como
catch catch y
-ErrorAction -ErrorAction
para promover errores no terminantes a terminantes cuando el script lo requiere.
$ErrorActionPreference $ErrorActionPreference
Ojo: /try try
solo captura errores terminantes. Esto no es un detalle accidental: los errores
no terminantes están pensados para reportar problemas sin romper el flujo,
mientras que catch catch /try try está
diseñado para el control explícito del flujo ante fallos críticos. En última
instancia, PowerShell nos permite decidir si los errores
informan o definen el comportamiento del programa.
catch catch
Error no terminante
Un error no terminante registra la falla pero continúa la ejecución. Es útil cuando procesas un conjunto de elementos y quieres un reporte por elemento de qué funcionó y qué falló, sin detener todo ante el primer error. Solo lo mencionamos aquí como contexto; lo veremos con más detalle cuando abordemos el pipeline, donde resulta especialmente relevante.
Error terminante
Un error terminante interrumpe inmediatamente el flujo. Úsalo cuando
la operación es crítica (crear/escribir/borrar datos relevantes, cambios de estado,
CI/CD), promoviendo fallos con
y manejándolos con -ErrorAction Stop -ErrorAction Stop /try try /catch catch .
finally finally
En CI/CD suele ser deseable fallar rápido para evitar despliegues inconsistentes o estados intermedios.
Regla práctica
Si un fallo invalida el resultado del script, conviértelo en terminante; si solo invalida un elemento, suele ser mejor tratarlo como no terminante (registrar y continuar).
Este ejemplo implementa una copia segura y predecible con para confirmación, y elevación de errores a terminantes para capturarlos con
ShouldProcess ShouldProcess . El bloque catch catch
garantiza una salida estructurada con el estado de la operación, incluso
ante fallos o cancelaciones.
finally finally
ShouldProcess y salida estructurada #Requires -Version 7.5
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
param(
[Parameter(Mandatory)]
[ValidateNotNullOrWhiteSpace()]
[ValidateScript({ Test-Path -LiteralPath $_ })]
[string] $Source,
[Parameter(Mandatory)]
[ValidateNotNullOrWhiteSpace()]
[ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })]
[string] $Destination,
[switch] $Recurse
)
Set-StrictMode -Version 3.0
$result = @{
Source = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($Source)
Destination = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($Destination)
}
$result.Target = Join-Path $result.Destination (Split-Path -Leaf $result.Source)
try {
$shouldProcess = $PSCmdlet.ShouldProcess($result.Source, 'Copy to {0}' -f $result.Destination)
if ($shouldProcess) {
if (Test-Path -LiteralPath $result.Target) {
$result.Status = 'Skipped'
$result.Reason = ('Target already exists: {0}' -f $result.Target)
}
else {
$copyParams = @{
LiteralPath = $result.Source
Destination = $result.Destination
Recurse = $Recurse
ErrorAction = 'Stop'
}
Copy-Item @copyParams
$result.Status = 'Copied'
}
}
else {
# Make cancellation explicit so callers don't need to infer it from missing Status
$result.Status = 'Cancelled'
$result.Reason = 'ShouldProcess returned False (confirmation declined or -WhatIf)'
}
}
catch {
$result.Status = 'Failed'
$result.Error = [PSCustomObject]@{
Kind = $_.Exception.GetType().Name
Message = $_.Exception.Message
}
}
finally {
[PSCustomObject]$result
} Detalles clave
El objetivo del diseño no es solo copiar archivos: es comunicar explícitamente qué ocurrió, sin obligar al consumidor a inferirlo desde excepciones o salida textual.
- Rutas normalizadas y destino final:
resuelve rutas absolutas;$PSCmdlet.GetUnresolvedProviderPathFromPSPath()$PSCmdlet.GetUnresolvedProviderPathFromPSPath()compone elJoin-Path ... (Split-Path -Leaf ...)Join-Path ... (Split-Path -Leaf ...)Target. - Validación temprana:
asegura que el origen existe y que el destino es un contenedor.[ValidateScript({ Test-Path ... })][ValidateScript({ Test-Path ... })] -
: promueve fallos de-ErrorAction Stop-ErrorAction Stopa terminantes para entrar enCopy-ItemCopy-Item.catchcatch - Salida estructurada: en
devolvemosfinallyfinallycon$result$resultSource/Destination/Target,Statusy, cuando aplica,ReasonoError.
Cancelled se modela de forma explícita para evitar ambigüedad: el
script no falló, simplemente no ejecutó la acción (decisión del
usuario o ).
-WhatIf -WhatIf
Estados posibles del resultado
-
Copied: la copia se realizó correctamente. -
Skipped: el destino ya existía. -
Cancelled:devolvióShouldProcessShouldProcessfalse. -
Failed: ocurrió un error terminante durante la operación.
Uso
Ejecuta el script desde la terminal pasando un archivo y una carpeta destino, para centrarnos en el contrato del script antes de introducir pipelines:
# Preparación mínima
$dest = 'backup'
if (!(Test-Path -LiteralPath $dest)) {
New-Item -ItemType Directory -Path $dest
}
# Ensayo con -WhatIf -> 'Cancelled'
$w = ./Copy-ItemStrict.ps1 -Source './Copy-ItemStrict.ps1' -Destination $dest -WhatIf
$w.Status
$w.Reason
# Copia real -> 'Copied' (primera vez) o 'Skipped'
$r = ./Copy-ItemStrict.ps1 -Source './Copy-ItemStrict.ps1' -Destination $dest
$r.Status
$r.Target
Más adelante veremos cómo esta salida estructurada permite encadenar decisiones en
pipelines, sin depender de /try try externos.
catch catch
Piensa rápido
- Repite la copia para observar
Skippedy elReason. - Intenta copiar una carpeta sin
-Recursepara verFailedy leerError.Kind/Error.Message.
Esquema de salida y estabilidad
Este ejemplo define un contrato explícito: siempre devuelve
Source/Destination/Target y añade Status para que el
consumidor no tenga que inferir qué pasó leyendo excepciones o texto. Nombrar
Cancelled de forma directa evita el antipatrón de asumir que
«no se hizo nada» solo porque falta información, algo frágil en
automatización.
Hay un compromiso
Status en un pipeline) versus uno flexible
(propiedades opcionales según el caso). Aquí todavía no usamos el pipeline,
así que privilegiamos claridad por encima de rigidez total.
Regla práctica
Nota
@{} @{} (hashtable) puedes perder el orden de propiedades. Si necesitas un orden fijo (por ejemplo, para
una tabla), crea el [PSCustomObject] [PSCustomObject] desde el inicio y
agrega propiedades con Add-Member Add-Member .
catch catch tipado
catch catch tipado
Puedes definir varios bloques para distintos
tipos de excepción y cerrar con uno genérico. Ordénalos de los más específicos a los
más generales.
catch catch
catch y uso práctico try {
Copy-Item @copyParams
}
catch [System.UnauthorizedAccessException] {
Write-Warning ('Permisos insuficientes: {0}' -f $_.Exception.Message)
}
catch [System.IO.IOException] {
Write-Warning ('Problema de E/S: {0}' -f $_.Exception.Message)
}
catch {
Write-Warning ('Error {0}: {1}' -f $_.Exception.GetType().Name, $_.Exception.Message)
}
En PowerShell es común incluir un genérico
porque muchos cmdlets encapsulan las excepciones .NET dentro de objetos
catch catch . En la práctica esto implica que el
tipo de excepción original no siempre es el que llega al
[ErrorRecord] [ErrorRecord] , por lo que tipar puede fallar. El
catch catch genérico actúa como última línea de
defensa: garantiza que el error no se pierda ni quede sin manejar.
catch catch
Regla práctica
catch catch solo cuando esperas un fallo concreto y
recurrente; mantén siempre un catch catch genérico como
respaldo. En ambos casos, el objetivo es convertir el error en información
útil (por ejemplo en Error) para quien consuma el resultado.
Verificar y ejecutar comandos externos con seguridad
Patrón simple: resolver el binario real con ,
ejecutarlo con el call operator Get-Command Get-Command , y validar
& & . Devuelve un objeto con datos útiles para logs
o para controlar el flujo.
$LASTEXITCODE $LASTEXITCODE
#Requires -Version 7.5
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[ValidateNotNullOrWhiteSpace()]
[string] $Name,
[Parameter(ValueFromRemainingArguments)]
[ValidateNotNull()]
[string[]] $Rest = @()
)
Set-StrictMode -Version 3.0
$cmds = @(Get-Command -Name $Name -CommandType Application -ErrorAction Stop)
if ($cmds.Count -gt 1) {
Write-Warning ("Multiple executables named '{0}' were found. Using: {1}" -f
$Name, $cmds[0].Source)
}
$path = $cmds[0].Source
$originalEncoding = [Console]::OutputEncoding
try {
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$out = & $path @Rest 2>&1
}
finally {
[Console]::OutputEncoding = $originalEncoding
}
if ($LASTEXITCODE -eq 0) {
[PSCustomObject]@{
ToolPath = $path
ExitCode = $LASTEXITCODE
Output = $out
}
}
else {
$nl = [Environment]::NewLine
$msg = ('{0} {1} returned exit code {2}.{3}Output:{3}{4}' -f $Name, ($Rest -join ' '),
$LASTEXITCODE, $nl, ($out -join $nl))
throw [System.Exception]::new($msg)
} Detalles clave
-
: todo lo que quede después deValueFromRemainingArgumentsValueFromRemainingArgumentsse captura en-Name-Namesin intentar interpretarlo como parámetros del script. Así puedes pasar flags arbitrarios al binario:$Rest$Rest.Invoke-Tool -Name git -C . status --porcelainInvoke-Tool -Name git -C . status --porcelain -
: resuelve el ejecutable real (solo de tipo Application) a partir de todos los candidatos que encuentra (devuelve una colección). Aquí usamos una heurística simple (primer candidato), suficiente para scripts controlados; si el entorno es más complejo, puedes filtrar por ruta/versión. ConGet-Command ... -ErrorAction StopGet-Command ... -ErrorAction Stopconvertimos «no encontrado» en error terminante.-ErrorAction Stop-ErrorAction Stop - Seguridad (PATH hijacking): resolver el binario con
y ejecutar su ruta (Get-CommandGet-Command) reduce el riesgo de invocar otro ejecutable con el mismo nombre por manipulación del$path$pathPATH. - Forzar arreglo con
: envolver la llamada a@()@()enGet-CommandGet-Commandgarantiza que el resultado sea siempre un arreglo (0, 1 o más elementos). De este modo@(...)@(...)y la indexación (.Count.Count) funcionan de forma consistente sin errores sorpresa cuando solo hay un candidato o ninguno.$cmds[0]$cmds[0] -
: ruta absoluta al binario resuelto (p. ej.,[CommandInfo].Source[CommandInfo].SourceC:\Program Files\Git\cmd\git.exe). Se usa para invocarlo de forma inequívoca. -
: establece UTF-8 temporalmente para capturar stdout/stderr con caracteres especiales. Se restaura en[Console]::OutputEncoding[Console]::OutputEncodingpara no afectar la sesión.finallyfinally - Línea clave:
: ejecuta el binario ($out = & $path @Rest 2>&1$out = & $path @Rest 2>&1), pasa argumentos sin reinterpretarlos (&&) y captura stdout + stderr juntos (@Rest@Rest).2>&12>&1 -
: código de salida del proceso nativo.$LASTEXITCODE$LASTEXITCODE= éxito; cualquier otro se trata como error y se eleva con un mensaje detallado. Nota:00solo aplica a procesos nativos; los cmdlets de PowerShell reportan fallos vía errores, no por exit codes.$LASTEXITCODE$LASTEXITCODE -
: promueve el fallo a error terminante con contexto (comando, argumentos, código y salida), ideal para CI/CD y manejo en niveles superiores conthrow [System.Exception]::new($msg)throw [System.Exception]::new($msg)/trytry.catchcatch
Arreglos en PowerShell
En PowerShell, un arreglo ( ) es una
colección ordenada de elementos. Es, además, la forma “natural” de representar
cero, uno o muchos resultados: muchos comandos devuelven un arreglo cuando
hay múltiples valores. Para normalizar, envolver una expresión en [T[]] [T[]] garantiza que el resultado sea siempre un arreglo (aunque tenga 0 o 1 elemento).
Declaras un arreglo vacío con @() @() o simplemente listando
valores separados por comas:
@() @()
# Arreglo vacío
$empty = @()
# Arreglo con valores
$tools = @('git', 'curl', 'wget')
# O simplemente:
$tools = 'git', 'curl', 'wget'
# Acceso por índice (base cero)
$tools[0] # 'git'
$tools[1] # 'curl'
# Contar elementos
$tools.Count # 3
En , el parámetro Invoke-Tool.ps1 Invoke-Tool.ps1 es un arreglo de strings ($Rest $Rest ) que captura
todos los argumentos restantes gracias a [string[]] [string[]] . Luego, ValueFromRemainingArguments ValueFromRemainingArguments (splatting) expande ese arreglo como
argumentos individuales al comando nativo. Esto evita un error común: pasar
@Rest @Rest sin splatting enviaría el arreglo como un
solo
argumento.
$Rest $Rest
Importante
+= +=
crean un nuevo arreglo.
Streams de salida en PowerShell
PowerShell no se limita a imprimir texto: maneja múltiples streams de salida, lo que permite separar mensajes de éxito, errores, advertencias, depuración, etc. Esto hace posible redirigirlos o tratarlos de forma independiente en un mismo script.
La idea clave para esta etapa es simple: distinguir entre datos y
mensajes. En la práctica, devolver objetos (por ejemplo un ) por el pipeline es equivalente a usar [PSCustomObject] [PSCustomObject] .
Write-Output Write-Output
De momento solo nos interesa la idea general: el stream 1 se usa
para la salida normal, y el resto (2–6) sirven para errores, advertencias, mensajes
verbosos, depuración, etc. El stream 6 (Information) es útil para
mensajes informativos que el consumidor puede mostrar, suprimir o redirigir según su
configuración. Más adelante veremos con detalle cómo usar
para propagar errores no terminantes en
el pipeline; por ahora nos apoyaremos sobre todo en
salida estructurada y dejaremos la responsabilidad de imprimir en
pantalla a quien consuma estos scripts (otros cmdlets, pipelines o
herramientas de automatización), que decidirán qué mostrar, cuándo y cómo.
Write-Error Write-Error
| Stream | Descripción | Write Cmdlet |
| 1 | Éxito (Output) | |
| 2 | Error | |
| 3 | Warning | |
| 4 | Verbose | |
| 5 | Debug | |
| 6 | Information | |
| n/a | Progress | |
Ejercicio:
Fallback por comando
Requisitos
- Implementa
que intente ejecutar una tarea usando una cadena de alternativas de binarios. No interrogues el sistema operativo; en su lugar, resuelve comandos (conInvoke-WebRequestByFallback.ps1Invoke-WebRequestByFallback.ps1) y usaInvoke-Tool.ps1Invoke-Tool.ps1/trytrypara avanzar al siguiente. La idea es que el comportamiento dependa de la disponibilidad real de herramientas, no del “entorno declarado” (plataforma/versión).catchcatch - Escenario propuesto (puedes elegir otro): descargar un archivo probando primero
wgety luegocurl. - El script debe:
- Interfaz: recibir
y-Uri-Uri(obligatorios).-OutFile-OutFile - Estrategia de fallback: intentar
wget; si falla, intentarcurl(en el).catchcatch - Fallos explícitos: si ambos fallan,
con un mensaje consolidado.throwthrow - Contrato de salida: devolver un objeto estructurado con el estado de la operación.
- Objetivo: la descarga es un pretexto; lo importante es modelar una cadena de alternativas con fallos explícitos y un resultado verificable.
-
Notas
wget wget
wget wget
Descargador común en Linux/BSD; puede instalarse en macOS/Windows. Usa
para definir el archivo de salida.
-O -O
wget # Descargar a un archivo específico
wget -O "<OutFile>" "<Uri>"
# Ejemplo
wget -O "./download/file.txt" "https://example.com/file.txt" curl curl
curl curl
Cliente de transferencia que viene preinstalado en macOS y muchas distros Linux;
en Windows 10+ suele estar disponible. Úsalo con
para seguir redirecciones y
-L -L para especificar archivo de salida.
-o -o
curl curl # Descargar siguiendo redirecciones
curl -L -o "<OutFile>" "<Uri>"
# Ejemplo
curl -L -o "./download/file.txt" "https://example.com/file.txt" Uso esperado
$params = @{
Uri = 'https://www.toptal.com/developers/gitignore/api/powershell,windows,linux,macos,visualstudiocode'
OutFile = '.gitignore'
Verbose = $true
}
./Invoke-WebRequestByFallback.ps1 @params Hints
- Usa
para obtener la ruta real deJoin-Path ... -ResolveJoin-Path ... -ResolveInvoke-Tool.ps1y fallar temprano si no existe.Invocador seguro$invoker = Join-Path $PSScriptRoot '..' 'tools' 'Invoke-Tool.ps1' -Resolve # Ejemplo de uso con call operator (&) y argumentos: & $invoker wget -O './out.txt' 'https://example.com/file.txt'valida la ruta en tiempo de inicio; evita fallos tardíos.-Resolve-Resolve - Prefiere tipar
y validar el esquema en lugar de[uri] $Uri[uri] $Uri:[string][string]Validación de URL robusta[Parameter(Mandatory)] [ValidateScript({ $_.Scheme -in @('http','https') })] [uri] $UriEl tipoparsea la dirección; el[uri][uri]asegura[ValidateScript][ValidateScript]http/https.
Solución
#Requires -Version 7.5
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
param(
[Parameter(Mandatory)]
[ValidateScript({ $_.Scheme -in @('http','https') })]
[uri] $Uri,
[Parameter(Mandatory)]
[ValidateNotNullOrWhiteSpace()]
[string] $OutFile
)
Set-StrictMode -Version 3.0
$invoker = Join-Path $PSScriptRoot '..' 'tools' 'Invoke-Tool.ps1' -Resolve
if ($PSCmdlet.ShouldProcess("$Uri to $OutFile", 'Download file')) {
try {
& $invoker wget -O $OutFile $Uri
[PSCustomObject]@{
Uri = $Uri
OutFile = $OutFile
Tool = 'wget'
Status = 'Success'
}
}
catch {
Write-Warning ('wget failed: {0}' -f $_.Exception.Message)
try {
& $invoker curl -L -o $OutFile $Uri
[PSCustomObject]@{
Uri = $Uri
OutFile = $OutFile
Tool = 'curl'
Status = 'Success'
}
}
catch {
Write-Warning ('curl failed: {0}' -f $_.Exception.Message)
throw [System.Exception]::new("Both wget and curl failed to download $Uri")
}
}
}Conclusiones
El hilo conductor de esta lección es que, en PowerShell, el manejo de errores es una
decisión de diseño y una herramienta explícita de control de flujo.
Cuando la integridad importa, eleva fallos con
y manéjalos con
-ErrorAction Stop -ErrorAction Stop /try try /catch catch ; cuando buscas reportar sin interrumpir, prefiere errores no terminantes. Al ejecutar
binarios externos, resuélvelos primero (finally finally ),
ejecútalos con Get-Command Get-Command y valida con
& & o un wrapper como
$LASTEXITCODE $LASTEXITCODE , devolviendo salida estructurada
en lugar de texto plano.
Invoke-Tool.ps1 Invoke-Tool.ps1
Puntos clave
- Promueve errores críticos con
para activar-ErrorAction Stop-ErrorAction Stopdonde puedas decidir cómo reaccionar.catchcatch - En
,catchcatches el$_$_(tipo y mensaje en[ErrorRecord][ErrorRecord]).$_.Exception$_.Exception - Resuelve binarios con
y llama al path real.Get-Command -ErrorAction StopGet-Command -ErrorAction Stop - Ejecuta con
y valida con&&(o tu wrapper).$LASTEXITCODE$LASTEXITCODE -
mezcla stderr en stdout para capturar todo en una variable cuando te convenga simplificar el flujo.2>&12>&1
¿Qué nos llevamos?
El buen manejo de errores es diseño, no accidente. Elevar fallos a terminantes, envolver herramientas externas y devolver objetos no es “ser más estricto”: es ser más predecible. Si registras con intención, priorizas la salida estructurada sobre el texto suelto y «fail loudly» cuando corresponde, tus scripts serán más confiables, portables y fáciles de mantener.
Comparativas y otros ecosistemas
¿Con ganas de más?
Referencias recomendadas
- “Handling errors” (pp. 279–286) en Learn PowerShell in a Month of Lunches, fourth edition: Covers Windows, Linux, and MacOS por Travis PlunkCapítulo práctico sobre manejo de errores en PowerShell que explica la diferencia entre errores no terminantes y excepciones, cómo forzar excepciones con
para poder capturarlas con-ErrorAction Stop-ErrorAction Stop/trytry/catchcatch, y el papel definallyfinally,$Error$Error(incluyendo el uso de-ErrorVariable-ErrorVariablepara acumular) y++. Advierte contra malas prácticas como silenciar errores globalmente, y muestra cuándo registrar, continuar o detener según el objetivo del script. Incluye patrones para comandos nativos y métodos .NET (cuándo ajustar temporalmente las preferencias), y ejemplos de$ErrorActionPreference$ErrorActionPreferencetipados. Ideal para entender qué registrar, cómo reaccionar ante fallos y cómo diseñar herramientas que fallen de forma explícita y depurable.catchcatch
Referencias adicionales
- “Errors and exceptions” (pp. 531–562) en Windows PowerShell in Action, Third Edition por Bruce Payette y Richard SiddawayCapítulo estructurado sobre el sistema de manejo de errores de PowerShell como herramienta de automatización crítica. Explica la distinción fundamental entre errores terminantes (que interrumpen el flujo) y no terminantes (que continúan pero registran fallos), alineados con el modelo de streaming de PowerShell. Cubre objetos
con sus propiedades ricas (ErrorRecordErrorRecordException,TargetObject,CategoryInfo,InvocationInfo), cómo capturar errores usando redirección (), el parámetro2>&12>&1, y variables de estado (-ErrorVariable-ErrorVariable,$?$?). Incluye patrones para diagnosticar y gestionar errores en scripts, especialmente útil para entender cuándo un fallo debe detener la ejecución y cuándo debe reportarse sin interrumpir un pipeline.$LASTEXITCODE$LASTEXITCODE - “ about_Redirection ” en la documentación oficial de PowerShellBreve guía de redirección en PowerShell: explica cómo enviar salida a archivos y combinar flujos (éxito, error, warning, etc.) usando
,Out-FileOut-Filey operadores de redirección (Tee-ObjectTee-Object,>>,>>>>,n>&1n>&1). Incluye tabla de flujos redireccionables, cambios en PowerShell 7.4 para redirigir stdout de comandos nativos (conservando bytes), ejemplos prácticos (fusionar*>*>, redirigir todos los flujos, suprimir Information/Host), efectos de Action Preferences, consideraciones de codificación y ancho de salida, y notas sobre confusiones comunes con2>&12>&1vs. comparadores (>>,-gt-gt).-lt-lt - “ about_Try_Catch_Finally ” en la documentación oficial de PowerShellDescripción formal de cómo usar
/trytry/catchcatchpara manejar errores terminantes en PowerShell. Presenta la sintaxis general de los bloques, muestra cómo envolver código que puede fallar, cómo disponer de varios bloquesfinallyfinally(genéricos y tipados) y en qué orden se evalúan, y explica qué ocurre con las excepciones no capturadas. Detalla la relación concatchcatchy con las preferencias de error, cómo acceder a la información de la excepción víatraptrap/$_$_y las propiedades de$PSItem$PSItem([ErrorRecord][ErrorRecord]CategoryInfo,TargetObject, etc.), y cómo usarpara liberar recursos o dejar el sistema en un estado consistente. Incluye ejemplos prácticos y notas sobre buenas prácticas para escribir bloquesfinallyfinallyclaros y seguros.catchcatch