¿Qué es Windows PowerShell y qué come? Parte 4: trabajar con objetos, clases personalizadas



La salida de texto de los comandos en la ventana del intérprete de PowerShell es solo una forma de mostrar información en una forma legible para los humanos. De hecho, el entorno se centra en trabajar con objetos: los cmdlets y las funciones los reciben en la entrada y regresan en la salida , y los tipos de variables disponibles en modo interactivo y en scripts se basan en clases .NET. En el cuarto artículo del ciclo, estudiaremos trabajar con objetos con más detalle.

Tabla de contenido:


PowerShell




ForEach-Object, Group-Object Measure-Object
.NET COM (New-Object)

PSCustomObject


PowerShell


Recuerde que un objeto es una colección de campos de datos (propiedades, eventos, etc.) y sus métodos de procesamiento (métodos). Su estructura está determinada por el tipo, que generalmente se basa en las clases utilizadas en la plataforma unificada .NET Core. También es posible trabajar con objetos COM, CIM (WMI) y ADSI. Se necesitan propiedades y métodos para realizar diversas acciones en los datos, además de PowerShell, los objetos se pueden pasar como argumentos a funciones y cmdlets, valores asignados a variables y también hay un mecanismo para componer comandos (tubería o tubería). Cada comando en la tubería pasa su salida al siguiente a su vez, objeto por objeto. Para el procesamiento, puede usar cmdlets compilados o crear sus propias funciones avanzadaspara realizar varias manipulaciones con objetos en la tubería: filtrar, ordenar, agrupar e incluso cambiar su estructura. La transferencia de datos en este formulario tiene una gran ventaja: el equipo receptor no necesita analizar el flujo de bytes (texto), toda la información necesaria se extrae fácilmente al referirse a las propiedades y métodos correspondientes.

Ver estructura de objeto


Por ejemplo, ejecute el cmdlet Get-Process, que le permite obtener información sobre los procesos que se ejecutan en el sistema:



muestra algunos datos de texto formateados que no dan una idea de las propiedades de los objetos devueltos y sus métodos. Para ajustar la salida, debe aprender a examinar la estructura de los objetos, y el cmdlet Get-Member nos ayudará con esto:

Get-Process | Get-Member



Aquí ya vemos el tipo y la estructura, y con la ayuda de parámetros adicionales podemos, por ejemplo, mostrar solo las propiedades del objeto que ingresó la entrada:

Get-Process | Get-Member -MemberType Property

Este conocimiento será necesario para resolver tareas administrativas de forma interactiva o para escribir sus propios scripts: por ejemplo, para obtener información sobre procesos bloqueados por la propiedad Responding.

Filtrado de objetos


PowerShell le permite canalizar objetos que satisfacen una condición específica:

Where-Object {   }

El resultado de la ejecución del bloque de script entre paréntesis de operador debe ser un valor lógico. Si es verdadero ($ verdadero), el objeto que ingresó el cmdlet Where-Object se pasará por la tubería, de lo contrario (el valor $ false) se eliminará. Por ejemplo, enumeramos los servicios de Windows Server detenidos, es decir, aquellos con la propiedad Estado establecida en Detenido:

Get-Service | Where-Object {$_.Status -eq "Stopped"}



Aquí vemos nuevamente la representación textual, pero si desea comprender el tipo y la estructura interna de los objetos que pasan por la tubería, es fácil:

Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member



Ordenar objetos


Al canalizar objetos, a menudo es necesario ordenarlos. Los nombres de propiedad (claves de clasificación) se pasan al cmdlet Sort-Object y devuelve los objetos ordenados por sus valores. La salida de los procesos en ejecución se puede ordenar fácilmente por el tiempo de procesador empleado (propiedad de la CPU):

Get-Process | Sort-Object –Property cpu

El parámetro -Property se puede omitir al llamar al cmdlet Sort-Object; se usa de manera predeterminada. Para la ordenación inversa, use el parámetro -Descendente:

Get-Process | Sort-Object cpu -Descending



Selección de objetos y sus partes.


El cmdlet Select-Object le permite seleccionar un número específico de objetos al principio o al final de una tubería mediante los parámetros -Primero o -Último. Con él, puede seleccionar objetos individuales o ciertas propiedades, así como crear nuevos objetos sobre su base. Analizaremos el trabajo del cmdlet con ejemplos simples.

El siguiente comando muestra información sobre 10 procesos que consumen la cantidad máxima de RAM (propiedad WS):

Get-Process | Sort-Object WS -Descending | Select-Object -First 10



Puede seleccionar solo ciertas propiedades de los objetos que pasan por la tubería y crear otras nuevas sobre la base de:

Get-Process | Select-Object ProcessName, Id -First 1

Como resultado de la canalización, obtendremos un nuevo objeto cuya estructura será diferente de la estructura devuelta por el cmdlet Get-Process. Verificaremos esto usando Get-Member:

Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member



Tenga en cuenta que Select-Object devuelve un solo objeto (-Primero 1), que solo tiene dos campos especificados por nosotros: sus valores se copiaron del primer objeto pasado a la tubería con el cmdlet Get-Process. Usando Select-Object, se basa una de las formas de crear objetos en scripts de PowerShell:

$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType()



Con Select-Object, puede agregar propiedades calculadas a objetos que deben representarse como una tabla hash . En este caso, el valor de su primera clave corresponde al nombre de la propiedad, y el valor de la segunda corresponde al valor de la propiedad para el elemento actual de la tubería:

Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}}



Veamos la estructura de los objetos que pasan por la tubería:

Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member



Para cada objeto, objeto de grupo y objeto de medida


Hay otros cmdlets para trabajar con objetos. Por ejemplo, hablaremos de los tres más útiles:

ForEach-Object le permite ejecutar código de PowerShell para cada objeto en la tubería:

ForEach-Object {   }

Group-Object agrupa objetos por valor de propiedad:

Group-Object PropertyName

Si lo ejecuta con el parámetro -NoElement, puede encontrar el número de elementos en grupos.

Measure-Object agrega varios parámetros de resumen por los valores de los campos de objetos en la tubería (calcula la suma y también encuentra el valor mínimo, máximo o promedio):

Measure-Object -Property PropertyName -Minimum -Maximum -Average -Sum

Por lo general, los cmdlets considerados se usan de forma interactiva, y los scripts a menudo crean funciones con los bloques Begin, Process y End.

Crear objetos .NET y COM (New-Object)


Hay muchos componentes de software con interfaces .NET Core y COM que son útiles para los administradores del sistema. Con la clase System.Diagnostics.EventLog, puede administrar los registros del sistema directamente desde Windows PowerShell. Veamos un ejemplo de creación de una instancia de esta clase con el cmdlet New-Object con el parámetro -TypeName:

New-Object -TypeName System.Diagnostics.EventLog



Como no especificamos un registro de eventos específico, la instancia resultante de la clase no contiene datos. Para cambiar esto, durante su creación, debe llamar al método de constructor especial utilizando el parámetro -ArgumentList. Si queremos acceder al registro de la aplicación, pase la cadena "Aplicación" como argumento al constructor:

$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog



Tenga en cuenta: guardamos la salida del comando en la variable $ AppLog. Aunque las tuberías se usan comúnmente en modo interactivo, las secuencias de comandos a menudo requieren mantener una referencia de objeto. Además, las principales clases de .NET Core están contenidas en el espacio de nombres del sistema: PowerShell busca de forma predeterminada los tipos especificados en él, por lo que escribir Diagnostics.EventLog en lugar de System.Diagnostics.EventLog es bastante correcto.

Para trabajar con el diario, puede consultar los métodos apropiados:

$AppLog | Get-Member -MemberType Method



Digamos que se borra utilizando el método Clear () con derechos de acceso:

$AppLog.Clear()

El cmdlet New-Object también se usa para trabajar con componentes COM. Hay bastantes de ellos, desde las bibliotecas suministradas con el servidor de secuencias de comandos de Windows hasta aplicaciones ActiveX, como, por ejemplo, Internet Explorer. Para crear un objeto COM, debe especificar el parámetro -ComObject con el identificador de programa ProgId de la clase deseada:

New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObject

Para crear sus propios objetos con una estructura arbitraria, usar New-Object parece demasiado arcaico y engorroso; este cmdlet se usa para trabajar con componentes de software externos a PowerShell. En artículos posteriores, este tema se discutirá con más detalle. Además de los objetos .NET y COM, también aprenderemos sobre los objetos CIM (WMI) y ADSI.

Llamando a métodos estáticos


No es posible crear instancias de algunas clases de .NET Core: estas incluyen System.Environment y System.Math. Son estáticos y contienen solo propiedades y métodos estáticos. En esencia, estas son bibliotecas de referencia que se utilizan sin crear objetos. Puede hacer referencia a una clase estática a través de un literal, encerrando el nombre del tipo entre corchetes. Además, si observa la estructura del objeto utilizando Get-Member, veremos el tipo System.RuntimeType en lugar de System.Environment:

[System.Environment] | Get-Member



Para ver solo elementos estáticos, debe llamar a Get-Member con el parámetro -Static (preste atención al tipo de objeto):

[System.Environment] | Get-Member -Static



Para acceder a propiedades y métodos estáticos, se utilizan dos puntos consecutivos en lugar de un punto después de un literal:

[System.Environment]::OSVersion

O

$test=[System.Math]::Sqrt(25) 
$test
$test.GetType()



Escriba PSCustomObject


Entre los muchos tipos de datos disponibles en PowerShell, vale la pena mencionar PSCustomObject, diseñado para almacenar objetos con una estructura arbitraria. Crear un objeto de este tipo con el cmdlet New-Object se considera una forma clásica, pero engorrosa y obsoleta:

$object = New-Object  –TypeName PSCustomObject -Property @{Name = 'Ivan Danko'; 
                                          City = 'Moscow';
                                          Country = 'Russia'}

Veamos la estructura del objeto:

$object | Get-Member



A partir de PowerShell 3.0, hay disponible otra sintaxis:

$object = [PSCustomObject]@{Name = 'Ivan Danko'; 
                                          City = 'Moscow';
                                          Country = 'Russia'
}

Puede acceder a los datos de una de las formas equivalentes:

$object.Name

$object.'Name'

$value = 'Name'
$object.$value

Aquí hay un ejemplo de cómo convertir una tabla hash existente en un objeto:

$hash = @{'Name'='Ivan Danko'; 'City'='Moscow'; 'Country'='Russia'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()



Uno de los inconvenientes de los objetos de este tipo es que el orden de sus propiedades puede cambiar. Para evitar esto, debe usar el atributo [ordenado]:

$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko'; 
                                          City = 'Moscow';
                                          Country = 'Russia'
}

Hay otras opciones para crear un objeto: arriba examinamos el uso del cmdlet Select-Object . Queda por hacer frente a la adición y eliminación de elementos. Hacer esto para el objeto del ejemplo anterior es bastante simple:

$object | Add-Member –MemberType NoteProperty –Name Age  –Value 33
$object | Get-Member



El cmdlet Add-Member le permite agregar no solo propiedades, sino también métodos al objeto $ object creado anteriormente mediante la construcción "-MemberType ScriptMethod":

$ScriptBlock = {
    #  
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member

Nota: para almacenar el código para el nuevo método, utilizamos la variable $ ScriptBlock de tipo ScriptBlock.



Para eliminar propiedades, use el método apropiado:

$object.psobject.properties.remove('Name')

Creando tus propias clases


PowerShell 5.0 introduce la capacidad de definir clases usando la sintaxis característica para lenguajes de programación orientados a objetos. La palabra de servicio Clase está destinada a esto, después de lo cual debe especificar el nombre de la clase y describir su cuerpo entre paréntesis de operador:

class MyClass
{
    #  
}

Este es un verdadero tipo de .NET Core, cuyo cuerpo describe sus propiedades, métodos y otros elementos. Considere un ejemplo de una definición de clase simple:

class MyClass 
{
     [string]$Name
     [string]$City
     [string]$Country
}

Para crear un objeto (una instancia de una clase), use el cmdlet New-Object o un literal del tipo [MyClass] y el nuevo método pseudoestático (constructor predeterminado):

$object = New-Object -TypeName MyClass

o

$object = [MyClass]::new()

Analicemos la estructura del objeto:

$object | Get-Member



No olvide el alcance: no puede referirse al nombre del tipo como una cadena o usar un literal de tipo fuera del script o módulo en el que se define la clase. Al mismo tiempo, las funciones pueden devolver instancias de la clase (objetos) que estarán disponibles fuera del módulo o script.

Después de crear el objeto, complete sus propiedades:

$object.Name = 'Ivan Danko'
$object.City = 'Moscow'
$object.Country = 'Russia'
$object



Tenga en cuenta que en la descripción de la clase no solo se establecen los tipos de propiedad, sino también sus valores predeterminados:

class Example
{
     [string]$Name = 'John Doe'
}

La descripción del método de clase se asemeja a la descripción de una función, pero sin usar la palabra función función. Como en la función, los parámetros se pasan a los métodos, si es necesario:

class MyClass 
{
     [string]$Name
     [string]$City
     [string]$Country
     
     # 
     Smile([bool]$param1)
     {
         If($param1) {
            Write-Host ':)'
         }
     }
}

Ahora el representante de nuestra clase sabe sonreír:

$object = [MyClass]::new()
$object.Smile($true)

Los métodos se pueden sobrecargar, además, la clase tiene propiedades y métodos estáticos , así como constructores cuyos nombres coinciden con el nombre de la clase misma. Una clase definida en un script o módulo de PowerShell puede servir como base para otra, así es como se implementa la herencia. Al mismo tiempo, el uso de clases .NET existentes está permitido como base:

class MyClass2 : MyClass
{
      #  ,     MyClass
}
[MyClass2]::new().Smile($true)

Nuestra descripción de trabajar con objetos en PowerShell no es exhaustiva. En las siguientes publicaciones, trataremos de profundizarlo con ejemplos prácticos: el quinto artículo de la serie estará dedicado a los problemas de integración de PowerShell con componentes de software de terceros. Las partes pasadas se pueden encontrar en los enlaces a continuación.



1: Windows PowerShell
2: Windows PowerShell
3: ,


All Articles