TEMA
about_pipelines
DESCRIPCIÓN BREVE
Uso de canalizaciones para combinar comandos en Windows PowerShell
DESCRIPCIÓN DETALLADA
Una canalización es una serie de comandos conectados por
operadores de canalización (|) (ASCII 124). Cada operador de
canalización envía los resultados del comando anterior al
siguiente comando.
Puede utilizar las canalizaciones para enviar los objetos
generados por un comando a otro comando para que los procese. Y
el resultado de ese comando lo puede enviar a un tercer comando.
El resultado es una cadena de comandos o "canalización" muy
eficaz que se compone de una serie de comandos sencillos.
Por ejemplo:
Command-1 | Command-2 | Command-3
En este ejemplo, los objetos que Command-1 emite se envían a
Command-2. Command-2 procesa los objetos y los envía a Command-3.
Command-3 procesa los objetos y los envía a través de la
canalización. Al no haber más comandos en la canalización, se
muestran los resultados en la consola.
En una canalización, los comandos se procesan de izquierda a
derecha en el orden en que aparecen. El procesamiento se
administra como una sola operación y el resultado se muestra
cuando se genera.
A continuación figura un ejemplo sencillo. El comando siguiente
obtiene el proceso Notepad (Bloc de notas) y, a continuación, lo
detiene.
get-process notepad | stop-process
El primer comando usa el cmdlet Get-Process para obtener el
objeto que representa el proceso Notepad. Utiliza un operador de
canalización (|) para enviar el objeto de proceso al cmdlet
Stop-Process, que detiene el proceso Notepad. Observe que el
comando Stop-Process no tiene parámetro Name ni ID para
especificar el proceso, ya que el proceso especificado se envía a
través de la canalización.
A continuación figura un ejemplo práctico. Esta canalización de
comandos obtiene los archivos de texto del directorio actual,
selecciona únicamente los archivos de más de 10.000 bytes, los
ordena por tamaño y muestra el nombre y el tamaño de cada archivo
en una tabla.
Get-ChildItem -path *.txt | Where-Object {$_.length -gt 10000} |
Sort-Object -property Length | Format-Table -property name, length
Esta canalización se compone de cuatro comandos en el orden
especificado. El comando se escribe horizontalmente, pero en el
siguiente gráfico se muestra el proceso verticalmente.
Get-ChildItem -path *.txt
|
| (FileInfo objects )
| ( .txt )
|
V
Where-Object {$_.length -gt 10000}
|
| (FileInfo objects )
| ( .txt )
| ( Length > 10000 )
|
V
Sort-Object -property Length
|
| (FileInfo objects )
| ( .txt )
| ( Length > 10000 )
| ( Sorted by length )
|
V
Format-Table -property name, length
|
| (FileInfo objects )
| ( .txt )
| ( Length > 10000 )
| ( Sorted by length )
| (Formatted in a table )
|
V
Name Length
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
USAR CANALIZACIONES
Los cmdlets de Windows PowerShell se diseñaron para utilizarlos
en canalizaciones. Por ejemplo, normalmente se pueden canalizar
los resultados de un cmdlet Get a un cmdlet de acción (como un
cmdlet Set, Start, Stop o Rename) para el mismo sustantivo.
Por ejemplo, se puede canalizar cualquier servicio del cmdlet
Get-Service al cmdlet Start-Service o Stop-Service (si bien los
servicios deshabilitados no se pueden reiniciar de esta manera).
Esta canalización de comandos inicia el servicio WMI en el equipo:
get-service wmi | start-service
Los cmdlets que obtienen y establecen objetos de los proveedores
de Windows PowerShell, como los cmdlets Item e ItemProperty,
también se diseñaron para utilizarlos en canalizaciones.
Por ejemplo, se pueden canalizar los resultados de un comando
Get-Item o Get-ChildItem en el proveedor del Registro de Windows
PowerShell al cmdlet New-ItemProperty. Este comando agrega una
nueva entrada del Registro, NoOfEmployees, con el valor 8124, a
la clave del Registro MyCompany.
get-item -path HKLM:\Software\MyCompany | new-Itemproperty -name NoOfEmployees -value 8124
Un gran número de los cmdlets de utilidad, como Get-Member,
Where-Object, Sort-Object, Group-Object y Measure-Object, se
utilizan casi exclusivamente en las canalizaciones. Se puede
canalizar cualquier objeto a estos cmdlets.
Por ejemplo, se pueden canalizar todos los procesos del equipo al
comando Sort-Object para que se ordenen por el número de
identificadores en el proceso.
get-process | sort-object -property handles
Asimismo, se puede canalizar cualquier objeto a los cmdlets de
formato, como Format-List y Format-Table, a los cmdlets de
exportación, como Export-Clixml y Export-CSV, y a los cmdlets
Out, como Out-Printer.
Por ejemplo, se puede canalizar el proceso Winlogon al cmdlet
Format-List para que se muestren todas las propiedades del
proceso en una lista.
get-process winlogon | format-list -property *
Con un poco de práctica, se dará cuenta de que al combinar
comandos en canalizaciones ahorrará tiempo y no tendrá que
escribir tanto, por lo que el uso de scripts resultará más eficaz.
FUNCIONAMIENTO DE LAS CANALIZACIONES
Cuando se "canalizan" objetos, es decir, cuando se envían los
objetos del resultado de un comando a otro comando, Windows
PowerShell intenta asociar los objetos canalizados a uno de los
parámetros del cmdlet receptor.
Para ello, el componente de "enlace de parámetros" de Windows
PowerShell, que asocia los objetos de entrada con los parámetros
de los cmdlets, busca un parámetro que cumpla los siguientes
criterios:
-- El parámetro debe aceptar entradas de canalizaciones (no
todos los parámetros las aceptan).
-- El parámetro debe aceptar el tipo del objeto enviado o el
tipo en el que se puede convertir el objeto.
-- El parámetro aún no puede estar presente en el comando.
Por ejemplo, el cmdlet Start-Service tiene muchos parámetros,
pero solo dos de ellos, Name e InputObject, aceptan entradas de
canalizaciones. El parámetro Name toma cadenas y el parámetro
InputObject toma objetos de servicio. Por consiguiente, se
pueden canalizar cadenas y objetos de servicio (así como objetos
con propiedades que se pueden convertir en cadenas y objetos de
servicio) a Start-Service.
Si el componente de enlace de parámetros de Windows PowerShell
no logra asociar los objetos canalizados con un parámetro del
cmdlet receptor, el comando generará un error y Windows
PowerShell solicitará los valores de parámetro que faltan.
No se puede forzar dicho componente a que asocie los objetos
canalizados con un parámetro concreto; ni siquiera se puede
sugerir ningún parámetro. La lógica del componente administra la
canalización de la manera más eficaz posible.
PROCESAMIENTO DE UNO EN UNO
La canalización de objetos a un comando es muy similar al uso de
un parámetro del comando para enviar los objetos.
Por ejemplo, canalizar objetos que representan los servicios del
equipo a un comando Format-Table, como:
get-service | format-table -property name, dependentservices
es muy similar a guardar los objetos de servicio en una variable
y usar el parámetro InputObject de Format-Table para enviar el
objeto de servicio:
$services = get-service
format-table -inputobject $services -property name, dependentservices
o bien, incrustar el comando en el valor de parámetro:
format-table -inputobject (get-service wmi) -property name, dependentservices
Sin embargo, hay una diferencia importante. Cuando se canalizan
varios objetos a un comando, Windows PowerShell los envía al
comando de uno en uno. Cuando se usa el parámetro de un comando,
los objetos se envían como un solo objeto de matriz.
Esta diferencia aparentemente técnica puede tener consecuencias
interesantes y, a veces, útiles.
Por ejemplo, si se canalizan varios objetos de proceso del
cmdlet Get-Process al cmdlet Get-Member, Windows PowerShell los
envía de uno en uno a Get-Member.
Get-Member muestra la clase de .NET (tipo) de los objetos de
proceso así como sus propiedades y métodos.
(Get-Member elimina los duplicados, por lo que solo muestra un
tipo de objeto si todos los objetos son del mismo tipo.)
En este caso, Get-Member muestra las propiedades y los métodos
de cada objeto de proceso, es decir, un objeto System.Diagnostics
.Process.
get-process | get-member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
Sin embargo, si se utiliza el parámetro InputObject de
Get-Member, Get-Member recibirá una matriz de objetos
System.Diagnostics.Process como una sola unidad y mostrará las
propiedades de una matriz de objetos. (Fíjese en el símbolo de
matriz ([]) después del nombre de tipo System.Object.)
get-member -inputobject (get-process)
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object& Address(Int32 )
Clone Method System.Object Clone()
...
Puede que este resultado no sea lo que buscaba, pero si lo
comprende, podrá utilizarlo. Por ejemplo, una matriz de objetos
de proceso tiene una propiedad Count que se puede usar para
contar el número de procesos en el equipo.
(get-process).count
Esta distinción puede ser importante. Por lo tanto, cuando
canalice objetos a un cmdlet, no olvide que esos objetos se
envían de uno en uno.
Acepta entradas de canalizaciones
Para poder recibir objetos en una canalización, el cmdlet
receptor debe tener un parámetro que acepte las entradas de
canalizaciones. Se puede usar un comando Get-Help con los
parámetros Full o Parameter para determinar cuáles son los
parámetros de un cmdlet que aceptan entradas de canalizaciones,
en caso de que los haya.
En la presentación predeterminada de Get-Help, el elemento
"Acepta entradas de canalizaciones" aparece en una tabla de
atributos de parámetro. Esta tabla se muestra únicamente si se
usa el parámetro Full o Parameter del cmdlet Get-Help.
Por ejemplo, para determinar cuáles son los parámetros del cmdlet
Start-Service que aceptan entradas de canalizaciones, escriba:
get-help start-service -full
get-help start-service -parameter *
Por ejemplo, en la Ayuda del cmdlet Start-Service se muestra que
los parámetros Name e InputObject aceptan entradas de
canalizaciones ("true"). Todos los demás parámetros tienen el
valor "false" en la fila "¿Acepta entradas de canalizaciones?".
-name <string[]>
Especifica el nombre de servicio del servicio que se va a iniciar.
El nombre del parámetro es opcional. Puede usar "-Name" o su alias,
"-ServiceName", o puede omitir el nombre del parámetro.
¿Requerido? sí
¿Posición? 1
Valor predeterminado
--> ¿Aceptar canalización? true (ByValue, ByPropertyName)
¿Aceptar caracteres comodín? sí
-inputObject <ServiceController[]>
Especifica objetos ServiceController que representan los
servicios que se van a iniciar. Especifique una variable
que contenga los objetos o escriba un comando o una
expresión que obtenga los objetos.
¿Requerido? false
¿Posición? named
Valor predeterminado
--> ¿Aceptar canalización? true (ByValue)
¿Aceptar caracteres comodín? false
Esto significa que se pueden enviar objetos (PsObjects) a través
de la canalización al cmdlet Where-Object y Windows PowerShell
asociará el objeto al parámetro InputObject.
MÉTODOS PARA ACEPTAR ENTRADAS DE CANALIZACIONES
Los parámetros de los cmdlets pueden aceptar las entradas de
canalizaciones de dos formas diferentes:
-- ByValue: los parámetros que aceptan las entradas "por valor"
pueden aceptar objetos canalizados con el mismo tipo de .NET
que su valor de parámetro u objetos que se pueden convertir
en ese tipo.
Por ejemplo, el parámetro Name de Start-Service acepta
entradas de canalizaciones por valor. Puede aceptar objetos
de cadena u objetos que se pueden convertir en cadenas.
-- ByPropertyName: los parámetros que aceptan entradas "por
nombre de propiedad" pueden aceptar objetos canalizados
únicamente si una propiedad del objeto tiene el mismo nombre
que el parámetro.
Por ejemplo, el parámetro Name de Start-Service puede aceptar
objetos que tienen una propiedad Name.
(Para ver las propiedades de un objeto, canalícelo a Get-Member.)
Algunos parámetros pueden aceptar objetos por valor o por nombre
de propiedad. Estos parámetros se han diseñado para que acepten
fácilmente las entradas de las canalizaciones.
INVESTIGAR LOS ERRORES DE CANALIZACIÓN
Si un comando no se ejecuta correctamente debido a un error de
canalización, se puede investigar el error y rescribir el comando.
Por ejemplo, el comando siguiente intenta mover una entrada del
Registro de una clave del Registro a otra usando el cmdlet
Get-Item a fin de obtener la ruta de acceso de destino y, a
continuación, canalizando la ruta de acceso al cmdlet
Move-ItemProperty.
Concretamente, el comando utiliza el cmdlet Get-Item para
obtener la ruta de acceso de destino. Utiliza un operador de
canalización para enviar el resultado al cmdlet Move-ItemProperty.
El comando Move-ItemProperty especifica la ruta de acceso y el
nombre actuales de la entrada del Registro que se va a mover.
get-item -path hklm:\software\mycompany\sales |
move-itemproperty -path hklm:\software\mycompany\design -name product
El comando genera un error y Windows PowerShell muestra el
siguiente mensaje de error:
Move-ItemProperty: El objeto de entrada no se puede enlazar
a ninguno de los parámetros del comando, bien porque el
comando no admite la entrada de canalización o porque la
entrada y sus propiedades no coinciden con ninguno de los
parámetros que aceptan entradas de canalización.
En línea:1 carácter:23
+ $a | move-itemproperty <<<< -path hklm:\software\mycompany\design -name product
Si desea investigar el error, utilice el cmdlet Trace-Command
para realizar un seguimiento del componente de enlace de
parámetros de Windows PowerShell. El comando siguiente realiza un
seguimiento del componente de enlace de parámetros durante el
procesamiento del comando. Usa el parámetro -pshost para mostrar
los resultados en la consola y utiliza el comando -filepath para
enviarlos al archivo debug.txt a fin de utilizarlos
posteriormente como referencia.
trace-command -name parameterbinding -expression {get-item -path hklm:\software\mycompany\sales |
move-itemproperty -path hklm:\software\mycompany\design -name product} -pshost -filepath debug.txt
Los resultados del seguimiento son largos, pero muestran los
valores que se enlazan al cmdlet Get-Item y, a continuación, los
valores con nombre que se enlazan al cmdlet Move-ItemProperty.
...
BIND NAMED cmd line args [Move-ItemProperty]
BIND arg [hklm:\software\mycompany\design] to parameter [Path]
...
BIND arg [product] to parameter [Name]
....
BIND POSITIONAL cmd line args [Move-ItemProperty]
...
Por último, muestra que se genera un error al intentar enlazar la
ruta de acceso al parámetro Destination de Move-ItemProperty.
...
BIND PIPELINE object to parameters: [Move-ItemProperty]
PIPELINE object TYPE = [Microsoft.Win32.RegistryKey]
RESTORING pipeline parameter's original values
Parameter [Destination] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION
...
Para investigar el error, utilice el cmdlet Get-Help para ver
los atributos del parámetro Destination. El comando siguiente
obtiene información detallada sobre el parámetro Destination.
get-help move-itemproperty -parameter destination
Los resultados muestran que el parámetro Destination acepta las
entradas de canalización únicamente "por nombre de propiedad".
Es decir, el objeto canalizado debe tener una propiedad
denominada Destination.
-destination <string>
Especifica la ruta de acceso a la ubicación de destino.
¿Requerido? sí
¿Posición? 2 Valor predeterminado
¿Aceptar canalización? true (ByPropertyName)
¿Aceptar caracteres comodín? sí
Para ver las propiedades del objeto que se canaliza al cmdlet
Move-ItemProperty, canalícelo al cmdlet Get-Member. El siguiente
comando canaliza los resultados de la primera parte del comando
al cmdlet Get-Member.
get-item -path hklm:\software\mycompany\sales | get-member
El resultado muestra que el elemento es un objeto Microsoft.Win32
.RegistryKey que no tiene la propiedad Destination. Esto explica
por qué el comando generó un error.
Para corregir el comando, es preciso especificar el destino en
el cmdlet Move-ItemProperty. Se puede usar un comando
Get-ItemProperty para obtener la ruta de acceso, pero el nombre
y el destino deben especificarse en la parte Move-ItemProperty
del comando.
get-item -path hklm:\software\mycompany\design |
move-itemproperty -dest hklm:\software\mycompany\design -name product
Para comprobar si el comando se ejecutó correctamente, utilice
un comando Get-ItemProperty:
get-itemproperty hklm:\software\mycompany\sales
Los resultados muestran que la entrada del Registro Product se
movió a la clave Sales.
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\mycompany\sales
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\software\mycompany
PSChildName : sales
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
Product : 18
VEA TAMBIÉN
Para obtener información acerca de los objetos, escriba el
siguiente comando en el símbolo del sistema de PowerShell:
help about_objects
Para obtener información acerca de los parámetros, escriba el siguiente comando:
help about_parameters
Para obtener información acerca de la sintaxis de comandos, escriba el siguiente comando:
help about_command_syntax
Para obtener información acerca de las instrucciones foreach, escriba el siguiente comando:
help about_foreach