Volver a lo básico: Comprender los objetos de PowerShell

PowerShell es un lenguaje poderoso. ¿Pero qué hace que este lenguaje de secuencias de comandos sea tan poderoso? Los objetos de PowerShell. ¿Qué son estos objetos mágicos y cómo trabaja PowerShell con ellos? Sigue atento para descubrirlo.

PowerShell es un lenguaje orientado a objetos y una shell. Esto difiere de las shells tradicionales como cmd y Bash. Estas shells tradicionales se enfocaban en texto, es decir, cadenas, y aunque aún son útiles, tienen limitaciones en sus capacidades. Casi todo en PowerShell es un objeto.

En este artículo, aprenderás algunos conceptos clave cuando se trata de objetos en PowerShell. Al final de este artículo, habrás aprendido cómo aplicar este conocimiento a tus propios scripts mediante ejemplos de código útiles y visualizaciones.

Si eres más un aprendiz visual, siéntete libre de ver el video complementario de este artículo a continuación.

¡Así que prepárate! ¡Te espera una experiencia memorable que te ayudará a dominar el concepto de objetos en PowerShell!

Requisitos previos

En este artículo, aprenderás sobre objetos en PowerShell a través de un enfoque práctico. Si decides seguir y probar los ejemplos de código, Windows PowerShell 5.1 o cualquier versión de PowerShell 6+ debería funcionar. Sin embargo, todos los ejemplos que veas se realizarán en Windows 10 versión 1903 con Windows PowerShell 5.1.

Entendiendo la Anatomía de un Objeto

Los objetos están en todas partes en PowerShell. Es posible que te estés preguntando “¿Cómo se ve un objeto?” En esta primera sección, obtendrás una visión general de lo que consiste un objeto. Una vez que tengas una idea amplia de lo que hace que un objeto sea un objeto, luego podrás sumergirte en algunos ejemplos de código!

Descubriendo los Miembros del Objeto con Get-Member

Los objetos tienen muchos tipos diferentes de información asociada con ellos. En PowerShell, a esta información a veces se le llama miembros. Un miembro de un objeto es un término genérico que se refiere a toda la información asociada con un objeto.

Para descubrir información sobre un objeto (miembros), puedes usar el cmdlet Get-Member. El cmdlet Get-Member es un comando útil que te permite encontrar propiedades disponibles, métodos, etc. para cualquier objeto en PowerShell.

Por ejemplo, digamos que deseas ver los miembros de un objeto en particular devuelto mediante el cmdlet Get-Service. Puedes hacerlo canalizando la salida del comando Get-Service al cmdlet Get-Member como se muestra a continuación.

language-powershell
Get-Service -ServiceName 'BITS' | Get-Member

Acostúmbrate al cmdlet Get-Member. Lo usarás mucho en este artículo.

Cada comando en PowerShell que produce salida puede ser canalizado a Get-Member. Solo recuerda colocar este cmdlet como el último en la canalización, ya que sobrescribirá la salida con su propia salida.

Tipos y Clases de Objetos

Sin entrar en muchos detalles sobre la programación orientada a objetos, cada objeto tiene un “esquema”. El “esquema” de un objeto es una especie de plantilla que contiene el plano para crear un objeto. Ese plano se llama un tipo.

Cada objeto en PowerShell tiene un tipo específico. Cada objeto tiene un plano a partir del cual fue creado. El tipo de objeto está definido por una clase. Considera este ejemplo; 9 es un número, Bluegill es un pez, Labrador es un perro, etc. La clase viene antes del tipo.

Los objetos son instancias de clases con un tipo particular.

No te preocupes por profundizar mucho en este tema. A menos que seas un desarrollador de software, probablemente no necesites preocuparte demasiado por la semántica en este momento. Sin embargo, es un concepto importante de conocer a un nivel básico.

Propiedades

El concepto más importante sobre los objetos que debes entender son las propiedades. Las propiedades son atributos que describen un objeto. Un objeto puede tener muchas propiedades diferentes que representan varios atributos.

Una de las formas más fáciles de descubrir qué propiedades existen en los objetos es usando el cmdlet Get-Member. Puedes ver a continuación que al usar el parámetro MemberType, Get-Member limitará la salida devuelta solo a objetos. También verás que muestra el tipo de objeto System.ServiceProcess.ServiceController también.

PS51> Get-Service | Get-Member -MemberType Property
Get-Service object properties

Ahora toma el ejemplo del servicio BITS que se mencionó anteriormente y observa los valores específicos de las propiedades de ese objeto utilizando el código a continuación. El cmdlet Get-Member te permite encontrar los nombres de las propiedades, pero no los valores. Sin embargo, usando el cmdlet Select-Object de PowerShell, puedes inspeccionar los valores de la propiedad.

A continuación, puedes ver que StartType es una propiedad en el objeto. El objeto devuelto tiene muchos miembros diferentes, pero al usar el cmdlet Select-Object, se limita la salida para mostrar solo esa propiedad.

PS51> Get-Service -ServiceName 'BITS' | Select-Object -Property 'StartType'
BITS service start type

Las propiedades son, con mucho, el componente más común de un objeto con el que trabajarás en PowerShell.

Alias

Algunas propiedades tienen un MemberType de Alias. Los alias son seudónimos de nombres de propiedad. A veces, pueden proporcionar nombres más intuitivos a las propiedades.

Puedes ver un ejemplo de un objeto con alias utilizando el cmdlet Get-Service nuevamente, como se muestra a continuación. La propiedad Name tiene como alias ServiceName y RequiredServices tiene como alias la propiedad ServicesDependedOn.

PS51> Get-Service | Get-Member -MemberType 'AliasProperty'
AliasProperty members on service objects

Cuando una propiedad tiene un alias, puedes hacer referencia al valor de esa propiedad usando el nombre del alias en lugar del nombre real de la propiedad. En este ejemplo, un atributo descriptivo como Name y RequiredServices es más intuitivo y más fácil de escribir que ServiceName y ServicesDependedOn.

Puedes ver un ejemplo de cómo hacer referencia a estos alias a continuación.

# Utiliza la propiedad AliasProperty en lugar de un nombre de propiedad real
PS51> $Svc = Get-Service -ServiceName 'BITS' # Objeto con el que estás trabajando
PS51> $Svc.Name
BITS
PS51> $Svc.RequiredServices

Deberías ver la siguiente salida. Nótese nuevamente que estás manteniendo el código corto, limpio y conciso. La información es la misma, independientemente de si se utiliza el alias o no:

Properties on the BITS service object

Métodos

Las propiedades son solo una parte que crea un objeto; los métodos también son un concepto importante de entender. Los métodos son las acciones que se pueden realizar en un objeto. Al igual que con las propiedades, puedes descubrir los métodos en un objeto utilizando el cmdlet Get-Member.

Para limitar la salida de Get-Member solo a métodos, establece el valor del parámetro MemberType en Method, como se muestra a continuación.

PS51> Get-Service | Get-Member -MemberType 'Method'
Methods on service objects

Como principiante, usarás los métodos con mucha menos frecuencia que las propiedades.

Otros tipos de miembros

Las propiedades, los métodos y los alias no son los únicos tipos de miembros que puede tener un objeto. Sin embargo, serán, con mucho, los tipos de miembros más comunes con los que trabajarás.

Para completar, aquí hay algunos otros tipos de miembros que podrías encontrar.

  • Propiedad de script: se utilizan para calcular valores de propiedad.
  • Propiedad de nota: se utilizan para nombres de propiedad estáticos.
  • Conjuntos de propiedades: estos son como alias que contienen exactamente lo que el nombre indica; conjuntos de propiedades. Por ejemplo, has creado una propiedad personalizada llamada Specs para tu función Get-CompInfo. Specs es en realidad un subconjunto de las propiedades Cpu, Mem, Hdd, IP. El propósito principal de los conjuntos de propiedades es proporcionar un único nombre de propiedad para concatenar un grupo de propiedades.

También es importante mencionar el concepto de eventos de objetos. Los eventos están fuera del alcance de este artículo.

Trabajando con objetos en PowerShell

Ahora que tienes una comprensión básica de lo que consiste un objeto, comencemos a ensuciarnos las manos y entrar en algo de código.

Muchos comandos de PowerShell producen resultados, pero a veces no necesitas ver todo este resultado. Necesitas limitar o manipular de alguna manera ese resultado. Afortunadamente, PowerShell tiene algunos comandos diferentes que te permiten hacer precisamente eso.

Comencemos con un ejemplo de enumerar todos los servicios en el equipo local usando el cmdlet Get-Service como se muestra a continuación. Puedes ver en el resultado que se devuelven muchos servicios diferentes (objetos).

PS51> Get-Service -ServiceName *
Using a wildcard on ServiceName parameter

Controlando las propiedades de los objetos devueltos

Continuando con el ejemplo de Get-Service, tal vez no necesites ver cada propiedad. En cambio, solo necesitas ver las propiedades Status y DisplayName. Para limitar las propiedades devueltas, usarías el cmdlet Select-Object.

El cmdlet Select-Object “filtra” varias propiedades para no ser devueltas al canal de PowerShell. Para “filtrar” propiedades de objetos para que no sean devueltas, puedes usar el parámetro Property y especificar un conjunto delimitado por comas de una o más propiedades para devolver.

A continuación puedes ver un ejemplo de solo devolver las propiedades Status y DisplayName.

PS51> Get-Service -ServiceName * | Select-Object -Property 'Status','DisplayName'
Showing the Status and DisplayName properties

Ordenar objetos

Quizás estés construyendo un informe para mostrar servicios y su estado. Para digerir la información fácilmente, te gustaría ordenar los objetos devueltos por el valor de la propiedad Status. Para hacerlo, puedes usar el cmdlet Sort-Object.

El cmdlet Sort-Object te permite recopilar todos los objetos devueltos y luego mostrarlos en el orden que definas.

Por ejemplo, usando el parámetro Property de Sort-Object, puedes especificar una o más propiedades en los objetos entrantes de Get-Service para ordenar por ellas. PowerShell pasará cada objeto al cmdlet Sort-Object y luego los devolverá ordenados por el valor de la propiedad.

A continuación puedes ver un ejemplo de devolver todos los objetos de servicio ordenados por su propiedad Status devuelta correctamente en orden descendente usando el parámetro de conmutación Descending de Sort-Object.

PS51> Get-Service -ServiceName * | Select-Object -Property 'Status','DisplayName' |
	Sort-Object -Property 'Status' -Descending
Using Sort-Object to sort service objects by Status in descending order

El tubo [ | ] en PowerShell es una de las pocas técnicas de continuación de línea que deberías usar cuando sea necesario. Úsalo en lugar de las comillas invertidas.

Filtrando Objetos

Tal vez decides que no quieres ver todos los servicios en una máquina. En cambio, necesitas limitar la salida por criterios específicos. Una forma de filtrar el número de objetos devueltos es usando el cmdlet Where-Object.

Mientras que el cmdlet Select-Object limita la salida de propiedades específicas, el cmdlet Where-Object limita la salida de objetos enteros.

El cmdlet Where-Object es similar en función a la cláusula WHERE de SQL. Actúa como un filtro de la fuente original para devolver solo ciertos objetos que coinciden con un criterio específico.

Tal vez hayas decidido que solo quieres objetos devueltos con un valor de propiedad Status de Running y solo aquellos con un valor de propiedad DisplayName que comienza con A.

Puedes ver en el siguiente fragmento de código que se insertó una referencia Where-Object entre Select-Object y Sort-Object en el orden del canal. Usando un valor de scriptblock con una condición requerida creada para que cada objeto cumpla a través del parámetro FilterScript, puedes diseñar cualquier tipo de consulta que desees.

Consulta el cmdlet Format-Table si quieres manipular cómo se devuelve la salida a la consola.

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object -FilterScript {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending | Format-Table -AutoSize
Formatting object output

Contando y Promediando Objetos Devueltos

El comando Get-Service devuelve muchos objetos diferentes. Usando el cmdlet Where-Object, has filtrado una parte de esos objetos, ¿pero cuántos? Introduciendo el cmdlet Measure-Object.

El cmdlet Measure-Object es un comando de PowerShell que, entre otras operaciones matemáticas, puede contar cuántos objetos recibe a través del pipeline.

Tal vez te gustaría saber cuántos objetos se devuelven finalmente cuando se ejecutan tus comandos combinados. Puedes dirigir la salida final al cmdlet Measure-Object para encontrar el número total de objetos devueltos como se muestra a continuación.

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending | Measure-Object

Una vez que los comandos hayan terminado de procesarse, verás, en este caso, que inicialmente se devolvieron 21 objetos creados con el cmdlet Get-Service.

Finding the number of objects returned with Measure-Object

Tal vez solo estés buscando el total de objetos devueltos. Dado que el comando Measure-Object devuelve el total de objetos encontrados a través de una propiedad Count, puedes hacer referencia nuevamente al cmdlet Select-Object. Pero esta vez, solo devolviendo la propiedad Count.

PS51> Get-Service * | Select-Object -Property 'Status','DisplayName' |
	Where-Object {$_.Status -eq 'Running' -and $_.DisplayName -like "Windows*" |
		Sort-Object -Property 'DisplayName' -Descending |
			Measure-Object |
				# Empezamos de nuevo, filtrando primero, formateando al final
				Select-Object -Property 'Count'
Only returning the count property

Tomando Acción sobre Objetos con Bucles

A medida que se procesa cada objeto a través del pipeline, puedes tomar acción sobre cada objeto con un bucle. Hay diferentes tipos de bucles en PowerShell, pero manteniéndonos en ejemplos de pipeline, veamos el cmdlet ForEach-Object.

El cmdlet ForEach-Object te permite tomar acción sobre cada objeto que fluye hacia él. Este comportamiento se explica mejor con un ejemplo.

Continuando con el ejemplo de Get-Service, tal vez quieras encontrar todos los servicios en una computadora con Windows cuyo nombre comience con “Windows” y esté en ejecución. Utilizando el cmdlet Where-Object, puedes crear las condiciones como lo hiciste anteriormente.

Where-Object -FilterScript {$_.DisplayName -Like "Windows*" -and $_.Status -eq 'Running'}

Pero ahora, en lugar de devolver objetos completos o incluso algunas propiedades, te gustaría devolver la cadena <ServiceName> está en ejecución para cada objeto utilizando el código **Write-Host -ForegroundColor 'Yellow' <ServiceName> "is running".

Ahora estás manipulando la salida y creando tu propia cadena. La única manera de hacerlo es utilizando el cmdlet ForEach-Object, como se muestra a continuación. A continuación, puedes ver que para cada objeto devuelto mediante Where-Object, PowerShell ejecuta el código Write-Host -ForegroundColor 'Yellow' $_.DisplayName "is running".

PS51> Get-Service -ServiceName * |
	Where-Object {$_.DisplayName -Like "Windows*" -and $_.Status -eq 'Running'} | 
		Foreach-Object {
			Write-Host -ForegroundColor 'Yellow' $_.DisplayName "is running"
		}
Filtering by property with Where-Object

El cmdlet ForEach-Object es útil de muchas maneras. Como ejemplo, podrías incorporar lógica adicional para recorrer cada objeto de servicio encontrado y, según el valor de una propiedad, cambiar el color y el texto de la cadena de salida o incluso realizar una acción adicional, como iniciar un servicio detenido.

¡Imagina las posibilidades que esto te brinda! Con un poco de reflexión y planificación, podrías crear un script que tome un comando y lo ejecute sin esfuerzo en muchos objetos.

Comparando Objetos

A veces necesitas examinar dos objetos y comparar los valores de las propiedades.

Quizás tenga dos sistemas en su red que son casi idénticos. Sin embargo, está experimentando lo que espera ser un problema de configuración con un servicio en uno de los dos sistemas.

Concluye que dado que estos sistemas están en diferentes partes de su red, necesitará usar comandos remotos para recopilar la información en una sesión de PowerShell. Abre tu editor favorito y creas un script. Este script, como puedes ver a continuación, se conecta a dos servidores diferentes y enumera todos los procesos en cada uno de ellos.

$A = 'Svr01a.contoso.com'
$B = 'Svr02b.contoso.com'

$ProcA = Invoke-Command -Computername $A -Scriptblock {Get-Process -Name *}
$ProcB = Invoke-Command -ComputerName $B -Scriptblock {Get-Process -Name *}

Ahora has capturado todos los procesos en cada computadora en las variables $ProcA y $ProcB. Ahora necesitas compararlos. Podrías buscar manualmente en cada conjunto de procesos o podrías hacerlo de manera fácil y usar un cmdlet llamado Compare-Object.

Compare-Object te permite comparar los valores de las propiedades de dos objetos diferentes. Este cmdlet lee cada propiedad en cada objeto, mira sus valores y luego devuelve lo que es diferente, por defecto y también lo que es lo mismo.

Para usar Compare-Object, especifica un parámetro ReferenceObject y un parámetro DifferenceObject proporcionando cada objeto como los valores de parámetro como se muestra a continuación.

Compare-Object -ReferenceObject $ProcA -DifferenceObject $ProcB

Por defecto, Compare-Object solo devolverá diferencias en los objetos indicados por la propiedad SideIndicator. Los símbolos o indicadores laterales utilizados son >, <, y = para mostrar las coincidencias de los objetos que se están comparando.

Running Compare-Object

Puedes usar el parámetro de cambio IncludeEqual con Compare-Object para devolver las propiedades del objeto que son iguales. Si es así, verás == como indicador lateral. De manera similar, puedes usar ExcludeDifferent para dejar fuera las diferencias.

El cmdlet Compare-Object es un cmdlet muy útil. Si deseas aprender más, asegúrate de visitar la documentación en línea.

Trabajando con Objetos Personalizados

Ahora que tienes una buena comprensión de qué son los objetos y cómo puedes trabajar con ellos, ¡es hora de crear tus propios objetos!

Creando Objetos Personalizados a Partir de Tablas de Hash

Una forma de crear tus propios objetos es mediante el uso de tablas de hash. Las tablas de hash son conjuntos de pares clave/valor precisamente lo que necesitas para crear propiedades para un objeto.

Comencemos creando un objeto de PowerShell personalizado con algunas clave/valor usando una tabla de hash. En el siguiente ejemplo, estás creando una tabla de hash. Esta tabla de hash representa un único objeto y sus propiedades. Una vez que la tabla de hash $CarHashtable ha sido definida, luego puedes usar el PsCustomObject acelerador de tipo.

El acelerador de tipo pscustomobject es una forma rápida de crear una instancia de la clase pscustomobject. Este comportamiento se llama casting.

Al final del siguiente fragmento de código, tienes un objeto ($CarObject) del tipo pscustomobject con cinco propiedades asignadas.

## Define el hashtable
$CarHashtable = @{
	Brand      = 'Ford'
	Style      = 'Truck'
	Model      = 'F-150'
	Color      = 'Red'
	Drivetrain = '4x4'
}

## Crea un objeto
$CarObject = [PsCustomObject]$CarHashTable

Alternativamente, también puedes usar el cmdlet New-Object. Utilizando el mismo hashtable, en lugar de usar el acelerador de tipo pscustomobject, podrías hacerlo de la manera larga con New-Object. Un ejemplo de esto se muestra a continuación.

$CarHashtable = @{
	Brand      = 'Ford'
	Style      = 'Truck'
	Model      = 'F-150'
	Color      = 'Red'
	Drivetrain = '4x4'
}
#Crea un objeto
$CarObject = New-Object -TypeName PsObject -Properties $CarHashtable

Cuando se crea $CarObject, ahora puedes ver que puedes hacer referencia a cada una de las propiedades como si provinieran de un cmdlet de PowerShell incorporado como Get-Service.

Inspecting object properties

Agregando y quitando propiedades

No solo puedes crear objetos personalizados, sino que también puedes agregarles cosas. ¿Recuerdas el uso del cmdlet Get-Member? Get-Member tiene un relativo llamado Add-Member. El cmdlet Add-Member no enumera miembros, los agrega.

Usando el objeto personalizado creado previamente como ejemplo, tal vez quieras agregar una propiedad de año de modelo a ese objeto. Puedes hacerlo pasando un objeto a Add-Member especificando:

  • El tipo de miembro (en este caso un simple \texttt{NoteProperty})
  • El nombre de la propiedad (\texttt{Year})
  • El valor de la propiedad (\texttt{Value})

Puedes ver un ejemplo de esto a continuación.

PS51> $CarObject | Add-Member -MemberType NoteProperty -Name 'Year' -Value '2010'

Puedes ver abajo nuevamente que aparece como cualquier otra propiedad.

Adding and viewing a new property

Puedes usar técnicas similares para agregar muchos tipos diferentes de miembros. Si deseas explorar más por tu cuenta, echa un vistazo a la Add-Member documentación.

También puedes eliminar fácilmente un miembro de un objeto. Aunque no hay un cmdlet Remove-Member, aún puedes hacer que suceda llamando al método Remove() en el objeto como se muestra a continuación. Aprenderás sobre métodos en la próxima sección.

PS51> $CarObject.psobject.properties.remove('Drivetrain')

Introducción rápida a los Métodos

A lo largo de este artículo, has estado trabajando con propiedades. Has leído valores de propiedades, creado tus propias propiedades y las has agregado y eliminado. Pero realmente no has hecho mucho en el entorno. No has cambiado nada en el servidor. Vamos a tomar alguna acción con métodos.

Los métodos realizan algún tipo de acción. Los objetos almacenan información mientras que los métodos toman acción.

Por ejemplo, puedes estar al tanto del comando Stop-Service. Este comando detiene un servicio de Windows. Para hacerlo, puedes enviar un objeto de Get-Service directamente a Stop-Service para que suceda.

Puedes ver a continuación un ejemplo de cómo detener el servicio BITS. Este ejemplo detiene el servicio BITS y luego verifica el estado para asegurarse de que esté detenido. Has realizado dos acciones con cmdlets; detener el servicio y verificar el estado.

PS51> Get-Service -ServiceName 'BITS' | Stop-Service
PS51> Get-Service -ServiceName 'BITS'

En lugar de ejecutar Get-Service dos veces y ejecutar un comando separado, Stop-Service, en su lugar, puedes aprovechar los métodos que están integrados directamente en los objetos de servicio. Muchos objetos tienen métodos. En este caso, Stop-Service e incluso esa segunda referencia de Get-Service ni siquiera es necesaria.

Running commands to stop and start a service

Al invocar métodos en el propio objeto de servicio, puedes detener y obtener el estado actualizado, todo usando un solo objeto. A continuación, puedes ver esto en acción. Observa que al usar los métodos Stop() y Start(), puedes manipular el servicio de la misma manera que lo hicieron los comandos.

Para asegurarte de que el valor de la propiedad Status esté actualizado después de que haya cambiado el estado del servicio, puedes invocar el método Refresh(), que actúa como otra llamada al comando Get-Service.

## Detener BITS en la máquina local
$Svc = Get-Service -ServiceName 'BITS' #Objeto con el que estás trabajando
$Svc.Stop() #Método / acción que estás realizando
$Svc.Refresh() #Método / acción que estás realizando
$Svc.Status #Propiedad

#Iniciar BITS en la máquina local
$Svc = Get-Service -ServiceName 'BITS' #Objeto con el que estás trabajando
$Svc.Start() #Método / acción que estás realizando
$Svc.Refresh() #Método / acción que estás realizando
$Svc.Status #Propiedad

Deberías ver la siguiente salida:

Executing methods on the service object

Para obtener más información sobre los métodos, consulta el tema de ayuda about_Methods.

Conclusión

Hay muchas cosas que puedes hacer con objetos en PowerShell. Este artículo fue solo una introducción para ayudarte a comenzar a aprender sobre ellos. En este artículo, has aprendido algunos conceptos básicos sobre qué son los objetos, cómo tomar acciones, manipularlos y crearlos. Has visto algunos escenarios diferentes que te han mostrado cómo realizar estas tareas con ejemplos de código. Mantén la calma y aprende PowerShell. ¡Gracias por leer!

Source:
https://adamtheautomator.com/powershell-objects/