Justin Beagley
Justin Beagley

Reputation: 299

Enumerate through array fails

I'm enumerating through all of the datastores in our VMware environment to get names and used space.

When I run the foreach loop, it's both enumerating through the array, and not enumerating through the array.

Here's my script:

$list = @()
$row = '' | select Name, UsedSpace
$datastores = Get-Datastore

foreach ($store in $datastores) {
    $row.name = $store.name;
    $row.usedspace = [math]::Round(($store.extensiondata.summary.capacity - $store.extensiondata.summary.freespace)/1gb)
    Write-Host $row; #To Verify that each row is different, and that enumeration is working#
    $list += $row;
}

Console Output:

@{name=datastore1; usedspace=929}
@{name=datastore2; usedspace=300}
@{name=datastore3; usedspace=400}

$list variable output:

Name        Usedspace
Datastore3  400
Datastore3  400
Datastore3  400

So it's enumerating through. getting all the correct data. but for some reason the line $list += $row is waiting until the last object in the array, grabs only that data, but knows that there's 3 objects in the array, and populates each index with that objects data.

The only thing I've done to troubleshoot is bounced my PowerShell console.

Upvotes: 2

Views: 55

Answers (2)

user6811411
user6811411

Reputation:

Alternatively you could create a PSCustomObject

$list = foreach ($store in Get-Datastore) {
    [PSCustomObject]@{
        Name      = $store.name
        UsedSpace = [math]::Round(($store.extensiondata.summary.capacity - 
                                   $store.extensiondata.summary.freespace)/1gb)
    }
}
$list 

As mentioned in the comments, with:

$row = '' | select Name, UsedSpace; $row.GetType()

you implicitly also create an (empty) PSCustomObject,
but as this needs to be created in every iteration of the foreach and then (inefficiently) appended to $list by rebuilding the array - directly building the PSCustomObject is IMO more clear / straight forward.

Upvotes: 1

briantist
briantist

Reputation: 47792

The reason for this is that $row is a single object. You created it once, and then you keep changing the values of its properties. When you add it to the array, you're adding a reference to it, not a copy. So the values seen will always be those that were most recently set.

Recreate your $row on every iteration of the loop.

Upvotes: 4

Related Questions