Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Descripción breve
Combinando comandos en canalizaciones de PowerShell
Descripción larga
Una tubería es una serie de comandos conectados por operadores de tubería (|) (ASCII 124). Cada operador de canalización envía los resultados del comando anterior al siguiente comando.
La salida del primer comando se puede enviar para su procesamiento como entrada al segundo comando. Y esa salida se puede enviar a otro comando. El resultado es una compleja cadena de comandos o canalización que se compone de una serie de comandos simples.
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 la canalización. Dado que no hay más comandos en la canalización, los resultados se muestran en la consola.
En una canalización, los comandos se procesan en orden de izquierda a derecha. El procesamiento se controla como una sola operación y la salida se muestra a medida que se genera.
Este es un ejemplo sencillo. El siguiente comando obtiene el proceso del Bloc de notas y, a continuación, lo detiene.
Por ejemplo
Get-Process notepad | Stop-Process
El primer comando usa el cmdlet Get-Process para obtener un objeto que representa el proceso del Bloc de notas. Usa un operador de canalización (|) para enviar el objeto de proceso al cmdlet Stop-Process, que detiene el proceso del Bloc de notas. Observe que el comando Stop-Process no tiene un Nombre o un ID parámetro para especificar el proceso, porque el proceso especificado se envía a través de la tubería.
Este ejemplo de canalización obtiene los archivos de texto del directorio actual, selecciona solo los archivos que tienen más de 10 000 bytes de longitud, los ordena por longitud y muestra el nombre y la longitud de cada archivo de una tabla.
Get-ChildItem -Path *.txt |
Where-Object {$_.length -gt 10000} |
Sort-Object -Property length |
Format-Table -Property name, length
Esta canalización consta de cuatro comandos en el orden especificado. En la ilustración siguiente se muestra la salida de cada comando a medida que se pasa al siguiente comando de la canalización.
Get-ChildItem -Path *.txt
| (FileInfo objects for *.txt)
V
Where-Object {$_.length -gt 10000}
| (FileInfo objects for *.txt)
| ( Length > 10000 )
V
Sort-Object -Property Length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
V
Format-Table -Property name, length
| (FileInfo objects for *.txt)
| ( Length > 10000 )
| ( Sorted by length )
| ( Formatted in a table )
V
Name Length
---- ------
tmp1.txt 82920
tmp2.txt 114000
tmp3.txt 114000
Uso de canalizaciones
La mayoría de los cmdlets de PowerShell están diseñados para admitir canalizaciones. En la mayoría de los casos, puede canalizar los resultados de un cmdlet Get a otro cmdlet del mismo nombre.
Por ejemplo, puede canalizar la salida del cmdlet Get-Service a los cmdlets Start-Service o Stop-Service.
Esta canalización de ejemplo inicia el servicio WMI en el equipo:
Get-Service wmi | Start-Service
Por ejemplo, puede canalizar la salida de Get-Item o Get-ChildItem del proveedor de registro de PowerShell al cmdlet New-ItemProperty. En este ejemplo se agrega una nueva entrada del Registro,
Get-Item -Path HKLM:\Software\MyCompany |
New-ItemProperty -Name NoOfEmployees -Value 8124
Muchos de los cmdlets de utilidades, como Get-Member, Where-Object, Sort-Object, Group-Object y Measure-Object, se usan casi exclusivamente en canalizaciones. Puede canalizar cualquier tipo de objeto a estos cmdlets. En este ejemplo se muestra cómo ordenar todos los procesos del equipo por el número de identificadores abiertos en cada proceso.
Get-Process | Sort-Object -Property handles
Puede canalizar objetos a los cmdlets de formato, exportación y salida, como Format-List, Format-Table, Export-Clixml, Export-CSVy Out-File.
En este ejemplo se muestra cómo usar el cmdlet Format-List para mostrar una lista de propiedades de un objeto de proceso.
Get-Process winlogon | Format-List -Property *
Con un poco de práctica, encontrará que combinar comandos simples en canalizaciones ahorra tiempo y escritura, y hace que el scripting sea más eficaz.
Funcionamiento de las canalizaciones
En esta sección se explica cómo se enlazan los objetos de entrada a parámetros de cmdlet y se procesan durante la ejecución de la canalización.
Acepta la entrada de canalización
Para admitir la canalización, el cmdlet receptor debe tener un parámetro que acepte la entrada de canalización. Use el comando Get-Help con las opciones Full o Parameter para determinar qué parámetros de un cmdlet aceptan entradas de canalización.
Por ejemplo, para determinar cuál de los parámetros del cmdlet Start-Service acepta la entrada de canalización, escriba:
Get-Help Start-Service -Full
o
Get-Help Start-Service -Parameter *
La ayuda del cmdlet
-InputObject <ServiceController[]>
Specifies ServiceController objects representing the services to be started.
Enter a variable that contains the objects, or type a command or expression
that gets the objects.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByValue)
Accept wildcard characters? false
-Name <String[]>
Specifies the service names for the service to be started.
The parameter name is optional. You can use Name or its alias, ServiceName,
or you can omit the parameter name.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
Al enviar objetos a través de la canalización a
Métodos para aceptar entradas de canalización
Los parámetros de los cmdlets pueden aceptar la entrada de canalización de dos maneras distintas:
ByValue: el parámetro acepta valores que coinciden con el tipo de .NET esperado o que se pueden convertir a ese tipo.
Por ejemplo, el parámetro Name de
Start-Serviceacepta la entrada de canalización por valor. Puede aceptar objetos de cadena u objetos que se pueden convertir en cadenas.ByPropertyName: el parámetro acepta la entrada solo cuando el objeto de entrada tiene una propiedad del mismo nombre que el parámetro .
Por ejemplo, el parámetro Name de
Start-Servicepuede aceptar objetos que tienen una propiedad Name . Para enumerar las propiedades de un objeto, canalice aGet-Member.
Algunos parámetros pueden aceptar objetos tanto por valor como por nombre de propiedad, lo que facilita la entrada desde la canalización.
Enlace de parámetros
Al canalizar objetos de un comando a otro, PowerShell intenta asociar los objetos canalados con un parámetro del cmdlet receptor.
El componente de enlace de parámetros de PowerShell asocia los objetos de entrada con parámetros de cmdlet según los criterios siguientes:
- El parámetro debe aceptar la entrada de una canalización.
- El parámetro debe aceptar el tipo de objeto que se envía o un tipo que se puede convertir al tipo esperado.
- El parámetro no se usó en el comando .
Por ejemplo, el cmdlet Start-Service tiene muchos parámetros, pero solo dos de ellos, Nombre y InputObject aceptan entrada del pipeline. El parámetro Name
PowerShell administra el enlace de parámetros de la forma más eficaz posible. No puede sugerir ni forzar que PowerShell se enlace a un parámetro específico. Se produce un error en el comando si PowerShell no puede enlazar los objetos canalados.
Para obtener más información sobre cómo solucionar errores de enlace, consulte Investigación de errores de enlace más adelante en este artículo.
Procesamiento individual
La canalización de objetos a un comando es muy similar al uso de un parámetro del comando para enviar los objetos. Echemos un vistazo a un ejemplo de canalización. En este ejemplo, se usa una canalización para mostrar una tabla de objetos de servicio.
Get-Service | Format-Table -Property Name, DependentServices
Funcionalmente, esto es como usar el parámetro InputObject de Format-Table para enviar la colección de objetos.
Por ejemplo, podemos guardar la colección de servicios en una variable que se pasa mediante el parámetro InputObject .
$services = Get-Service
Format-Table -InputObject $services -Property Name, DependentServices
O bien, podemos insertar el comando en el parámetro
Format-Table -InputObject (Get-Service) -Property Name, DependentServices
Sin embargo, hay una diferencia importante. Al canalizar varios objetos a un comando, PowerShell envía los objetos al comando uno a uno. Cuando se usa un parámetro de comando, los objetos se envían como un único objeto de matriz. Esta diferencia menor tiene consecuencias significativas.
Al ejecutar una canalización, PowerShell enumera automáticamente cualquier tipo que implemente la IEnumerable interfaz y envía los miembros a través de la canalización de uno en uno. La excepción es [hashtable], que requiere una llamada al GetEnumerator() método.
En los ejemplos siguientes, una matriz y una tabla hash se canalizan al cmdlet Measure-Object para contar el número de objetos recibidos de la canalización. La matriz tiene varios miembros y la tabla hash tiene varios pares clave-valor. Solo se enumera la matriz una a la vez.
@(1,2,3) | Measure-Object
Count : 3
Average :
Sum :
Maximum :
Minimum :
Property :
@{"One"=1;"Two"=2} | Measure-Object
Count : 1
Average :
Sum :
Maximum :
Minimum :
Property :
Del mismo modo, si canaliza varios objetos de proceso desde el cmdlet Get-Process al cmdlet Get-Member, PowerShell envía cada objeto de proceso, de uno en uno, a Get-Member.
Get-Member muestra la clase .NET (tipo) de los objetos de proceso y sus propiedades y métodos.
Get-Process | Get-Member
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
...
Nota:
Get-Member elimina duplicados, por lo que si los objetos son todos del mismo tipo, solo muestra un tipo de objeto.
Sin embargo, si usa el parámetro InputObject de Get-Member, entonces Get-Member recibe una matriz de objetos System.Diagnostics.Process como una sola unidad. Muestra las propiedades de una matriz de objetos. (Anote el símbolo de matriz (
Por ejemplo
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()
...
Es posible que este resultado no sea lo que tenías en mente. Pero después de entenderlo, puedes usarlo. Por ejemplo, todos los objetos de matriz tienen una propiedad Count. Puede usarlo para contar el número de procesos que se ejecutan en el equipo.
Por ejemplo
(Get-Process).count
Es importante recordar que los objetos enviados a la canalización se entregan de uno en uno.
Investigación de errores de canalización
Cuando PowerShell no puede asociar los objetos canalados a un parámetro del cmdlet receptor, se produce un error en el comando.
En el ejemplo siguiente, intentamos mover una entrada del Registro de una clave del Registro a otra. El cmdlet Get-Item obtiene la ruta de acceso de destino, que luego se canaliza al cmdlet Move-ItemProperty. El comando Move-ItemProperty especifica la ruta de acceso actual y el nombre 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 produce un error y PowerShell muestra el siguiente mensaje de error:
Move-ItemProperty : The input object can't be bound to any parameters for
the command either because the command doesn't take pipeline input or the
input and its properties do not match any of the parameters that take
pipeline input.
At line:1 char:23
+ $a | Move-ItemProperty <<<< -Path HKLM:\Software\MyCompany\design -Name p
Para investigar, use el cmdlet Trace-Command para realizar un seguimiento del componente de enlace de parámetros de PowerShell. En el ejemplo siguiente se monitoriza la vinculación de parámetros mientras se ejecuta la canalización. El parámetro PSHost muestra los resultados del seguimiento en la consola y el parámetro FilePath envían los resultados de seguimiento al archivo debug.txt para obtener una referencia posterior.
Trace-Command -Name ParameterBinding -PSHost -FilePath debug.txt -Expression {
Get-Item -Path HKLM:\Software\MyCompany\sales |
Move-ItemProperty -Path HKLM:\Software\MyCompany\design -Name product
}
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 el intento de enlazar la ruta de acceso al parámetro Destination de Move-ItemProperty ha fallado.
...
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
...
Use el cmdlet Get-Help para ver los atributos del parámetro destino.
Get-Help Move-ItemProperty -Parameter Destination
-Destination <String>
Specifies the path to the destination location.
Required? true
Position? 1
Default value None
Accept pipeline input? True (ByPropertyName)
Accept wildcard characters? false
Los resultados muestran que Destino acepta la entrada de canalización solo por "nombre de propiedad". Por lo tanto, el objeto canalizado debe tener una propiedad denominada Destination.
Use Get-Member para ver las propiedades del objeto procedente de Get-Item.
Get-Item -Path HKLM:\Software\MyCompany\sales | Get-Member
La salida muestra que el elemento es un objeto Microsoft.Win32.RegistryKey que no tiene una propiedad Destination. Esto explica por qué se produjo un error en el comando.
El parámetro Path acepta la entrada de canalización por nombre o por valor.
Get-Help Move-ItemProperty -Parameter Path
-Path <String[]>
Specifies the path to the current location of the property. Wildcard
characters are permitted.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? true
Para corregir el comando, debemos especificar el destino en el cmdlet Move-ItemProperty y usar Get-Item para obtener la ruta de acceso de del elemento que queremos mover.
Por ejemplo
Get-Item -Path HKLM:\Software\MyCompany\design |
Move-ItemProperty -Destination HKLM:\Software\MyCompany\sales -Name product
Continuación de línea intrínseca
Como ya se ha descrito, una canalización es una serie de comandos conectados por operadores de canalización (|), normalmente escritos en una sola línea. Sin embargo, para mejorar la legibilidad, PowerShell permite dividir la canalización entre varias líneas.
Cuando un operador de canalización es el último token de la línea, el analizador de PowerShell combina la siguiente línea al comando actual para continuar con la construcción de la canalización.
Por ejemplo, la siguiente canalización de una sola línea:
Command-1 | Command-2 | Command-3
se puede escribir como:
Command-1 |
Command-2 |
Command-3
Los espacios iniciales en las líneas siguientes no son significativos. La sangría mejora la legibilidad.