Qué es
Este artículo ofrece una guía completa sobre las mejores prácticas para scripting en PowerShell, enfocándose en la estructura del código, formato de salida, manejo de errores, optimización del rendimiento y medidas de seguridad.
Por qué
Seguir las mejores prácticas en scripting de PowerShell garantiza que tus scripts sean legibles, mantenibles, seguros y eficientes. Esto reduce la deuda técnica, mejora la colaboración y minimiza los riesgos en entornos de producción.
Cómo
Diseño de Herramientas y Controladores
Decide si estás creando una ‘Herramienta’ o un ‘Controlador’
- Herramienta: Funciones/módulos reutilizables.
- Controlador: Automatiza una tarea específica, no diseñado para reutilización.
Haz tu código modular
- Utiliza funciones y módulos para maximizar la reutilización.
Usa convenciones estándar de nomenclatura
- Sigue el formato Verbo-Sustantivo utilizando los verbos aprobados por PowerShell (
Get-Verb
).
Estandariza los nombres de los parámetros
- Usa nombres como
$ComputerName
en lugar de prefijos personalizados.
Las herramientas deben devolver datos en bruto
- Proporciona datos mínimamente procesados para mayor flexibilidad.
Los controladores deben devolver datos formateados
- Formatea la salida para generar reportes fáciles de leer.
Ejemplo
function Get-DiskInfo {
param ([string]$ComputerName)
Get-WmiObject Win32_LogicalDisk -ComputerName $ComputerName
}
Evita reinventar la rueda
Utiliza cmdlets integrados como Test-Connection
en lugar de crear funciones personalizadas.
# Recomendado
Test-Connection $ComputerName -Quiet
Escritura de Bloques de Parámetros
Escribe siempre la ayuda
Incluye ayuda basada en comentarios con .SYNOPSIS
, .DESCRIPTION
y al menos un .EXAMPLE
.
function Test-Help {
<#
.SYNOPSIS
Demuestra documentación de ayuda adecuada.
.EXAMPLE
Test-Help -MandatoryParameter "Ejemplo"
Ejecuta la función Test-Help con un parámetro obligatorio.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[Alias("MP")]
[String]$MandatoryParameter
)
}
Usa [CmdletBinding()]
Activa parámetros comunes como -Verbose
, -Debug
, -ErrorAction
.
Soporta -WhatIf y -Confirm
Para comandos que cambian el estado, usa SupportsShouldProcess
.
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Medium")]
param ([switch]$Force)
Define tipos fuertes en los parámetros
Especifica siempre los tipos para validación y claridad.
param (
[string]$Name,
[int]$Count
)
Usa [switch] correctamente
- Por defecto es
$false
. - Úsalo como booleano, evitando lógica de tres estados.
Formateo de Salida
Evita Write-Host salvo que sea necesario
Prefiere Write-Verbose
, Write-Debug
o Write-Output
según corresponda.
Usa Write-Progress para mostrar avances
Write-Progress -Activity "Procesando" -Status "50% Completado" -PercentComplete 50
Usa archivos de formato para objetos personalizados
Define archivos .format.ps1xml
en lugar de formateo inline.
Devuelve solo un tipo de objeto a la vez
Utiliza [OutputType()]
y evita mezclar tipos de objetos.
Mejores Prácticas de Manejo de Errores
Usa -ErrorAction Stop con cmdlets
Forzar errores para manejarlos con try-catch
.
try {
Get-Item "C:\RutaInvalida" -ErrorAction Stop
} catch {
Write-Warning "Elemento no encontrado."
}
Usa $ErrorActionPreference para operaciones fuera de cmdlets
Configúralo temporalmente a 'Stop'
en operaciones críticas.
Evita usar flags y $? para manejo de errores
Prefiere bloques estructurados try-catch
.
Copia $Error[0] o $_ inmediatamente dentro de catch
catch {
$errorDetails = $_
Write-Error "Ocurrió un error: $($errorDetails.Exception.Message)"
}
Optimización del Rendimiento
PERF-01 Mide el rendimiento cuando sea necesario
Utiliza Measure-Command
para comparar métodos.
Measure-Command {
foreach ($item in $data) { Process-Item $item }
}
PERF-02 Equilibra rendimiento y legibilidad
- Para pequeños conjuntos de datos, prioriza la legibilidad.
- Para grandes volúmenes, considera streaming o técnicas con .NET.
Legible pero menos eficiente:
$content = Get-Content -Path file.txt
foreach ($line in $content) {
Do-Something -Input $line
}
Optimizado para rendimiento:
Get-Content -Path file.txt | ForEach-Object {
Do-Something -Input $_
}
Alto rendimiento con .NET:
$sr = New-Object System.IO.StreamReader "file.txt"
while ($sr.Peek() -ge 0) {
$line = $sr.ReadLine()
Do-Something -Input $line
}
PERF-03 Prefiere características del lenguaje sobre cmdlets
- Construcciones del lenguaje (
foreach
) > Métodos .NET > Scripts > Cmdlets/Pipeline. - Mide siempre antes de optimizar.
Mejores Prácticas de Seguridad
Usa siempre PSCredential para credenciales
Evita contraseñas en texto plano. Utiliza parámetros [Credential()]
.
param (
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential
)
Al pasar a APIs:
$Insecure.SetPassword($Credential.GetNetworkCredential().Password)
Usa SecureString para datos sensibles
Solicita datos de forma segura y almacénalos cifrados.
$Secure = Read-Host -Prompt "Introduce datos seguros" -AsSecureString
Conversión segura a texto plano:
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Secure)
$PlainText = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
Guarda credenciales de forma segura
Utiliza Export-CliXml
.
Get-Credential | Export-CliXml -Path C:\secure\cred.xml
$Credential = Import-CliXml -Path C:\secure\cred.xml
Guarda cadenas cifradas
ConvertFrom-SecureString -SecureString $Secure | Out-File -Path "${Env:AppData}\secure.bin"
$Secure = Get-Content -Path "${Env:AppData}\secure.bin" | ConvertTo-SecureString
Conclusión
Aplicando estas mejores prácticas en diseño, documentación, manejo de salida, errores, rendimiento y seguridad, podrás crear scripts de PowerShell robustos, eficientes y fáciles de mantener. Busca siempre el equilibrio entre legibilidad, rendimiento y seguridad para entregar soluciones de automatización de alta calidad.