Saltar al contenido principal

Pipelines I: PowerShell declarativo

Metadatos de la lección

Autoría:
Ignacio Slater-Muñoz
Última actualización:
27 de marzo de 2026

Cambios recientes:

  • 8880728 · 27 de marzo de 2026 · ✨ feat(notes): add abstract slots and Python structured-output lesson ( GitLab / GitHub )
  • 0b7190d · 26 de marzo de 2026 · 📚🐛 feat(scripting): add Nushell pipelines lesson and unblock checks ( GitLab / GitHub )
  • 4443cc6 · 12 de marzo de 2026 · ✨♻️ feat(references): refine catalog-driven bibliography rendering ( GitLab / GitHub )

Abstract

En PowerShell, el pipeline es un modelo de trabajo orientado a objetos: cada cmdlet recibe datos estructurados, los procesa y entrega resultados al siguiente paso.

En esta lección practicarás cómo componer pipelines declarativos para filtrar, proyectar y transformar datos, manteniendo el foco en el flujo de objetos desde la fuente hasta la salida.

Pensar en pasos: de colecciones al pipeline de PowerShell

Antes de hablar del pipeline, observemos cómo procesamos colecciones en otros paradigmas. En muchos lenguajes (funcionales, orientados a objetos o incluso SQL), aplicamos una secuencia de transformaciones: filtrar, transformar y limitar.

Transformaciones encadenadas

Una transformación recibe una entrada y produce una salida. Al encadenarlas, describes qué quieres hacer con los datos (flujo), no cómo recorrerlos (bucle).

Mismo flujo, distintos lenguajes

Colecciones con operaciones encadenadas (Scala)
users                   // : List[User]
    .filter(_.active)   // : List[User]
    .map(_.email)       // : List[String]
    .distinct           // : List[String]
    .take(10)           // : List[String]
Colecciones con funciones de orden superior (Python)
list(
    islice(
        dict.fromkeys(
            map(
                lambda u: u.email,
                filter(
                    lambda u: u.active,
                    users # <class 'list'>
                ) # <class 'filter'>
            ) # <class 'map'>
        ), # <class 'dict'>
        10
    ) # <class 'itertools.islice'>
) # <class 'list'>
Consulta declarativa (SQL)
SELECT DISTINCT email
FROM users
WHERE active = TRUE
LIMIT 10;

Algunos lenguajes hacen estas transformaciones más explícitas y legibles que otros. En este ejemplo, Python mantiene el mismo modelo mental, pero con una carga sintáctica mayor.

Aunque la sintaxis cambia, la idea es siempre la misma:

Estás describiendo una cadena de transformaciones sobre un flujo de datos.

  • Quedarse solo con los elementos que cumplen una condición.
  • Extraer un dato relevante de cada elemento.
  • Eliminar duplicados.
  • Limitar la cantidad de resultados.

Puedes imaginarlo como una cadena de transformaciones: datos -> filtrar -> proyectar -> eliminar duplicados -> limitar.

¿Dónde entra PowerShell?

El pipeline de PowerShell expresa exactamente la misma idea, pero en lugar de encadenar métodos o funciones, conecta comandos que procesan objetos.

Cada comando:

  • Streaming: cada objeto fluye hacia el siguiente comando en cuanto está disponible (no espera a evaluar toda la colección).
  • Operador | : conecta la salida de un cmdlet con la entrada del siguiente.

El mismo flujo expresado como pipeline

Pipeline en PowerShell
Import-Csv users.csv |
    Where-Object { $_.active -eq 'true' } |
    Select-Object -ExpandProperty email |
    Sort-Object -Unique |
    Select-Object -First 10

Detalles clave

  • | conecta pasos: no es “texto” — son objetos tipados los que fluyen entre comandos.
  • Filtrar temprano: igual que en SQL o FP, reduces trabajo en los pasos siguientes del pipeline.
  • Procesamiento incremental: PowerShell no necesita cargar todo en memoria para empezar a trabajar.
  • El último comando decide cómo se muestran los resultados.

Cmdlets comunes en el pipeline

Una vez que entiendes el pipeline como una secuencia de transformaciones, el siguiente paso es conocer los cmdlets más comunes que aparecen en casi cualquier flujo de PowerShell.

No se trata de memorizar comandos, sino de reconocer roles: filtrar, transformar, ordenar, limitar y proyectar datos.

Filtrar objetos

Filtrar por condición
Get-Process | Where-Object { $_.CPU -gt 100 }
Nota: la propiedad CPU representa el tiempo total de CPU consumido por el proceso (en segundos), no un porcentaje de uso.

Detalles clave

  • Get-Process es un cmdlet de origen : consulta al sistema operativo y produce un flujo de objetos, uno por cada proceso en ejecución.
  • Where-Object recibe los objetos del pipeline uno a uno y evalúa una condición booleana para cada uno. Where-Object no modifica los objetos: decide cuáles continúan en el pipeline y cuáles se descartan.
  • Dentro del bloque { ... }, la variable automática $_ representa el objeto actual que está pasando por el pipeline. En este ejemplo, $_ es un objeto de tipo [System.Diagnostics.Process] .

Conceptualmente, este paso equivale a un filter en programación funcional o a una cláusula WHERE en SQL: describe qué procesos te interesan, no cómo recorrer la colección de procesos manualmente.

Proyectar y limitar

Seleccionar propiedades y limitar resultados
Get-Service | Select-Object -Property Name, Status -First 10

Detalles clave

  • Get-Service es un cmdlet de origen que consulta al sistema operativo y produce un flujo de objetos, uno por cada servicio.
  • Select-Object es el cmdlet principal para proyectar datos en el pipeline: permite elegir qué propiedades de cada objeto se mantienen en el resultado que continúa fluyendo en el pipeline.
    • La opción -Property Name, Status indica que solo nos interesan esas dos propiedades. El resultado no es el objeto original, sino un nuevo objeto que contiene únicamente esas propiedades. En la mayoría de los casos, PowerShell crea un objeto de tipo [PSCustomObject] .
    • La opción -First 10 limita el número de objetos que continúan fluyendo en el pipeline. Una vez alcanzado ese límite, el pipeline deja de producir más objetos. Esto es equivalente a un LIMIT en SQL. Limitar resultados temprano en el pipeline puede reducir el trabajo de los comandos siguientes.

Conceptualmente, este paso equivale a: SELECT Name, Status FROM services LIMIT 10 en SQL, o a un map que extrae solo ciertas propiedades de cada objeto en programación funcional. De nuevo, describes qué quieres obtener de cada objeto, no cómo recorrer la colección manualmente.

Proyectar vs expandir propiedades

Select-Object no solo cambia cómo se muestran los datos: también puede transformar la estructura del objeto que continúa fluyendo en el pipeline.

  • Select-Object -Property Name mantiene un objeto proyectado con la propiedad seleccionada.
  • Select-Object -ExpandProperty Name expande la propiedad y emite su valor directamente.

Ejemplo

Proyección
Get-Service |
    Select-Object -First 2 -Property Name |
    Format-List
Output
Name: AppMgmt
Name: AppVClient
Expansión
Get-Service |
    Select-Object -First 2 -ExpandProperty Name |
    Format-List
Output
AppMgmt
AppVClient

En el primer caso, el pipeline sigue transportando objetos con una propiedad Name . En el segundo caso, el pipeline emite directamente los valores de esa propiedad (cadenas de texto).

Transformar con ForEach-Object

Mientras Select-Object solo elige o expande propiedades existentes, ForEach-Object permite crear nuevos datos a partir de cada objeto (similar a map).

Transformar y enriquecer objetos
Get-ChildItem -Path . -File -Filter *.mp4 |
    ForEach-Object {
        [PSCustomObject]@{
            Name   = $_.Name
            SizeKB = [math]::Round($_.Length / 1KB, 2)
        }
    } |
    Sort-Object -Property SizeKB -Descending |
    Select-Object -First 10

Detalles clave

  • Get-ChildItem produce un flujo de objetos del sistema de archivos (como instancias de [FileInfo] ). Aquí limitamos a archivos con -File y al patrón -Filter *.mp4 .
  • ForEach-Object aplica un bloque a cada objeto del pipeline. Conceptualmente, se parece a map en programación funcional: por cada objeto que entra al pipeline, el bloque produce un resultado que continúa fluyendo. PowerShell ejecuta este bloque a medida que los objetos van llegando al pipeline; no necesita esperar a que toda la colección esté disponible.
  • Dentro del bloque, $_ vuelve a representar el objeto actual (en este caso, un archivo). Usamos sus propiedades Name y Length para calcular el tamaño en KB y construir una representación más útil del archivo.
  • El bloque devuelve un [PSCustomObject] , es decir, un objeto nuevo con propiedades explícitas. Esto mantiene el pipeline estructurado: los comandos siguientes reciben objetos con propiedades claras, en lugar de tener que interpretar texto.
  • Composición: observa cómo el pipeline fluye de la transformación hacia el ordenamiento y finalmente a la limitación.

Ejercicio: Transformar datos JSON con pipelines

Requisitos

Un uso común de PowerShell es el procesamiento y análisis de datos, especialmente en tareas de exploración y análisis de datos. Para eso necesitas poder leer y escribir objetos (serialización) en formatos estándar como JSON, CSV o XML. PowerShell incluye cmdlets que serializan y deserializan datos y que se integran naturalmente con el pipeline.

En este ejercicio practicarás un flujo típico: «texto → objetos → transformaciones → texto» . La regla es simple: trabaja con objetos hasta el último paso y solo convierte a texto cuando necesites escribir o exportar datos.

Supón que tienes un archivo users.json con una lista de usuarios con esta estructura:

[
    { "name": "Isaac", "email": "isaac@example.com", "active": true },
    { "name": "Miria", "email": "miria@example.com", "active": false }
]

Tu tarea es:

  • Filtrar solo los usuarios con active en true.
  • Transformar cada usuario a un objeto con solo name y email, ambos en mayúsculas.
  • Guardar el resultado en un nuevo archivo active-users.json.

Notas

  • ConvertFrom-Json toma texto JSON y lo convierte en objetos de PowerShell con propiedades accesibles.
  • ConvertTo-Json serializa objetos de PowerShell y produce texto JSON. En estructuras anidadas puede ser necesario aumentar la profundidad con -Depth .
  • Set-Content escribe texto en un archivo (creándolo o reemplazándolo).

Uso esperado

Pipeline base
Get-Content 'users.json' -Raw |
    ConvertFrom-Json |
    ... | # Tu código aquí: filtra y transforma objetos
    ConvertTo-Json |
    Set-Content 'active-users.json'

Solución

Get-Content 'users.json' -Raw |
    ConvertFrom-Json |
    Where-Object { $_.active } |
    ForEach-Object {
        [PSCustomObject]@{
            name  = $_.name.ToUpper()
            email = $_.email.ToUpper()
        }
    } |
    ConvertTo-Json -Depth 3 |
    Set-Content 'active-users.json'

Este pipeline lee el archivo como texto, lo convierte a objetos, aplica filtrado y transformación, vuelve a serializar a JSON, y finalmente guarda el resultado. El flujo principal es filtrar → transformar → serializar. El trabajo principal ocurre sobre objetos, no sobre strings.

Conclusiones

El pipeline de PowerShell no es solo sintaxis: es una forma de diseñar soluciones basada en etapas de transformación. Cada etapa toma objetos con propiedades claras y produce nuevos resultados que continúan fluyendo.

Pensar en roles (filtrar, proyectar, transformar, ordenar y limitar) ayuda a separar intención y mecanismo: primero defines qué resultado necesitas, luego dejas que el pipeline resuelva cómo recorrer los datos.

Puntos clave

  • El pipeline transporta objetos tipados, no texto.
  • Filtra temprano con Where-Object para reducir el trabajo en los pasos siguientes.
  • Proyecta lo necesario con Select-Object y limita con -First cuando puedas.
  • Transforma con ForEach-Object para construir objetos derivados a partir de cada entrada.
  • Decide el formato al final: exporta/serializa solo en la última etapa.

¿Qué nos llevamos?

Diseñar pipelines claros mejora la calidad técnica del trabajo: facilita leer, mantener y validar cada etapa de procesamiento.

Como criterio práctico, conserva la regla central de la lección: trabaja con objetos durante el pipeline y convierte a texto solo cuando necesites serializar o exportar resultados.

¿Con ganas de más?

Referencias adicionales

  • Collection Pipeline en martinfowler.com por Martin Fowler
    Artículo fundacional sobre el patrón Collection Pipeline: cómo encadenar operaciones declarativas (map, filter, reduce, group-by) para transformar colecciones. Compara sintaxis en múltiples lenguajes (Ruby, Clojure, Smalltalk), explora alternativas (loops, comprehensions), y discute temas avanzados como laziness, paralelismo e inmutabilidad. Incluye un catálogo detallado de operaciones comunes con ejemplos visuales.