Búsqueda de sitios web

Pipeline-Ready: funciones avanzadas de PowerShell


style="letter-spacing: 0px; text-transform: unset; background-color: transparent;">Trabajar con la canalización de PowerShell es eficiente. ¿Quiere obtener más información sobre la canalización? En esta publicación de blog, Philip Lorenz profundiza en el tema.

Introducción

La canalización es un concepto central en PowerShell que permite pasar la salida de una función o cmdlet como entrada a otra. Esto crea un método flexible y eficiente de procesamiento de datos al permitir encadenar tareas individuales y bien definidas. El principio "uno a la vez" permite procesar grandes cantidades de datos con un uso eficiente de los recursos. En el artículo "Trabajar de manera eficiente con la canalización de PowerShell: una guía para administradores", ya le mostré cómo puede usar la canalización para encadenar cmdlets existentes. En esta publicación de blog, le mostraré cómo preparar sus propias funciones para la canalización.

Integrar el soporte de canalización en sus propias funciones no solo es una buena práctica, sino que también amplía la funcionalidad y la reutilización del código. Proporcionar soporte de canalización en sus propias funciones requiere una comprensión de los mecanismos de canalización y la aplicación de parámetros y técnicas de procesamiento adecuados. A lo largo de este artículo, explicaremos estos conceptos, desde funciones rudimentarias hasta funciones avanzadas, e ilustraremos cómo puede maximizar la eficiencia de la canalización en sus scripts.

Conceptos básicos de soporte de canalización

Para utilizar la canalización en PowerShell de forma eficaz, es importante comprender algunos conceptos básicos. Dos elementos clave aquí son la palabra clave de filtro y la variable especial $_. Desempeñan un papel crucial cuando se trata de crear una función simple que brinde soporte para la canalización.

La palabra clave de filtro en PowerShell permite crear un tipo de función diseñada específicamente para procesar la entrada de canalización. Un filtro toma información de la canalización, la procesa y devuelve algo a la canalización. La variable $_ representa el objeto actual en la canalización que se está procesando. Aquí hay una función simple que muestra cómo se pueden usar la palabra clave de filtro y la variable $_:

Filter Convert-ToUpperCase {
  Write-Output "Input in uppercase: $($_.ToUpper())"
}

En este ejemplo, hemos creado un filtro llamado Convert-ToUpperCase. Este filtro toma entradas de texto de la canalización y, para cada entrada, se llama al método ToUpper para convertir el texto a mayúsculas. También hay una salida directa a la consola. Si utiliza este filtro en una canalización, cada entrada de texto se procesa individualmente y se reenvía a la salida en letras mayúsculas:

"hello", "world" | Convert-ToUpperCase

La salida sería:

Input in uppercase: HELLO
Input in uppercase: WORLD

Usar filtros y $_ es una forma sencilla y eficaz de integrar el soporte de canalización en sus funciones. Proporciona una forma clara y fácil de entender de tomar objetos de la canalización, procesarlos y transmitirlos, lo que forma la base para funciones y operaciones de canalización más complejas.

En la siguiente sección, veremos Parámetros con nombre y crearemos una función avanzada que va más allá del alcance de una función simple y proporciona más formas de interactuar con la canalización.

Funciones avanzadas con parámetros con nombre

Si bien las funciones y filtros simples son suficientes para muchas tareas, las funciones avanzadas de PowerShell permiten un mayor control y flexibilidad, especialmente cuando se trata de trabajar con canalizaciones. Una de las claves de esta funcionalidad avanzada son los parámetros con nombre.

Parámetros con nombre

Los Parámetros con nombre nos permiten controlar la entrada de datos de forma estructurada y comprensible. No solo puede especificar tipos para los parámetros de entrada, sino que también puede definir valores predeterminados y agregar validaciones.

A continuación se muestra un ejemplo de una función avanzada con parámetros con nombre:

function Get-ModifiedFiles {
    param (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]$Path,
        
        [datetime]$Since
    )
    
    process {
        $files = Get-ChildItem -Path 
        $Path -Recurse | 
        Where-Object { $_.LastWriteTime -gt $Since }
        $files
    }
}

En esta función Get-ModifiedFiles, hemos definido dos parámetros con nombre: $Path y $Since. El parámetro $Path es obligatorio y acepta entradas de la canalización, mientras que $Since es opcional. En el bloque de proceso, usamos Get-ChildItem para obtener todos los archivos en la ruta especificada y Where-Object para filtrar los archivos que se modificaron después de la fecha especificada.

Aquí hay una llamada ejemplar:

"./" | Get-ModifiedFiles -Since (Get-Date).AddDays(-7)

Producción :

En esta llamada, el directorio actual se pasa a la función Get-ModifiedFiles como una cadena simple y se devuelven todos los archivos que se han modificado en los últimos siete días.

Los parámetros con nombre proporcionan una forma clara y explícita de controlar las entradas de la función y permiten un control más preciso sobre el procesamiento de datos dentro de la función.

En el próximo capítulo, veremos la estructuración de funciones con los bloques Begin, Process, End y Clean.

Estructuración de funciones con bloques Begin, Process, End y Clean

La estructuración de funciones con los bloques Begin, Process, End y el bloque Clean recientemente introducido en PowerShell 7.3 proporciona un método sólido para procesar datos de canalización y limpiar recursos. Estos bloques permiten dividir el código en segmentos lógicos que se llaman en diferentes momentos durante la ejecución de la función.

  • El bloque Begin se ejecuta una vez al inicio de la función y es adecuado para acciones de inicialización.
  • El bloque Proceso se ejecuta para cada objeto que pasa a través de la canalización y es la ubicación principal para el procesamiento de datos.
  • El bloque End se ejecuta una vez después de que se hayan procesado todos los objetos de la canalización y es adecuado para acciones finales.

El bloque Limpiar, introducido en PowerShell 7.3, proporciona una manera de limpiar los recursos que abarcan los bloques Inicio, Proceso y Fin. Semánticamente, es similar a un bloque Finalmente y cubre todos los demás bloques con nombre de una función. La limpieza de recursos se aplica en varios escenarios, como cuando la ejecución de la canalización se completa normalmente, se interrumpe por un error de terminación, se detiene con Select-Object -First o se finaliza con CTRL+C o StopProcessing.().

Aquí hay un ejemplo que demuestra el uso de todos los bloques:

function Get-Size {
  param (
      [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
      [string]$Path
  )

  begin {
      # Initializing variables
      $totalSize = 0
      $tempDirectory = "./tmp"

      # Initialization: Creating temporary directory
      if (-not (Test-Path $tempDirectory)) {
          New-Item -Path $tempDirectory -ItemType Directory | Out-Null
      }
  }

  process {
      # Checking if the path exists and is a file
      if (Test-Path $Path -PathType Leaf) {
          $fileInfo = Get-Item $Path          $fileSize = $fileInfo.Length
          $totalSize += $fileSize

          # Writing file information to a temporary file
          $outputPath = Join-Path $tempDirectory ($fileInfo.Name + ".txt")
          $fileInfo | Out-File $outputPath
      }
  }
  end {
      # Outputting the total size of all processed files
      Write-Output "Total size of all processed files: $($totalSize / 1MB) MB"
  }

  clean {
      # Deleting temporary directory
      Remove-Item $tempDirectory -Recurse -Force
  }
}
  • Begin crea un directorio temporal que se utiliza durante el procesamiento.
  • El bloque Proceso comprueba si la ruta pasada es un archivo, recopila información sobre el archivo, actualiza el tamaño total y almacena la información del archivo en un archivo temporal.
  • El bloque End genera el tamaño total de todos los archivos procesados.
  • El bloque Limpiar elimina el directorio temporal una vez completado el procesamiento para garantizar que no queden datos no deseados.

Ejecute el siguiente código:

$files = @()
$files += "/Users/philip/Code/blog-post-code-examples/blog.docx"
$files += "/Users/philip/Code/blog-post-code-examples/image.dmg"
$files | Get-Size

Y obtenga el siguiente resultado:

Total size of all processed files: 615.562695503235 MB

Al utilizar los bloques Begin, Process, End y Clean, la función está estructurada y permite un procesamiento y limpieza eficientes.

Implementación de ByPropertyName en funciones propias

Hasta ahora, nos hemos ocupado de pasar valores ByValue a funciones. Sin embargo, PowerShell también ofrece la opción de pasar valores ByPropertyName. Esto permite una interacción más flexible e intuitiva con las funciones.

Por nombre de propiedad frente a por valor

  • ByValue: Aquí, el valor de un argumento se pasa directamente al parámetro correspondiente de la función. Esto es sencillo, pero puede generar confusión en situaciones donde las relaciones de los parámetros no están claras.
  • ByPropertyName: con este método, el valor de un argumento se pasa en función del nombre del parámetro. Esto puede resultar especialmente útil si la función tiene muchos parámetros o si la función se usa en una canalización donde la salida del cmdlet anterior se usa como entrada para el siguiente cmdlet.

A continuación se muestra un ejemplo para demostrar la implementación de ByPropertyName:

function Get-FileDetail {
    param (
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [string]$FullName
    )
    
    process {
        $fileInfo = Get-Item $FullName
        $fileDetail = @{
            Name = $fileInfo.Name
            Size = $fileInfo.Length
            LastModified = $fileInfo.LastWriteTime
        }
        $fileDetail
    }
}

Get-ChildItem -Path "./" | Get-FileDetail

En la consola se muestra lo siguiente:

En la función Get-FileDetail hemos definido el parámetro $FullName con el atributo ValueFromPipelineByPropertyName=$true. Esto permite que la función acepte valores de la canalización que se asignan según el nombre del parámetro $FullName. En la llamada de ejemplo, la salida de Get-ChildItem se reenvía a Get-FileDetail, donde se encuentra la propiedad FullName de los objetos de salida de Get-ChildItem se asigna al parámetro $FileName de Get-FileDetail.

Al utilizar ByPropertyName, las funciones se pueden usar de manera más intuitiva y flexible en las canalizaciones, y la asignación de valores de entrada a las funciones se vuelve más transparente.

En el siguiente párrafo, veremos la variable automática $Input, que proporciona otra forma de procesar la entrada de la canalización, especialmente si la entrada se va a tratar como un bloque en lugar de como elementos individuales.

La variable automática $Input

Si bien muchos desarrolladores de PowerShell están familiarizados con la variable $_ pipeline, $Input es menos conocida pero proporciona una funcionalidad valiosa en ciertos escenarios.

La variable $Input permite tratar toda la entrada de la canalización como un enumerador. Esto significa que en lugar de procesar cada elemento de la canalización por turno, puede acceder a toda la entrada como un todo. Esto puede resultar útil en escenarios en los que desee tratar la entrada como un bloque, p. al ordenar o agrupar datos.

Es importante tener en cuenta que $Input es un enumerador y no se puede utilizar directamente como una matriz. Para usar $Input como una matriz real, puede incluirla en @().

Aquí hay un ejemplo simple:

function Sort-InputData {
    process {
        $dataArray = @($Input)
        $sortedData = $dataArray | Sort-Object
        $sortedData
    }
}

# Beispielaufruf
1, 5, 3, 4, 2 | Sort-InputData

En esta función Soft-InputData, primero recopilamos todas las entradas de la canalización en una matriz $dataArray y luego ordenamos estos datos. El resultado es una lista ordenada de números.

¿Cuándo utilizar $Input?

Usar $Input es particularmente útil cuando desea realizar múltiples operaciones en toda la entrada de la canalización sin procesar cada valor individualmente. Sin embargo, es importante comprender la diferencia entre $Input y $_ y elegir la variable correcta para el escenario.

Conclusión

Las canalizaciones de PowerShell son sin duda una de las características más importantes de PowerShell. Su capacidad para transferir datos de manera eficiente y fluida entre diferentes cmdlets y funciones los distingue de otros lenguajes de secuencias de comandos. Para cualquier profesional de TI que busque automatizar tareas complejas y optimizar flujos de trabajo, son una herramienta indispensable.

Artículos relacionados