Funciones en scripts de PowerShell
Feb 12, 2025
Las funciones de PowerShell agrupan código reutilizable en unidades modulares y mantenibles que simplifican la escritura de scripts y reducen errores. Definidas con la function palabra clave, pueden incluir parámetros, aceptar entrada de pipeline y comportarse como cmdlets usando [CmdletBinding()]. Las funciones admiten características avanzadas como el manejo de errores con Try/Catch, salida detallada y de depuración, y organización de módulos. Las mejores prácticas incluyen nombramiento significativo, diseño modular, devolución de objetos y documentación con ayuda basada en comentarios.
Una función de PowerShell es un bloque de código diseñado para realizar una tarea específica. Una vez que se crea y se prueba una función, se puede utilizar en múltiples scripts, reduciendo el esfuerzo de codificación y el riesgo de errores. Usar funciones bien nombradas también hace que los scripts sean más fáciles de leer y mantener. Y dado que las funciones pueden devolver valores que pueden ser utilizados como entrada para otras funciones o bloques de código, facilitan la construcción de operaciones complejas.
Este artículo explica todo lo que necesita saber para comenzar a usar las funciones de PowerShell, incluyendo las mejores prácticas importantes, e incluso ofrece orientación para adentrarse en opciones más avanzadas.
Comenzando con las funciones de PowerShell
Cómo crear una función en PowerShell
Para definir una función, se utiliza la palabra clave function. La sintaxis básica es la siguiente:
function <Function-Name> {
<Code-Block>
}
El código dentro de las llaves {} se ejecutará cuando se llame a la función.
Si lo desea, puede utilizar la palabra clave param para especificar los parámetros de la función, junto con los tipos de datos, valores predeterminados y demás. Aquí está la sintaxis con los parámetros añadidos:
function <Function-Name> {
[param(
[<ParameterType>]$<ParameterName>,
[<ParameterType>]$<ParameterName2> = <DefaultValue>
)]
<Code-Block>
}
Este ejemplo de función de PowerShell multiplicará dos números y mostrará el resultado:
function Multiply-Numbers {
param (
[int]$Number1,
[int]$Number2
)
$Result = $Number1 * $Number2
Write-Output "The multiplication value of $Number1 and $Number2 is $Result."
}
Guardando una Función
Para guardar una función, simplemente guárdela en un archivo de script con una.ps1?extensión.
Llamando a una función
Para invocar una función en PowerShell, escriba el nombre de la función seguido de los parámetros nombrados necesarios. Por ejemplo, aquí le mostramos cómo llamar a la función que definimos anteriormente:
Multiply-Numbers -number1 6 -Number2 8
Ejecutando una función como parte de la sesión actual (Dot-Sourcing)
El dot-sourcing te permite ejecutar un script de PowerShell como si estuviera definido directamente dentro de tu sesión de consola actual. Para usar el dot-sourcing, antecede el nombre de la función con un punto y un espacio (. ) al llamarla.
Por ejemplo, supongamos que hemos definido la siguiente función llamada Add-Numbers:
function Add-Numbers {
param (
[int]$Number1,
[int]$Number2
)
$Sum = $Number1 + $Number2
Write-Output "The sum of $Number1 and $Number2 is $Sum."
}
Podemos incluir esta función en nuestra sesión como se muestra aquí:
Nombrando tus funciones de PowerShell
Para obtener el máximo valor de las funciones de PowerShell, asegúrate de seguir estas pautas al nombrar tus funciones.
Utilice el formato verbo-sustantivo.
PowerShell proporciona un conjunto de cmdlets preconstruidos cuyos nombres siguen un formato específico: un verbo que especifica la acción a realizar, seguido de un sustantivo que nombra el objeto sobre el cual actuar. Por ejemplo, el cmdlet get-user recupera información sobre un usuario y remove-item elimina un elemento especificado.
Es una mejor práctica seguir la misma convención de nombres para las funciones que creas. Hacerlo te ayudará a diseñar tus funciones de manera más efectiva y las hará más fáciles de reutilizar.
Utilice verbos aprobados.
PowerShell proporciona una lista de verbos recomendados para su uso en funciones. Para ver la lista, simplemente ejecute el siguiente cmdlet:
Get-Verb
Elija sustantivos descriptivos.
Es vital no darle a una función el mismo nombre que un cmdlet incorporado. Una buena manera de prevenir este problema es evitar usar sustantivos genéricos como user y data. En su lugar, elige sustantivos que indiquen claramente el tipo de datos sobre los que actúa la función. Por ejemplo, es fácil entender cómo difieren estas funciones: Get-EmployeeData, Get-UserInfo y Get-ServiceInfo.
Evite usar nombres de funciones para propósitos de versionado.
Agregar números de versión a los nombres de funciones, como Get-UserInfoV2, no es recomendable. Hace que los scripts sean más difíciles de entender y aumenta la probabilidad de usar versiones antiguas de una función. En su lugar, gestione las versiones a través de su sistema de control de versiones de archivos.
Capacidades de Funciones Avanzadas
Aceptando entrada de Pipeline
Puede diseñar una función para aceptar entradas de otra función o comando a través de un pipeline utilizando el atributo ValueFromPipeline.
Para ilustrar, vamos a crear una función que procese una lista de cadenas de texto una por una, convierta cada cadena a mayúsculas y muestre los resultados. Para mayor claridad, dividiremos el procesamiento de la cadena en tres bloques distintos:
- BEGIN — Este código se ejecuta una vez, antes de procesar cualquier entrada de la tubería.
- PROCESO — Esta sección se ejecuta para cada elemento que se pasa al pipeline, procesando los objetos de entrada uno por uno.
- FIN — Este código se ejecuta después de que todos los datos de entrada han sido procesados para finalizar la salida.
function Convert-ToUppercase {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
[string]$InputString
)
BEGIN {
Write-Verbose "Starting the uppercase conversion process."
}
PROCESS {
if (-not [string]::IsNullOrWhiteSpace($InputString)) {
Write-Verbose "Processing string: $InputString"
$InputString.ToUpper()
} else {
Write-Verbose "Skipped empty or null string."
}
}
END {
Write-Verbose "Finished processing all strings."
}
}
Así es como podríamos llamar a nuestra función para convertir una lista de cadenas proporcionadas a través de un pipeline:
"hello", "world", "this", "is", "powershell" | Convert-ToUppercase -Verbose
Tenga en cuenta que las funciones ligeras llamadas filters pueden proporcionar una manera altamente eficiente de procesar objetos que pasan a través de un pipeline.
Habilitando una función para que se comporte como un Cmdlet
Puede convertir una función básica en una función avanzada utilizando el atributo CmdletBinding. Al hacerlo, permite que la función se comporte como un cmdlet, incluyendo el soporte para los parámetros definidos de PowerShell.
Aquí está la función básica que definimos anteriormente para sumar dos números:
function Add-Numbers {
param (
[int]$Number1,
[int]$Number2
)
$Sum = $Number1 + $Number2
Write-Output "The sum of $Number1 and $Number2 is $Sum."
}
Podemos convertirlo en una función avanzada de la siguiente manera:
function Add-Numbers {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[int]$Number1,
[Parameter(Mandatory)]
[int]$Number2
)
process {
# Verbose Output
Write-Verbose "Starting addition of $Number1 and $Number2"
# Debugging Output
Write-Debug "Debugging: Ensuring numbers are valid integers"
# Perform the Addition
try {
$Result = $Number1 + $Number2
Write-Output $Result
} catch {
# Handle errors with error stream
Write-Error "An error occurred while performing the addition."
}
# Verbose Completion Message
Write-Verbose "Addition completed successfully"
}
}
Solicite una prueba gratuita de Netwrix Auditor
Construcción de Módulos de Función
Un módulo de función es un archivo con una extensión .psm1 que contiene una colección de funciones relacionadas. Organizar las funciones en módulos facilita la reutilización y el mantenimiento.
Para crear un módulo de función, simplemente cree un archivo de texto, pegue sus funciones y guarde el archivo con la extensión .psm1 en el directorio C:\Program Files\WindowsPowerShell\Modules. Por ejemplo, podríamos crear un módulo con función aritmética como la función Add-Numbers definida anteriormente.
Para importar el módulo en tu sesión de PowerShell, utiliza el comando Import-Module, como se muestra aquí:
Manejo de errores
PowerShell ofrece varias técnicas de manejo de errores para ayudarte a manejar problemas que de otra manera podrían detener la ejecución de una función con un error, como un intento de dividir por cero.
Bloques Try/Catch/Finally
Cuando sabes que una cierta condición podría causar un problema, puedes usar los bloques Try, Catch y Finally en tu función para manejar esa condición de manera elegante:
- Prueba — Este bloque contiene código que puede producir un error (como una operación de división). Si no ocurre ningún error, el bloque Catch no se ejecutará.
- Catch — Si ocurre un error en el bloque Try, el bloque Catch lo manejará capturando y procesando los detalles del error.
- Finalmente — Este bloque es opcional. Si está presente, se ejecuta después de los bloques Try y Catch, independientemente de si ocurrió un error.
-ErrorAction Parameter
El parámetro -ErrorAction permite especificar cómo se deben manejar los errores para una función en particular. Los valores posibles son:
- Continuar — Muestre un mensaje de error y continúe.
- Detener — Detiene la ejecución del script cuando ocurre un error.
- SilentlyContinue — Suprimir el mensaje de error y continuar con la ejecución.
- Consultar — Pida al usuario cómo manejar el error con opciones como Sí, No y Reintentar.
- Ignorar — Ignorar el error completamente sin siquiera mostrar un mensaje.
A continuación se presentan algunos ejemplos del parámetro -ErrorAction:
Remove-Item "C:\path\to\nonexistentfile.txt" -ErrorAction SilentlyContinue
Get-Process -Name "Notepad" -ErrorAction Stop
Variable $ErrorActionPreference
La variable $ErrorActionPreference controla cómo se manejan los errores globalmente para todos los cmdlets en una sesión. Esta variable se puede configurar para influir en el comportamiento del manejo de errores en todos los comandos, a menos que sea reemplazado por el parámetro -ErrorAction.
Ejemplo detallado
A continuación se muestra un ejemplo que utiliza múltiples métodos de manejo de errores:
- La variable $ErrorActionPreference establece la preferencia global de manejo de errores en stop, por lo que cuando ocurre un error que no se maneja de otra manera, la ejecución se detendrá.
- Los bloques Try/Catch manejan de manera elegante el posible error de dividir por cero sin detener la ejecución. El bloque Try realiza las operaciones matemáticas. Si se encuentra con una división por cero, el procesamiento se mueve al bloque Catch que imprime un mensaje de error.
- El bloque Finally se ejecutará independientemente de si ocurrió un error, imprimiendo un mensaje que indica que las operaciones están completas.
# Set global error action preference to 'Stop' to immediately halt on errors
$ErrorActionPreference = 'Stop'
function Perform-MathOperations {
param (
[int]$Num1,
[int]$Num2
)
try {
# Performing addition
Write-Host "Performing addition: $Num1 + $Num2"
$additionResult = $Num1 + $Num2
Write-Host "Addition Result: $additionResult"
# Checking for division by zero before performing division
if ($Num2 -eq 0) {
throw "Division by zero is not allowed."
}
# Performing division
Write-Host "Performing division: $Num1 / $Num2"
$divisionResult = $Num1 / $Num2
Write-Host "Division Result: $divisionResult"
}
catch {
# Catching any error that occurs in the try block
Write-Host "An error occurred: $_"
Write-Host "Error Type: $($_.Exception.GetType().Name)"
}
finally {
# This block always runs regardless of error occurrence
Write-Host "Finished performing math operations."
}
}
La captura de pantalla a continuación muestra el resultado de llamar a esta función de dos maneras. Primero, la llamamos con una entrada válida:
Realizar-MathOperations -Num1 10 -Num2 2
Luego lo llamamos con una entrada que resultará en un intento de dividir por cero:
Perform-MathOperations -Num1 10 -Num2 0
Solución de problemas de sus funciones
Puede mostrar mensajes que proporcionan diferentes niveles de detalle durante la ejecución de la función utilizando Write-output (o Write-host), Write-Verbose y Write-Debug. Esta información puede ayudarle a rastrear el camino de ejecución paso a paso para identificar comportamientos inesperados.
Por ejemplo, la siguiente captura de pantalla muestra cómo podríamos revisar nuestra función básica Add-Numbers para proporcionar detalles de solución de problemas. Tenga en cuenta que, por defecto, el flujo de mensajes detallados no se muestra, por lo que necesitamos usar -Verbose al invocar la función.
Add-Numbers -Number1 5 -Number2 10 -Verbose
De manera similar, Write-Debug los mensajes no se muestran en la consola por defecto, pero puedes mostrarlos incluyendo -Debug cuando ejecutas la función:
Add-Numbers -Number1 5 -Number2 10 -Debug
Mejores prácticas
- Diseñe cada función para que realice una sola tarea. Esto las hace más fáciles de probar, usar y mantener.
- Diseña las funciones de manera modular para que puedan reutilizarse en diferentes scripts.
- Al utilizar parámetros, especifique sus valores predeterminados.
- Incluya comentarios detallados en sus funciones. Esta ayuda basada en comentarios facilitará la depuración y la reutilización de las funciones.
- Haz que tus funciones devuelvan objetos en lugar de salida formateada para mejorar la reutilización.
Ejemplo adicional
La siguiente función ilustra muchas de las capacidades discutidas anteriormente, incluyendo el manejo de errores:
# Function: Backup-Files
# Description: Backs up files from a source directory to a backup directory.
function Backup-Files {
param (
[Parameter(Mandatory = $true)]
[string]$SourcePath, # The directory containing the files to back up
[Parameter(Mandatory = $true)]
[string]$BackupPath, # The directory where files will be backed up
[string[]]$Extensions = @("*") # File extensions to back up (default: all files)
)
# Check if the source path exists
if (-not (Test-Path -Path $SourcePath)) {
Write-Error "Source path '$SourcePath' does not exist."
return
}
# Create the backup directory if it does not exist
if (-not (Test-Path -Path $BackupPath)) {
Write-Output "Creating backup directory at '$BackupPath'..."
New-Item -ItemType Directory -Path $BackupPath | Out-Null
}
# Get files matching the specified extensions
foreach ($extension in $Extensions) {
$files = Get-ChildItem -Path $SourcePath -Filter "*.$extension" -File -ErrorAction SilentlyContinue
foreach ($file in $files) {
$destination = Join-Path -Path $BackupPath -ChildPath $file.Name
Write-Output "Backing up file: $($file.FullName) -> $destination"
Copy-Item -Path $file.FullName -Destination $destination -Force
}
}
Write-Output "Backup completed successfully."
}
Podemos llamar a esta función para respaldar todos los archivos, o solo seleccionar extensiones de archivo como se muestra aquí:
Backup-Files -SourcePath "D:\Office\project" -BackupPath "D:\Backup" -Extensions @("csv", "txt")
Conclusión
Las funciones en PowerShell ofrecen un enfoque estructurado para la creación de scripts que mejora la modularidad, reutilización y mantenibilidad. Siéntase libre de experimentar con todo el código de muestra proporcionado en este artículo. A medida que comience a crear sus propias funciones, asegúrese de adoptar las mejores prácticas para nombrarlas y utilizarlas.
Compartir en
Aprende más
Acerca del autor
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.