- 10/05/2020
- 8 minutos para leer
-
- j
- m
- s
- j
- c
PSCustomObject
s son una gran herramienta para añadir a tu cinturón de herramientas de PowerShell. Vamos a empezar con los fundamentosy trabajar nuestro camino en las características más avanzadas. La idea de usar un PSCustomObject
es tener una forma sencilla de crear datos estructurados. Echa un vistazo al primer ejemplo y tendrás una mejor idea de lo que significa.
Note
La versión original de este artículo apareció en el blog escrito por @KevinMarquette. El equipo dePowerShell agradece a Kevin por compartir este contenido con nosotros. Por favor, echa un vistazo a su blog enPowerShellExplained.com.
- Crear un PSCustomObject
- Convertir un hashtable
- Enfoque de legado
- Guardar en un archivo
- Trabajar con propiedades
- Añadir propiedades
- Quitar propiedades
- Enumerar nombres de propiedades
- Acceder dinámicamente a las propiedades
- Convertir PSCustomObject en un hashtable
- Prueba de propiedades
- Añadir métodos de objetos
- Objetos vs Tipos de valor
- psobject.copy()
- PSTypeName para tipos de objetos personalizados
- Using DefaultPropertySet (the long way)
- Update-TypeData con DefaultPropertySet
- Update-TypeData con ScriptProperty
- Parámetros de función
- Función OutputType
- Pensamientos finales
Crear un PSCustomObject
Me encanta usar en PowerShell. La creación de un objeto utilizable nunca ha sido más fácil.Debido a eso, voy a pasar por encima de todas las otras maneras que usted puede crear un objeto, pero necesito mencionar que la mayoría de estos ejemplos son PowerShell v3.0 y más reciente.
$myObject = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Este método funciona bien para mí porque yo uso hashtables para casi todo. Pero hay momentos en los que me gustaría que PowerShell tratara las hashtables más como un objeto. El primer lugar youounotice la diferencia es cuando se desea utilizar Format-Table
o Export-CSV
y te das cuenta de que ahashtable es sólo una colección de pares clave/valor.
A continuación, puede acceder y utilizar los valores como lo haría un objeto normal.
$myObject.Name
Convertir un hashtable
Ya que estoy en el tema, ¿sabías que puedes hacer esto:
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = $myHashtable
Yo prefiero crear el objeto desde el principio pero hay veces que tienes que trabajar con ahashtable primero. Este ejemplo funciona porque el constructor toma un hashtable para las propiedades del objeto. Una nota importante es que aunque este método funciona, no es un equivalente exacto. La mayor diferencia es que el orden de las propiedades no se conserva.
Enfoque de legado
Es posible que hayas visto a la gente usar New-Object
para crear objetos personalizados.
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = New-Object -TypeName PSObject -Property $myHashtable
Esta forma es bastante más lenta, pero puede ser su mejor opción en las primeras versiones de PowerShell.
Guardar en un archivo
Encuentro la mejor manera de guardar un hashtable en un archivo es guardarlo como JSON. Usted puede importar de nuevo en un
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path$myObject = Get-Content -Path $Path | ConvertFrom-Json
Cubro más formas de guardar objetos a un archivo en mi artículo sobreLas muchas maneras de leer y escribir en archivos.
Trabajar con propiedades
Añadir propiedades
Todavía puedes añadir nuevas propiedades a tu PSCustomObject
con Add-Member
.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'$myObject.ID
Quitar propiedades
También puedes eliminar propiedades de un objeto.
$myObject.psobject.properties.remove('ID')
La psobject
es una propiedad oculta que te da acceso a los metadatos del objeto base.
Enumerar nombres de propiedades
A veces necesitas una lista de todos los nombres de propiedades de un objeto.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
También podemos obtener esta misma lista de la propiedad psobject
.
$myobject.psobject.properties.name
Acceder dinámicamente a las propiedades
Ya he mencionado que se puede acceder directamente a los valores de las propiedades.
$myObject.Name
Puedes utilizar una cadena para el nombre de la propiedad y seguirá funcionando.
$myObject.'Name'
Podemos dar un paso más y utilizar una variable para el nombre de la propiedad.
$property = 'Name'$myObject.$property
Sé que parece extraño, pero funciona.
Convertir PSCustomObject en un hashtable
Para continuar con la última sección, puedes recorrer dinámicamente las propiedades y crear un hashtable a partir de ellas.
$hashtable = @{}foreach( $property in $myobject.psobject.properties.name ){ $hashtable = $myObject.$property}
Prueba de propiedades
Si necesitas saber si una propiedad existe, puedes simplemente comprobar que esa propiedad tiene un valor.
if( $null -ne $myObject.ID )
Pero si el valor pudiera ser $null
puedes comprobar si existe verificando elpsobject.properties
para ello.
if( $myobject.psobject.properties.match('ID').Count )
Añadir métodos de objetos
Si necesitas añadir un método de script a un objeto, puedes hacerlo con Add-Member
y unScriptBlock
. Tienes que usar la variable automática this
de referencia al objeto actual. Aquí está ascriptblock
para convertir un objeto en un hashtable. (mismo código del último ejemplo)
Entonces lo añadimos a nuestro objeto como una propiedad de script.
Entonces podemos llamar a nuestra función así:
$myObject.ToHashtable()
Objetos vs Tipos de valor
Los objetos y los tipos de valor no manejan las asignaciones de variables de la misma manera. Si se asignan tipos de valor entre sí, sólo el valor se copia a la nueva variable.
$first = 1$second = $first$second = 2
En este caso, $first
es 1 y $second
es 2.
Las variables de objeto mantienen una referencia al objeto real. Cuando se asigna un objeto a una newvariable, siguen haciendo referencia al mismo objeto.
$third = @{Key=3}$fourth = $third$fourth.Key = 4
Como $third
y $fourth
hacen referencia a la misma instancia de un objeto, tanto $third.key
como$fourth.Key
son 4.
psobject.copy()
Si necesitas una copia real de un objeto, puedes clonarlo.
$third = @{Key=3}$fourth = $third.psobject.copy()$fourth.Key = 4
Clone crea una copia superficial del objeto. Ahora tienen diferentes instancias y $third.key
es 3y $fourth.Key
es 4 en este ejemplo.
Llamo a esto una copia superficial porque si tienes objetos anidados. (donde las propiedades contienen otros objetos). Sólo se copian los valores de nivel superior. Los objetos hijos se referenciarán entre sí.
PSTypeName para tipos de objetos personalizados
Ahora que tenemos un objeto, hay algunas cosas más que podemos hacer con él que pueden no ser tan obvias. Lo primero que tenemos que hacer es darle un PSTypeName
. Esta es la forma más común que veo la gente lo hace:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Recientemente descubrí otra manera de hacer esto de este post por /u/markekraus. Hice un littledigging y más posts sobre la idea de Adam Bertram y Mike Shepard donde talkabout este enfoque que le permite definir en línea.
$myObject = @{ PSTypeName = 'My.Object' Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Me encanta lo bien que esto sólo encaja en el lenguaje. Ahora que tenemos un objeto con un nombre de tipo adecuado, podemos hacer algunas cosas más.
Nota
También puedes crear tipos personalizados de PowerShell usando clases de PowerShell. Para más información, veaPowerShell Class Overview.
Using DefaultPropertySet (the long way)
PowerShell decide por nosotros qué propiedades mostrar por defecto. Muchos de los comandos nativos tienen un archivo de formato.ps1xml
que hace todo el trabajo pesado. Desde este post de Boe Prox, hay otra manera de hacer esto en nuestro objeto personalizado usando sólo PowerShell. Podemos darle unMemberSet
para que utilice.
Ahora cuando mi objeto sólo cae en la cáscara, sólo mostrará esas propiedades por defecto.
Update-TypeData con DefaultPropertySet
Esto está bien pero recientemente vi una mejor manera cuando watchingPowerShell unplugged 2016 con Jeffrey Snover & Don Jones. Jeffrey estaba usandoUpdate-TypeData para especificar las propiedades por defecto.
$TypeData = @{ TypeName = 'My.Object' DefaultDisplayPropertySet = 'Name','Language'}Update-TypeData @TypeData
Eso es lo suficientemente simple que casi podría recordarlo si no tuviera este post como quickreference. Ahora puedo crear fácilmente objetos con un montón de propiedades y aún así darle una agradable cleanview cuando se mira desde el shell. Si necesito acceder o ver esas otras propiedades, que’restill allí.
$myObject | Format-List *
Update-TypeData con ScriptProperty
Algo más que saqué de ese video fue la creación de propiedades de script para sus objetos. Este sería un buen momento para señalar que esto funciona para los objetos existentes también.
Usted puede hacer esto antes de su objeto se crea o después y todavía va a funcionar. Esto es lo que hace que esto sea diferente a usar Add-Member
con una propiedad de script. Cuando se utiliza Add-Member
la forma Ireferenced antes, sólo existe en esa instancia específica del objeto. Este se aplica a todos los objetos con este TypeName
.
Parámetros de función
Ahora puede utilizar estos tipos personalizados para los parámetros en sus funciones y scripts. Usted puede tener onefunction crear estos objetos personalizados y luego pasarlos en otras funciones.
param( $Data )
PowerShell requiere que el objeto es el tipo especificado. Lanza un error de validación si el tipo no coincide automáticamente para ahorrarte el paso de comprobarlo en tu código. Un gran ejemplo de dejar que PowerShell haga lo que mejor sabe hacer.
Función OutputType
También puede definir un OutputType
para sus funciones avanzadas.
function Get-MyObject{ param ( ...
El valor del atributo OutputType es sólo una nota de documentación. No se deriva del código de la función ni se compara con la salida real de la función.
La razón principal por la que se utiliza un tipo de salida es para que la meta información sobre su función refleje sus intenciones. Cosas como Get-Command
y Get-Help
que su entorno de desarrollo puede aprovechar. Si quieres más información, entonces echa un vistazo a la ayuda para ello:about_Functions_OutputTypeAttribute.
Dicho esto, si estás usando Pester para probar tus funciones de forma unitaria, entonces sería una buena idea validar que los objetos de salida coincidan con tu OutputType. Esto podría atrapar las variables que acaban de caer en la tubería cuando no deberían.
Pensamientos finales
El contexto de esto fue todo acerca de , pero mucha de esta información se aplica toobjects en general.
He visto la mayoría de estas características de pasada antes, pero nunca los vio presentado como una colección deinformación en PSCustomObject
. Justo esta semana pasada me topé con otra y me sorprendió que no la hubiera visto antes. Quería reunir todas estas ideas para que puedas ver el panorama general y ser consciente de ellas cuando tengas la oportunidad de utilizarlas. Espero que aprendas algo y encuentres la forma de incorporarlo a tus guiones.