Powershell und JSON
Die lange Vorherrschaft von XML-Dateien (Siehe XML und XSLT) wird mehr und mehr durch JSON abgelöst. Am Anfang hatte ich noch meine Probleme mit den geschweiften und eckigen Klammern und einer passenden Formatierung. Aber mittlerweile ziehe ich JSON immer XML vor, wenn es irgendwie geht.
JSON mit PowerShell
PowerShell selbst kennt erst mal kein "JSON-Objekt". Bei XML gibt es ja "[xml]" als Variablentyp aber es gibt kein [json]-Prefix. Die in einem JSON-Objekt hinterlegten Felder und Werte werden aber zu einem PSCustomObject, wenn wie diese einlesen und konvertieren.
- ConvertFrom-JSON
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-json
Konvertiert einen String in ein PSCustomObject - ConvertTo-JSON
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json
Konvertiert eine Eingabe in einen JSON-String
Die beiden Seiten enthalten sehr viele Beispiele, die unterschiedliche Objekte entsprechend wandeln und da möchte ich nicht weiter drauf eingehen. Sie werden nur bei den ein oder anderen Skripten von mir sicher vermehrt die JSON-Nutzung sehen. Zumal JSON auch bei der Graph API und vielen anderen Stellen genutzt wird.
Typumwandung
Auf ein besonderes Problem mit JSON bin ich aber bei der Umsetzung meine Agenten Wallbox3Agent gestoßen. Auch hier hole ich mir Daten per Invoke-RESTMethod (REST - Representational State Transfer) und bekomme eine JSON-Struktur zurück. (Siehe auch Tesla Wallbox Gen 3) Dabei habe ich z.B. den Wert "vehicle_connected" ausgelesen, der den Wert "true" oder "false" hat.
Ich bin dann erst einmal davon ausgegangen, dass das PowerShell-Objekt nach der Konvertierung ein "String" mit dem Wert "true" oder "false" ist und ich entsprechend vergleiche. das hat aber nicht funktioniert, wie folgende kleine Testserien gezeigt hat.
Wert | Code | Ergebnis |
---|---|---|
true |
('{"test":true}' |ConvertFrom-Json).test.gettype().name boolean |
Das Ergebnis ist ein Boolean und der Wert ist "$true" |
"True" |
('{"test":"True"}' |ConvertFrom-Json).test.gettype().name String |
Durch die doppelten Anführungsstriche konvertiert PowerShell den Wert in einen "String" |
'True' |
('{"test":'True'}' |ConvertFrom-Json).test.gettype().name String |
Durch die einfachen Anführungsstriche konvertiert PowerShell den Wert in einen "String" |
True |
('{"test":True}' |ConvertFrom-Json).test.gettype().name ConvertFrom-Json: Conversion from JSON failed with error: Unexpected character encountered while parsing value: T. Path 'test' |
Interessanterweise ist JSON hier Case-sensibel, denn ein True wird nicht erkannt. |
Das gleiche Bild ergibt sich mit false, "false", 'false' und False.
Damit war natürlich mein Interesse geweckt und ich habe mir eine JSON-Struktur gebaut, die String, Integer, Float, Boolean und Array erhält.
$jsonstring = '{ "boolean": false, "unsignedinteger": 3300, "signedinteger": -3300, "float": 219.5, "String": "OK", "Array": [ "a1", "a2" ], "recursion": { "r1": 2222, "r2": "r2value" } }'
Mit der ConvertFrom-Json erhalte ich dann:
$jsonobject = $jsonstring | ConvertFrom-Json $jsonobject boolean : False unsignedinteger : 3300 signedinteger : -3300 float : 219,5 String : OK Array : {a1, a2} recursion : @{r1=2222; r2=r2value}
Es ist gut zu erkennen, dass das Array zu einem PowerShell-Array konvertiert wurde und auch die Rekursion quasi zu einem Unterobjekt wurde. Wer genau hinschaut sieht aber schon, dass False anders geschrieben sind und auch das Dezimalzeichen bei "float" verändert wurde. Was es genau ist, liefert ein "Get-Member":
$jsonobject | gm -MemberType noteproperty TypeName: System.Management.Automation.PSCustomObject Name MemberType Definition ---- ---------- ---------- Array NoteProperty Object[] Array=System.Object[] boolean NoteProperty bool boolean=False float NoteProperty double float=219,5 recursion NoteProperty System.Management.Automation.PSCustomObject recursion=@{r1=2222; r2=r2value} signedinteger NoteProperty long signedinteger=-3300 String NoteProperty string String=OK unsignedinteger NoteProperty long unsignedinteger=3300 $jsonobject.recursion | gm -MemberType noteproperty TypeName: System.Management.Automation.PSCustomObject Name MemberType Definition ---- ---------- ---------- r1 NoteProperty long r1=2222 r2 NoteProperty string r2=r2value
Damit erklärt sich auch, dass ich bei einen "String-Vergleich" die "falsche" Antwort bekomme:
PS C:\> $jsonobject.boolean -eq "false" False PS C:\> $jsonobject.contactor_closed -eq $false True
Weitere Links
- REST - Representational State Transfer
- XML und XSLT
- Tesla Wallbox Gen 3
- Wallbox3Agent
- Exchange REST API für Mail, Kontakt, Termine
- ConvertFrom-JSON
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-json
Konvertiert einen String in ein PSCustomObject - ConvertTo-JSON
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json
Konvertiert eine Eingabe in einen JSON-String - JSON in PowerShell erzeugen und
bearbeiten
https://www.windowspro.de/script/json-powershell-erzeugen-bearbeiten