Converti in csv da json in PowerShell

Sep 23 2020

questo è il mio csv:

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

Mi da:

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

Ora vorrei riavere quel csv dal mio json, tuttavia le catene di | ConvertFrom-Json | ConvertTo-CSV non funziona e sono curioso perché no?

Risposte

1 mklement0 Sep 25 2020 at 05:11

Per completare l'utile risposta di Steven con un breve riassunto e una prospettiva di edizione incrociata:

  • In PowerShell [Core] v7 + , non è necessario alcuno sforzo aggiuntivo: l'aggiunta | ConvertFrom-Json | ConvertTo-Csval codice funziona così com'è.

  • In Windows PowerShell e PowerShell [Core] v6.x , è necessario forza l'enumerazione di ConvertFrom-Jsonuscita 's in modo che ConvertTo-Csvper funzionare correttamente, perché, contro il comportamento abituale di PowerShell, ConvertFrom-Jsonemette una matrice JSON nel suo insieme, come un unico oggetto al gasdotto .

    • È il fatto che questo comportamento è insolito che ha spinto la v7 + a cambiare - vedere questa risposta per informazioni di base.

    • Il modo più semplice per forzare l'enumerazione, ovvero inviare un output-come-un-intero array / insieme degli elementi uno per uno alla pipeline è usare (...)l' operatore di raggruppamento .

# 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

Questo produce:

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

L'output di ConvertFrom-Jsonè un singolo array passato nella pipeline come tale. Questa è una conseguenza di come ConvertFrom-Jsonsta scrivendo il suo output. Probabilmente sta raccogliendo tutto e trasmettendo l'array in un Write-Outputcomando (implicito o meno) invece di trasmettere ogni oggetto lungo la pipeline mentre vengono creati. Probabilmente è una conseguenza di come è stato scritto il cmdlet e potrebbe essere stato necessario.

Il tuo codice corrente probabilmente sta generando un csv come:

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

Queste sono le proprietà della matrice non gli oggetti in essa contenuti. Un modo per aggirare il problema è sufficiente parcheggiare i dati in una variabile:

$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

Nota: se invii $ Json direttamente come $Json | ConvertFrom-Json | ConvertTo-Csv...potresti avere lo stesso problema.

Anche l'iterazione sugli oggetti Json sembra funzionare:

$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

Grazie a @notjustme, puoi accorciarlo usando (...)come:

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

Nota: corretto in base alla risposta di mklement0 .

Tutte queste opzioni stanno essenzialmente posizionando l'array davanti al tubo per aggirare il comportamento interno di ConvertFrom-Json

Anche in questo caso non sono sicuro al 100% perché ConvertFrom-Json si comporta in questo modo. Aggiornerò con ulteriori informazioni quando troverò una spiegazione più formale.