El canal de PowerShell es una de las características más importantes (y útiles) de la shell y lenguaje de scripting de PowerShell. Una vez que comprendas los conceptos básicos de cómo funciona y de lo que es capaz, podrás aprovechar su potencia en tus propias funciones. ¡En este tutorial, eso es exactamente lo que vas a hacer!
El canal de PowerShell te permite encadenar comandos para construir un ‘conducto’ único que simplifica el código, permite el procesamiento en paralelo y más. Si estás listo para aprender sobre el canal y construir tus propias funciones para aprovecharlo, ¡comencemos!
Prerrequisitos
Este artículo será un tutorial y consistirá en demostraciones prácticas. Si quieres seguir el tutorial, necesitarás PowerShell v3 o superior. Este tutorial utilizará Windows PowerShell v5.1.
Entendiendo el Canal de PowerShell
La mayoría de los comandos de PowerShell reciben alguna entrada a través de un parámetro. El comando recibe algún objeto como entrada y hace algo con él en su interior. Luego, opcionalmente, devuelve algún objeto como salida.
Los comandos en un canal actúan como corredores humanos en una carrera de relevos. Cada corredor en la carrera, excepto el primero y el último, acepta el testigo (objetos) de su predecesor y se lo pasa al siguiente.
Por ejemplo, el cmdlet Stop-Service
tiene un parámetro llamado InputObject
. Este parámetro te permite pasar un tipo específico de objeto a Stop-Service
que representa el servicio de Windows que deseas detener.
Para usar el parámetro InputObject
, podrías recuperar el objeto del servicio a través de Get-Service
y luego pasar el objeto al parámetro InputObject
como se muestra a continuación. Este método de proporcionar entrada al cmdlet Stop-Service
a través del parámetro InputObject
funciona muy bien y hace el trabajo.
Este método de pasar entrada al comando Stop-Service
requiere dos pasos distintos. PowerShell debe ejecutar Get-Service
primero, guardar la salida en una variable y luego pasar ese valor a Stop-Service
a través del parámetro InputObject
.
Ahora, contrae el fragmento anterior con el siguiente fragmento, que hace lo mismo. Es mucho más simple porque no tienes que crear una variable $services
ni siquiera usar el parámetro InputObject
en absoluto. En cambio, PowerShell “sabe” que pretendes usar el parámetro InputObject
. Lo hace a través de un concepto llamado enlace de parámetros.
Ahora has “encadenado” comandos con el operador |
. Has creado una cadena de comandos.
Pero, no tienes que usar solo dos comandos para crear una cadena de comandos; puedes encadenar tantos como desees (si los parámetros del comando lo admiten). Por ejemplo, el siguiente fragmento de código:
- Pasa todos los objetos que devuelve el cmdlet
Get-Service
al cmdletWhere-Object
. - Luego, el cmdlet
Where-Object
examina la propiedadStatus
de cada objeto y devuelve solo aquellos objetos con un valor deRunning
. - Luego, cada uno de esos objetos se envía a
Select-Object
, que solo devuelve las propiedadesName
yDisplayName
de los objetos. - Dado que ningún otro cmdlet acepta los objetos que produce
Select-Object
, el comando devuelve los objetos directamente a la consola.
Los cmdlets
Where-Object
ySelect-Object
entienden cómo procesar la entrada del pipeline mediante un concepto llamado asignación de parámetros, que se discute en la siguiente sección.
Para obtener información adicional sobre los pipelines, ejecute el comando
Get-Help about_pipelines
.
Asignación de Parámetros del Pipeline
A primera vista, el pipeline puede parecer trivial. Después de todo, solo está pasando objetos de un comando a otro. Pero en realidad, el pipeline es mucho más complicado. Los comandos aceptan entrada solo a través de parámetros. El pipeline debe averiguar de alguna manera qué parámetro usar incluso cuando no lo defines explícitamente.
La tarea de determinar qué parámetro usar cuando un comando recibe entrada a través del canal es conocida como enlace de parámetros. Para vincular con éxito un objeto que llega desde el canal a un parámetro, el/los parámetro(s) del comando entrante deben admitirlo. Los parámetros del comando admiten el enlace de parámetros del canal de una de dos maneras; PorValor
y/o PorNombreDePropiedad
.
PorValor
El parámetro del comando acepta el objeto completo que llega como valor del parámetro. Un parámetro PorValor
busca un objeto de un tipo específico en los objetos entrantes. Si ese tipo de objeto coincide, PowerShell asume que el objeto está destinado a ser vinculado a ese parámetro y lo acepta.
El cmdlet
Get-ChildItem
tiene un parámetro llamadoRuta
que acepta un tipo de objeto de cadena y entrada de canal a través dePorValor
. Debido a esto, ejecutar algo como'C:\Windows' | Get-ChildItem
devuelve todos los archivos en el directorio C:\Windows porqueC:\Windows
es una cadena.
PorNombreDePropiedad
El parámetro del comando no acepta un objeto completo sino una única propiedad de ese objeto. Hace esto no mirando el tipo de objeto sino el nombre de la propiedad.
El cmdlet
Get-Process
tiene un parámetroName
configurado para aceptar entrada de canalizaciónByPropertyName
. Cuando pasa un objeto con una propiedadName
al cmdletGet-Process
como[pscustomobject]@{Name='firefox'} | Get-Process
, PowerShell hace coincidir o enlaza la propiedadName
en el objeto entrante con el parámetroName
y utiliza ese valor.
Descubrir los parámetros del comando que admiten la canalización
Como se mencionó anteriormente, no todos los comandos admiten entrada de canalización. El autor del comando debe crear esa funcionalidad en el desarrollo. El comando debe tener al menos un parámetro que admita la canalización, poner ByValue
o ByPropertyName
.
¿Cómo sabes qué comandos y sus parámetros admiten entrada de canalización? Podrías intentarlo con ensayo y error, pero hay una mejor manera con el sistema de ayuda de PowerShell usando el comando Get-Help
.
Por ejemplo, echa un vistazo al parámetro Path
del cmdlet Get-ChildItem
a continuación. Puedes ver que admite ambos tipos de entrada de canalización.

Una vez que sepas qué parámetros de comando admiten la entrada de canalización, puedes aprovechar esa funcionalidad, como se muestra a continuación.
Sin embargo, el parámetro DisplayName
en Get-Service
no admite la entrada de canalización.

Creación de tu propia función de canalización
Aunque los cmdlets estándar de PowerShell admiten la entrada de canalización, no significa que no puedas aprovechar esa funcionalidad. Afortunadamente, también puedes crear funciones que acepten la entrada de canalización.
Para demostrar, comencemos con una función existente llamada Get-ConnectionStatus
.
- Esta función tiene un solo parámetro (que no acepta entrada de canalización) llamado
ComputerName
, que te permite pasar uno o más cadenas a él. Puedes decir que el parámetroComputerName
no acepta entrada de canalización porque no está definido como un atributo de parámetro ([Parameter()]
). - Luego, la función lee cada una de esas cadenas y ejecuta el cmdlet
Test-Connection
contra cada una. - Para cada nombre de computadora pasado, luego devuelve un objeto con una propiedad
ComputerName
y una propiedadStatus
.
Luego, deberá invocar Get-ConnectionStatus
pasando el parámetro ComputerName
con uno o más nombres de host o direcciones IP como se muestra a continuación.
Paso 1: Permitir entrada de canalización
Para que esta función acepte entrada de canalización, primero debe definir el atributo de parámetro apropiado. Este atributo puede ser ValueFromPipeline
para aceptar entrada de canalización por valor o ValueFromPipelineByPropertyName
para aceptar entrada de canalización por nombre de propiedad.
Para este ejemplo, agregue el atributo de parámetro ValueFromPipeline
dentro de los corchetes de la definición [Parameter()]
como se muestra a continuación.
En este punto, eso es todo lo que tienes que hacer técnicamente. La función Get-ConnectionStatus
ahora enlazará cualquier objeto de cadena pasado a él al parámetro ComputerName
. Pero, incluso si se está produciendo el enlace de parámetros, no significa que la función hará algo significativo con él.
Paso 2: Agregar un bloque de proceso
Cuando desee que PowerShell procese todos los objetos que provienen de la canalización, debe agregar un bloque Process
. Este bloque indica a PowerShell que procese cada objeto que proviene de la canalización.
Sin un bloque
Process
, PowerShell solo procesará el primer objeto que provenga de la canalización. El bloqueProcess
indica a PowerShell que continúe procesando objetos.
Agrega un bloque Process
como se muestra a continuación, encerrando toda la funcionalidad de la función.
Siempre envía la salida desde dentro del bloque
Process
. Enviar la salida desde dentro del bloqueProcess
“transmite” los objetos hacia la canalización, permitiendo que otros comandos acepten esos objetos desde la canalización.
Pasando Objetos a la Canalización de PowerShell
Una vez que tengas definido un bloque Process
en la función anterior, ahora puedes llamar a la función pasando valores al parámetro ComputerName
a través de la canalización como se muestra a continuación.
En este punto, puedes aprovechar el verdadero poder de la canalización y comenzar a incorporar más comandos en la mezcla. Por ejemplo, quizás tengas un archivo de texto, C:\Test\computers.txt, con una línea de direcciones IP separadas por una nueva línea como se muestra a continuación.
Luego podrías usar el cmdlet Get-Content
para leer cada una de esas direcciones IP en el archivo de texto y pasarlas directamente a la función Get-ConnectionStatus
.
Llevando esta configuración un paso más allá, podrías pasar los objetos que devuelve Get-ConnectionStatus
directamente al cmdlet ForEach-Object
.
El código a continuación:
- Lee todos los nombres de computadoras en el archivo de texto y los pasa a la función
Get-ConnectionStatus
. Get-ConnectionStatus
procesa cada nombre de computadora y devuelve un objeto con las propiedadesComputerName
yStatus
.Get-ConnectionStatus
luego pasa cada objeto al cmdletForEach-Object
, que devuelve una cadena única coloreada de cian con un estado legible para humanos.
Si la entrada de la canalización no estaba habilitada en el parámetro
ComputerName
o siGet-ConnectionStatus
no devolvía un objeto dentro del bloqueProcess
, PowerShell no mostraría ningún estado en la consola hasta que se procesen todos los objetos (direcciones IP).
Asociación de canalización por nombre de propiedad
Hasta ahora, el cmdlet Get-ConnectionStatus
está configurado para aceptar la entrada de la canalización por valor (ValueFromPipeline
) al aceptar una matriz de cadenas como '127.0.0.1', '192.168.1.100'
. ¿Esta función también funcionaría como se espera si la entrada se recibiera desde un archivo CSV en lugar de un archivo de texto de direcciones IP?
Tal vez tengas un archivo CSV que se ve así en C:\Test\pc-list.csv.
Ten en cuenta que el campo
ComputerName
en el archivo CSV tiene el mismo nombre que el parámetroComputerName
deGet-ConnectionStatus
.
Si intentaras importar el CSV y pasarlo por la canalización a Get-ConnectionStatus
, la función devolvería un resultado inesperado en la columna ComputerName
.
¿Puedes adivinar qué salió mal? Después de todo, el nombre del parámetro sí coincide, ¿entonces por qué la canalización de PowerShell no enlazó la salida que devolvió Import-CSV
al parámetro ComputerName
en Get-ConnectionStatus
? Porque necesitas el atributo del parámetro ValueFromPipelineByPropertyName
.
En este momento, el parámetro ComputerName
de la función tiene una definición de parámetro que se ve así [Parámetro(ValueFromPipeline)]
. Por lo tanto, debes agregar ValueFromPipelineByPropertyName
para establecer el parámetro ComputerName
para admitir la entrada por nombre de propiedad, como se muestra a continuación.
Una vez que hayas agregado el soporte de canalización por nombre de propiedad, le indicas a PowerShell que comience a buscar los nombres de propiedad del objeto y el tipo de objeto. Después de hacer este cambio, deberías ver la salida esperada.
Resumen
En este tutorial, aprendiste cómo funciona la canalización de PowerShell, cómo enlaza los parámetros e incluso cómo crear tu propia función que admita la canalización de PowerShell.
Aunque las funciones funcionarán sin la canalización, no “transmitirán” objetos de un comando a otro y simplificarán el código.
¿Puedes pensar en una función que hayas escrito, o tal vez estés a punto de escribir, que pueda beneficiarse al hacerla lista para la canalización?