0

I am trying to use $a variable in this script for working with intermediate steps so that I don't have to use $array[$array.Count-1] repeatedly. Similarly for $prop as well . However, values are being overwritten by last value in loop.

$guests = Import-Csv -Path C:\Users\shant_000\Desktop\UploadGuest_test.csv
$output = gc '.\Sample Json.json' | ConvertFrom-Json
$array = New-Object System.Collections.ArrayList;

foreach ($g in $guests) {
    $array.Add($output);
    $a = $array[$array.Count-1];

    $a.Username = $g.'EmailAddress';
    $a.DisplayName = $g.'FirstName' + ' ' + $g.'LastName';
    $a.Password = $g.'LastName' + '123';
    $a.Email = $g.'EmailAddress';

    foreach ($i in $a.ProfileProperties.Count) {
        $j = $i - 1;

        $prop = $a.ProfileProperties[$j];

        if ($prop.PropertyName -eq "FirstName") {
            $prop.PropertyValue = $g.'FirstName';
        } elseif ($prop.PropertyName -eq "LastName") {
            $prop.PropertyValue = $g.'LastName';
        }

        $a.ProfileProperties[$j] = $prop;
    }

    $array[$array.Count-1] = $a;
}

$array;
1
  • 1
    $output = gc '.\Sample Json.json' | ConvertFrom-Json -> $outputJson = gc '.\Sample Json.json', $array.Add($output) -> [void]$array.Add(($outputJson | ConvertFrom-Json)) Commented Jul 31, 2016 at 3:47

2 Answers 2

0

All array elements are referencing one actual variable: $output.

Create an entirely new object each time by repeating JSON-parsing:

$jsontext = gc '.\Sample Json.json'
..........
foreach ($g in $guests) {
    $a = $jsontext | ConvertFrom-Json

    # process $a
    # ............

    $array.Add($a) >$null
}

In case the JSON file is very big and you change only a few parts of it you can use a faster cloning technique on the changed parts (and their entire parent chain) via .PSObject.Copy():

foreach ($g in $guests) {
    $a = $output.PSObject.Copy()
    # ............

    $a.ProfileProperties = $a.ProfileProperties.PSObject.Copy()
    # ............
    foreach ($i in $a.ProfileProperties.Count) {
        # ............
        $prop = $a.ProfileProperties[$j].PSObject.Copy();
        # ............
    }

    $array.Add($a) >$null
}
Sign up to request clarification or add additional context in comments.

2 Comments

Are you sure that .PSObject.Copy() will make deep enough clone in OP case?
0

As others have pointed out, appending $object appends a references to the same single object, so you keep changing the values for all elements in the list. Unfortunately the approach @wOxxOm suggested (which I thought would work at first too) doesn't work if your JSON datastructure has nested objects, because Copy() only clones the topmost object while the nested objects remain references to their original.

Demonstration:

PS C:\> $o = '{"foo":{"bar":42},"baz":23}' | ConvertFrom-Json
PS C:\> $o | Format-Custom *

class PSCustomObject
{
  foo =
    class PSCustomObject
    {
      bar = 42
    }
  baz = 23
}

PS C:\> $o1 = $o
PS C:\> $o2 = $o.PSObject.Copy()

If you change the nested property bar on both $o1 and $o2 it has on both objects the value that was last set to any of them:

PS C:\> $o1.foo.bar = 23
PS C:\> $o2.foo.bar = 24
PS C:\> $o1.foo.bar
24
PS C:\> $o2.foo.bar
24

Only if you change a property of the topmost object you'll get a difference between $o1 and $o2:

PS C:\> $o1.baz = 5
PS C:\> $o.baz
5
PS C:\> $o1.baz
5
PS C:\> $o2.baz
23

While you could do a deep copy it's not as simple and straightforward as one would like to think. Usually it takes less effort (and simpler code) to just create the object multiple times as @PetSerAl suggested in the comments to your question.

I'd also recommend to avoid appending to an array (or arraylist) in a loop. You can simply echo your objects inside the loop and collect the entire output as a list/array by assigning the loop to a variable:

$json = Get-Content '.\Sample Json.json' -Raw
$array = foreach ($g in $guests) {
    $a = $json | ConvertFrom-Json   # create new object

    $a.Username = $g.'EmailAddress'
    ...

    $a   # echo object, so it can be collected in $array
}

Use Get-Content -Raw on PowerShell v3 and newer (or Get-Content | Out-String on earlier versions) to avoid issues with multiline JSON data in the JSON file.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.