Convertir en CSV à partir de JSON dans PowerShell

Sep 23 2020

c'est mon csv:

"name,data
Play,http://{gho}.domain.com/
BDomain,domain.com
Charts,2
Compress,0
CompressJ,0" | ConvertFrom-Csv | ConvertTo-Json

Donne moi:

[
{
    "name":  "Play",
    "data":  "http://{gho}.domain.com/"
},
{
    "name":  "BDomain",
    "data":  "domain.com"
},
{
    "name":  "Charts",
    "data":  "2"
},
{
    "name":  "Compress",
    "data":  "0"
},
{
    "name":  "CompressJ",
    "data":  "0"
}
]

Je voudrais maintenant récupérer ce csv de mon json, mais les chaînes de | ConvertFrom-Json | ConvertTo-CSV ne fonctionne pas, et je suis curieux de savoir pourquoi?

Réponses

1 mklement0 Sep 25 2020 at 05:11

Pour compléter la réponse utile de Steven avec un résumé succinct et une perspective multi-édition:

  • Dans PowerShell [Core] v7 + , aucun effort supplémentaire n'est nécessaire: l'ajout | ConvertFrom-Json | ConvertTo-Csvà votre code fonctionne tel quel .

  • Dans Windows PowerShell et PowerShell [Core] v6.x , vous devez forcer l'énumération de ConvertFrom-Jsonla sortie de s pour ConvertTo-Csvfonctionner correctement, car, par rapport au comportement habituel de PowerShell, ConvertFrom-Jsongénère un tableau JSON dans son ensemble, en tant qu'objet unique vers le pipeline .

    • C'est le fait que ce comportement est inhabituel qui a incité le changement v7 + - voir cette réponse pour des informations générales.

    • Le moyen le plus simple de forcer l'énumération - c'est-à-dire d'envoyer un par un les éléments d' un tableau / collection de sortie comme un tout au pipeline est d'utiliser (...)l' opérateur de regroupement .

# Works in all PowerShell versions, but in v7+ the (...) is no longer necessary.
(
"name,data
Play,http://{gho}.domain.com/
BDomain,domain.com
Charts,2
Compress,0
CompressJ,0" | ConvertFrom-Csv | ConvertTo-Json |
  ConvertFrom-Json
) | ConvertTo-Csv -NoTypeInformation

Cela donne:

"name","data"
"Play","http://{gho}.domain.com/"
"BDomain","domain.com"
"Charts","2"
"Compress","0"
"CompressJ","0"
2 Steven Sep 22 2020 at 23:59

La sortie de ConvertFrom-Jsonest un tableau unique transmis en tant que tel dans le pipeline. Ceci est une conséquence de la façon dont ConvertFrom-Jsonest écrit sa sortie. Il collecte probablement tout et génère le tableau en une seule Write-Outputcommande (implicite ou non) au lieu de diffuser chaque objet dans le pipeline au fur et à mesure de sa création. C'est probablement une conséquence de la façon dont la cmdlet est écrite et peut avoir été nécessaire.

Votre code actuel génère probablement un csv comme:

"Count","Length","LongLength","Rank","SyncRoot","IsReadOnly","IsFixedSize","IsSynchronized"
"5","5","5","1","System.Object[]","False","True","False"

Ce sont les propriétés du tableau et non les objets qu'il contient. Une façon de le contourner, il suffit de garer les données dans une variable:

$Json = "name,data Play,http://{gho}.domain.com/ BDomain,domain.com Charts,2 Compress,0 CompressJ,0" | ConvertFrom-Csv | ConvertTo-Json # Now you can convert back to csv without issue: $Json = $Json | ConvertFrom-Json $Json | ConvertTo-Csv -NoTypeInformation

Remarque: si vous envoyez $ Json directement comme $Json | ConvertFrom-Json | ConvertTo-Csv...vous pouvez avoir le même problème.

Itérer sur les objets Json semble également fonctionner:

$Json = "name,data Play,http://{gho}.domain.com/ BDomain,domain.com Charts,2 Compress,0 CompressJ,0" | ConvertFrom-Csv | ConvertTo-Json $Json | 
ConvertFrom-Json |
ForEach-Object{ $_ } | 
ConvertTo-Csv -NoTypeInformation

Grâce à @notjustme, vous pouvez raccourcir ceci en utilisant (...)comme:

($json | ConvertFrom-Json) | ConvertTo-Csv

Remarque: corrigé par la réponse de mklement0 .

Toutes ces options placent essentiellement le tableau devant le tuyau pour contourner le comportement interne de ConvertFrom-Json

Encore une fois, je ne sais pas à 100% pourquoi ConvertFrom-Json se comporte de cette façon. Je mettrai à jour avec des informations supplémentaires lorsque je trouverai une explication plus formelle.