parse - Formatear instancias[pscustomobject] devueltas por Invoke-RestMethod o ConvertFrom-Json
powershell convertfrom json (2)
Estoy intentando crear una tabla a partir de un archivo JSON que recibo de una API RESTful.
Cuando imprimo la propiedad del objeto json obtengo un resultado como este:
PS> Write-Output JSON.Object Object1 : @{key1=property; key2=property; key3=property; key4=property} Object2 : @{key1=property; key2=property; key3=property; key4=property} Object3 : @{key1=property; key2=property; key3=property; key4=property} Object4 : @{key1=property; key2=property; key3=property; key4=property}
La salida que me gustaría ver es esta:
Name key1 key2 key3 key4 ----- ---- ---- ---- ---- Object1 property property property property Object2 property property property property Object3 property property property property
Además, ¿es posible evitar mostrar una clave específica y sus propiedades?
Ejemplo:
Name key1 key2 key4 # ← Not displaying key3 ----- ---- ---- ---- Object1 property property property Object2 property property property Object3 property property property
Debe agregar el nombre clave principal como nombre de propiedad a los objetos anidados:
$json.Object | ForEach-Object {
foreach ($p in $_.PSObject.Properties) {
$p.Value | Select-Object @{n=''Name'';e={$p.Name}},*
}
}
Tenga en cuenta que PowerShell representará el resultado en forma de lista de forma predeterminada, ya que sus objetos tienen más de 4 propiedades. Format-List -AutoSize
a través de Format-List -AutoSize
para obtener resultados tabulares.
Para complementar la elegante respuesta de Ansgar Wiecher con información de fondo :
Definamos la entrada de muestra que simula un único objeto anidado convertido a una instancia de PowerShell [pscustomobject]
través de ConvertFrom-Json
:
$objFromJson = [pscustomobject] @{
Object1 = [pscustomobject] @{key1=''o11''; key2=''o12''; key3=''o13''; key4=''o14''}
Object2 = [pscustomobject] @{key1=''o21''; key2=''o22''; key3=''o23''; key4=''o24''}
Object3 = [pscustomobject] @{key1=''o31''; key2=''o32''; key3=''o33''; key4=''o34''}
Object4 = [pscustomobject] @{key1=''o41''; key2=''o42''; key3=''o43''; key4=''o44''}
Object5 = [pscustomobject] @{key1=''o51''; key2=''o52''; key3=''o53''; key4=''o54''}
}
$objFromJson
salida $objFromJson
da salida que está formateada como en la pregunta.
¿Por qué esto da como resultado el formato de salida que se muestra en la pregunta?
Para tipos como [pscustomobject]
, que no tienen definiciones de formato explícitas definidas para ellos (a través de archivos *.ps1xml
y cargados implícitamente en la sesión o explícitamente a través de Update-FormatData
), PowerShell decide qué formato predeterminado usar en función del número de propiedades del tipo:
- Un tipo con hasta 4 propiedades usa implícitamente
Format-Table
- un tipo con 5 o más propiedades usa implícitamente
Format-List
La entrada de muestra en la pregunta es, presumiblemente, abreviada ; con solo 4 propiedades, habría resultado una pantalla tabular .
Las propiedades mismas se representan llamando a .PSObject.ToString()
en sus valores, que es típicamente la misma representación que obtendría si .PSObject.ToString()
referencia al objeto dentro de una cadena de comillas dobles, excepto que esta última siempre usa el formato invariante de cultura, mientras que .ToString()
respetará la cultura actual, si el tipo lo admite.
En el caso de una instancia [pscustomobject]
, esto da como resultado una representación que se asemeja a un literal hashtable, pero no es una (para información de fondo, vea esta respuesta mía); p.ej:
> $objFromJson.Object1.PSObject.ToString()
@{key1=o11; key2=o12; key3=o13; key4=o14}
Remodelación de los datos como se desee
No hay forma de usar cmdlets de formateo como Format-Table
directamente para obtener el resultado deseado; los datos deben reformarse primero:
Específicamente, las propiedades del objeto $objFromJson
deben $objFromJson
formar en una colección de objetos personalizados :
cuya propiedad
Name
contiene el nombre de una propiedad dada, ycuyas otras propiedades son las propiedades del objeto del valor de esa propiedad; en otras palabras: las propiedades del valor de la propiedad de entrada deben ser propiedades del propio objeto de salida.
La extracción de $objFromJson
las propiedades es facilitada por PowerShell al agregar (entre otras) una propiedad .PSObject
oculta a todos los objetos, cuya propiedad .Properties
contiene una colección de todas las definiciones de propiedad del objeto (nombre, valor, metadatos adicionales como el tipo de propiedad, ...); p.ej:
> $objFromJson.Object1.PSObject.Properties
MemberType : NoteProperty
IsSettable : True
IsGettable : True
Value : o11
TypeNameOfValue : System.String
Name : key1
IsInstance : True
# ... remaining properties
La salida de la colección de las definiciones de propiedad de $objFromJson
y la extracción de las propiedades de Name
y Value
las definiciones es un paso en la dirección correcta:
> $objFromJson.PSObject.Properties | Select-Object Name, Value
Name Value
---- -----
Object1 @{key1=o11; key2=o12; key3=o13; key4=o14}
Object2 @{key1=o21; key2=o22; key3=o23; key4=o24}
Object3 @{key1=o31; key2=o32; key3=o33; key4=o34}
Object4 @{key1=o41; key2=o42; key3=o43; key4=o44}
Object5 @{key1=o51; key2=o52; key3=o53; key4=o54}
Sin embargo, debemos hacer que las propiedades .Value
propiedad .Value
de los objetos de salida se obtengan con valores individuales de propiedad.
La elegante respuesta de Ansgar demuestra cómo hacer eso en una sola tubería.
Permítanme complementarlo con una función de ayuda reutilizable derivada de él:
function ConvertTo-Collection($InputObject) {
foreach ($obj in $InputObject) {
foreach ($prop in $obj.PSObject.Properties) {
$prop.Value | Select-Object @{ n=''Name''; e={ $prop.Name }}, *
}
}
}
Con esa función en su lugar, la salida deseada ahora se puede lograr así:
ConvertTo-Collection $objFromJson | Format-Table
Para excluir una propiedad específica, como key3
:
ConvertTo-Collection $objFromJson | Select-Object -ExcludeProperty key3 | Format-Table