Windows PowerShell

¿Lo que la complicada es $ _?

Don Jones

W uando Estoy realizando una charla de clase o conferencia Windows PowerShell, me encanta trot fuera una línea como éste:

Importación-CSV c:\users.csv | ForEach-Object {New-QADUser - logonname $ _.username - nombre $ _.Name}

De hecho, en una conferencia de TechMentor reciente, comencé Mis sesiones con algo parecido y he usado una versión más tiempo en un hablar en Tech-Ed. Esta línea importa una lista de información de usuario de un archivo .csv y activa esa información en los nuevos usuarios en Active Directory. Es una gran demostración porque muestra que Windows PowerShell puede conseguir bastante simplemente ejecutar comandos en lugar de tener a secuencias de comandos complejas de programa.

Pero mucho después de que se he movido a otras demostraciones, hay algo que aún está realizando los ojos de personas cruzados: $_. En las clases prácticas, verá a los alumnos intentando reproducir con $ _on la línea de comandos, sin mucha suerte. En los foros de discusión en línea, verá personas que formulan preguntas acerca de él, intentando entender lo que significa. Afortunadamente, la respuesta es sencilla, si no es exactamente simple.

Pasar de dinero... ER, Object

Recuerde que todo en Windows PowerShell es un objeto. Normalmente, puede ignorar este hecho, que es interesante porque son objetos entre los problemas de desarrolladores de software que pueden realizar fácilmente para obtener una explicación confusa. Trataré evitar los aspectos más confusos con este sencillo ejemplo:

Get-Service

Este cmdlet genera un montón de objetos de servicio. Esto simplemente significa que se pueden canalizar a otros cmdlets que aceptan objetos de servicio como entrada:

Get-Service | Stop-Service

Pero realmente no ejecute a menos que le interesa detener cada servicio en su equipo--que se probablemente lo bloquearse, si no cerró inesperadamente. Básicamente, Stop-Service puede aceptar objetos de servicio, entre otras cosas, como entrada, que le indica qué servicios para detener. Algunos cmdlets son más ampliamente aceptando y puede tomar casi cualquier tipo de objeto como entrada:

Get-Service | Sort-Object Name Get-Process | Sort-Object Name

En estos ejemplos, Sort-Object es perfectamente feliz trabajar con objetos de cualquier servicio o procesar objetos, para colocarlos en orden por cualquier propiedad de objeto--en ambos casos, la propiedad Name--que especifique.

Lo que técnicamente hablando, Name es que se van a aceptar el cmdlet del - parámetro de propiedad, significa que podría haber escrito una línea de comandos más completa, como este:

Get-Process | Sort-Object-propiedad Name

Esto significa que "Poner estos objetos y ordenarlos en la propiedad Name". Cada cmdlet tiene uno o más parámetros que comportamiento del cmdlet de alguna forma de personalizar. Sort-Object, por ejemplo, tiene otro parámetro que me invertir el orden de ordenación permite:

Get-Process | Sort-Object - propiedad Name - descendente

Independientemente, Sort-Object es tomar los objetos de entrada, para colocarlos en un orden diferente y producir esos mismos objetos en su nueva secuencia.

Super parámetros: Scriptblocks

Algunos cmdlets especialmente eficaces puede tener toda las secuencias de comandos dadas a ellos como parámetros. Windows PowerShell en normalmente hace referencia a ellos como scriptblocks, porque, bueno, porque cada uno es un bloque de código de secuencia de comandos. Con más frecuencia, éstas constan de un bloque de comandos en lugar de una secuencia de comandos que implican la programación detallada, pero se puede colocar casi cualquier cosa en un bloque de script.

Tal un cmdlet es Where-Object. Acepta un montón de objetos como entrada--hará cualquier tipo de objeto--y, a continuación, se ejecuta un bloque de script una vez para cada objeto que se ha de entrada.

Si ese bloque de script envía el valor booleano true, el objeto canalizado en se canaliza fuera; si el bloque script envía False, el objeto canalizado en se descarta. De esta manera, puede utilizar Where-Object para objetos de filtro según algunos criterios. Por ejemplo:

Get-WmiObject-clase Win32_Service | Where-Object-filterscript {$ _.State - eq "running"}

Hay que $ _ nuevo. En realidad, ambas-clase - filterscript parámetros y son posicionales, lo que significa que siempre que se pasa un valor en la primera posición, no necesita el nombre de parámetro real. Esto significa que normalmente verá un ejemplo de este escrito como:

Get-WmiObject Win32_Service | Where-Object {$ _.State - eq "running"}

Pero es lo mismo. Las llaves son que el shell del estandarizado forma envolvente un bloque de script. En este caso, el bloque script no mucho de una secuencia de comandos en absoluto; es una comparación bastante sencilla. Y ahí es donde entra en juego $ _: Recuerde que el bloque de script ejecutará una vez para cada objeto canalizado en. Cuando se ejecuta el bloque de script, $ _ se reemplaza con el objeto de entrada actual. En otras palabras, $ _ es un marcador de posición para el objeto de canalización actual. $ _ le permite comparar las propiedades del objeto--, como la propiedad State--con valores como "Running".

¿Qué es un nombre?

Siempre he pensé que $ _ era una pieza impar de sintaxis. En determinadas ocasiones, he pensé que canaliza en un nombre más fácil de leer, tal como $ o $ inputobject podría más sentido, pero $ _ es al menos fácil de escribir. Me han dicho que $ _ obtuvo su nombre porque el carácter de subrayado se parece a un carácter de canalización (|) aparece en su lado, lo que implica que contiene todo lo que se ha canalizado en.

La persona que me dijo esto era en una posición para conocer aspectos tales y era bastante grave--pero todavía se siente mi pierna tugged en ligeramente. He decidido que, para mí, $ _ representa un espacio en blanco, como en "relleno en el espacio en blanco". Es un espacio en blanco que obtiene rellena automáticamente por el shell cuando se ejecuta el bloque de script.

Y en él se encuentra la clave que obtiene la mayoría de las personas confundirse: $ _ sólo es válido y utilizable en ubicaciones específicas donde Windows PowerShell está buscando explícitamente de él y está preparado para reemplazar con algún objeto de entrada. Un lugar de este tipo es el bloque de script que se utiliza para los cmdlets Where-Object y ForEach-Object (como el uno al principio de este artículo).

Otro lugar está dentro del bloque PROCESS de ciertos tipos de funciones de Windows PowerShell. Pero, por supuesto, no puede simplemente escriba $ _.Status en línea de comandos del shell y esperar que funcione. El shell no está buscando $ _ en ese momento, por lo que obtener no reemplazado $ _ con nada; es esencialmente un valor indefinido.

Nidos: No sólo de aves

Otra situación confuso puede producirse cuando tienes scriptblocks anidados. Considere este ejemplo, que lee una lista de nombres de equipo de un archivo (un nombre por línea) e intenta reiniciarlos todos por con Instrumental de administración de Windows (WMI):

Get-Content c:\names.txt | ForEach-Object {Get-WmiObject - nombreEquipo $ _ - clase Win32_OperatingSystem | ForEach-Object {$_.Reboot()}}

Esto puede obtener un poco más fácil de leer si dejar de tratar esto como una única línea de comandos y aplicar en su lugar humanos descriptivas formato:

Get-Content c:\names.txt | ForEach-Object {Get-WmiObject - nombreEquipo $ _ - clase Win32_OperatingSystem | ForEach-Object {$_.Reboot()}}

 

Aquí, es más fácil de averiguar que hay anidados cmdlets ForEach-Object. Cada uno tiene un bloque de script y cada bloque script utiliza $ _. El truco es que $ _ cambia realmente su significado en el transcurso de esta línea de comandos, pero siempre contiene uno de los objetos que se canaliza a ese cmdlet ForEach-Object.

Por tanto, el primer ForEach-Object está recibiendo los nombres de equipo de Get-Content; por lo tanto, el primer $ _ contiene nombres de equipo, que se reciben a-parámetro NombreDeEquipo.

El segundo ForEach-Object recibe datos de entrada de Get-WmiObject, por tanto, su $ _ contiene esos objetos WMI--específicamente, las instancias de la clase Win32_OperatingSystem, que tienen un método práctico para Reboot().

Éste es un truco para averiguar qué $ _ contiene: Recuerde que siempre contendrá objetos creados por el cmdlet siguiente a la izquierda de la línea de comandos.

Cuando obtenga profundamente anidadas situaciones como ésta, poder con versiones anteriores de seguimiento puede ayudarle a averiguar lo que sucede en más fácilmente.

Siempre es la problemas comunes

Siempre he pensaban que la diferencia entre que se un gurú y un cibernovato Windows PowerShell no es memorizar todos los comandos disponibles o poder escribir secuencias de comandos complejas. En su lugar, está siendo capaz de maestro de cuantas "trampas" o impares piezas de sintaxis, que acompaña cada shell o el idioma. $ _ es una de ellas. Es difícil averiguar simplemente observando lo qué $ _ hace.

Pero ahora que sabe, puede empezar a utilizar en más de sus propios comandos. Tal como lo hace, será maestro lo--y moverá que mucho más cerca al que se va a una

Windows PowerShell gurú.

 

Don Jones es uno de más experimentados Windows PowerShell formadores de la nación y escritores. Blogs semanal Windows PowerShell sugerencias en ConcentratedTech.com; también puede ponerse en contacto con él o a las preguntas le de existen .