PowerShell Ersetzen innerhalb eines Objektes mit Variablen

pizza4ever

Lt. Commander
Registriert
Apr. 2009
Beiträge
1.665
Hallo zusammen,

wenn ich in folgendem Code mit Variablen Ersetzungen vornehmen will klappt das untere Beispiel nicht.

Wer weiß, wie ich das am elegantesten umsetzen kann?

Danke

Alex

Code:
$tmp = '{
    "months": [
        {
        "orders": 500
        }
    ]

}'

$test = $tmp | ConvertFrom-Json
Write-Host $test.months
#das geht natürlich
$test.months[0].orders = 300
Write-Host $test.months
#das auch:
$var = 'orders'
$test.months[0]."$var" = 200
Write-Host $test.months
#aber das nicht
$var = 'months[0].orders'
$test."$var" = 100
 
Du versuchst auch auf den Key bzw. die Property months[0].orders zuzugreifen und nicht auf die Struktur months, davon das erste Element, davon die Property orders.
Code:
PS > $tmp = '{
>>>     "months": [
>>>         {
>>>         "orders": 500
>>>         }
>>>     ]
>>>
>>> }'

PS > $test = $tmp | ConvertFrom-Json
PS > $var = 'months[0].orders'

## hier fliegts dir um die Ohren

PS > $test."$var" = 100
Exception setting "months[0].orders": "The property 'months[0].orders' cannot be found on this object. Verify that the property exists and can be set."
At line:1 char:1
+ $test."$var" = 100
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting

## Member hinzufügen

PS > $test | Add-Member -Name $var -Type NoteProperty -Value 50
PS > $test | ConvertTo-Json
{
  "months": [
    {
      "orders": 500
    }
  ],
  "months[0].orders": 50
}

## klappt

PS > $test."$var" = 999
PS > $test | ConvertTo-Json
{
  "months": [
    {
      "orders": 500
    }
  ],
  "months[0].orders": 999
}
Wenn du so Zugriff auf die Properties willst, musst du dir eine eigene Funktion schreiben, die das eben nach ., [] usw. aufdröselt. Quasi einen eigenen Parser. Als großes Vorbild sei da bspw. jq genannt, welches den übergebenen String eben parst und dann eigene Transformationen durchführt - eben auf der Struktur, nicht dem einzelnen Key.
 
Am Elegantesten beschreibst Du das ursprüngliche Problem, denn auf diese Art und Weise mißbrauchst Du eine jede Programmiersprache.

Ansonsten müßtest Du mal schauen, wie man unter PS am besten einen String evaluiert. Dann mußt Du den Quellcode bzw das Codefragment in einem String abbilden und diesen als Quellcode auswerten.

Dir muß aber klar sein, daß das kreuzgefährlich ist, unzuverlässig und fehlerträchtig; wenn jemand mit ausreichend passendem Input kommt, fliegt Dir das Ganze um die Ohren und Du hast einen klassischen Fall von Code Injection.

NICHT machen, wenn irgend möglich.
 
Mein Problem ist, dass ich zur Laufzeit mir einen JSON Aufruf dynamisch aufbauen lassen möchte.

Ich habe quasi ein "Standardjson" und will mir mit einer zweiten Informationsquelle (Json, txt-Datei, ps1 skript) den Webservice aufruf zusammenbauen.

Im Standardjson will ich:

  • Die Grundsätzliche Struktur festlegen.
  • viele Default Werte festlegen

mit der zweiten Informationsquelle will ich:
  • diese dann teilweise wieder überschreiben
  • ggf. in Arrays weitere Elemente hinzufügen (und hierbei ggf. wieder Standardwerte aus dem "Standardjson" übernehmen.

Am Ende will ich ggf. zur Laufzeit noch ein paar Ersetzungen vornehmen (wie z.B. Tagesdatum = aktuelles Datum) setzen.

Meine erste Idee war das Standardjson zu speichern und in einer zweiten TXT-Datei dann sowas wie:

months[0].orders = 300

... wer aber aus o.g. Gründen nicht soooo besonders gut funktioniert ....


Habt ihr dafür eine bessere Idee?
 
Du kannst jederzeit eine JSON-Datenstruktur aus einem PS-Objekt ableiten mit ConvertTo-JSon.

Mir persönlich haben von anfang an Import-Json und Export-Json gefehlt - und ich sehe, PS7 kann das immer noch nicht -- evtl kann es sinnvoll sein, erstmal zwei entsprechende Funktionen zu implementieren als "Aufsatz" zu convertFrom/To-Json.

Dann kannst Du einfach JSON-Objekte aus .json-Dateien holen (als Templates).

Ich mach das bei mir immer so, ich bau mir ein ordentliches OO-Framework, sprich ein paar passende Klassen, plus ein paar Interfaceklassen, die dann auf JSON abbilden können, und dazu dann die nötigen Methoden und Eigenschaften (dran denken, daß JSON nichts mit Methoden anfangen kann, daher die Interfaceklassen nach Möglichkeit davon freihalten). Wenn Interaktion erforderlich wird, zur Laufzeit ConvertTo-JSon drüberschicken und fertig ist der JSON-String, ohne daß man groß basteln muß.

Am Ende des Tages ist JSON nur eine Abbildung eines Objekts. Verzichte auf dessen Einsatz solange wie es geht, wenn Du dann ein konfiguriertes Objekt hast, dann kannst Du das ganz einfach über die *-Json cmdlets als solches exportieren. Und mit passenden Interfaceklassen kann man ganz einfach eine statische JsonParser-Methode bauen, die die nicht-typisierten Informationen aus dem JSON-Objekt holt und in die Objektstruktur einliest.
 
Ok danke für die Info.

hab es nun erstmal mit JSONS als Vorlage + ps1 Code erledigt....

Eine Frage habe ich noch:

wieso ist der Output von:

Code:
function f {
  [CmdletBinding()]Param()
  Write-Verbose 'f: Start'
  $t = New-Object 'System.Collections.ArrayList'
  $t.add('test1')
  $t.add('test2')
  $t.add('test3')
  Write-Host "während dem Funktionsaufruf"
Write-Host $t
  return , $t
}
[System.Collections.ArrayList]$things = f -verbose
Write-Host "Nach dem Funktionsaufruf"
Write-Host $things

während dem Funktionsaufruf
test1 test2 test3
Nach dem Funktionsaufruf
0 1 2 test1 test2 test3

Wieso unterscheidet sich $things von $t?
 
Arraylist.Add gibt einen int zurück, der schießt quer.

Schreib vor jedes $t.Add ein $null = davor. Das verwirft den Rückgabewert der Methode.
 
Zurück
Oben