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