Home > front end >  Powershell: adding an element from an array to another array
Powershell: adding an element from an array to another array

Time:10-19

I am trying to add elements to array for filtering. after it goes through the loop the first time I receive "Method invocation failed because [System.Management.Automation.PSObject] does not contain a method named 'op_Addition'."

I have tried several methods to try and figure this out.

$JsonDB = Get-Content 'Q:\Technology\1AA\HardwareCollection.json' | Out-String | ConvertFrom-Json
    foreach($client in $JsonDB)
        {
            if($client.HRSeparation -eq "No")
                {
                    $ClientNotHRSeparated  = $client
                }
            else
                {
                    $ClientHRSeparated  = $client
                }
        }
$JsonDB

Any help would be greatly appreciated, Thanks!!

CodePudding user response:

The behavior of = is entirely dependent on the left-hand side operand. On the first assignment, the value of $ClientNotHRSeparated is $null, so the resulting operation is:

$ClientNotHRSeparated = $null   $someCustomPSObject

Which PowerShell evaluates as just:

$ClientNotHRSeparated = $someObject

On the second assigment, $ClientNotHRSeparated is no longer $null, and PowerShell instead of tries to identify an overload for that works on two operands of type [PSObject], which is where it fails.

If you want = to perform array addition, define the two array variables ahead of time with an assignment of a resizable array (use the @() array subexpression operator):

$ClientNotHRSeparated = @()
$ClientHRSeparated = @()

$JsonDB = Get-Content 'Q:\Technology\1AA\HardwareCollection.json' | Out-String | ConvertFrom-Json
foreach ($client in $JsonDB) {
    if ($client.HRSeparation -eq "No") {
        $ClientNotHRSeparated  = $client
    }
    else {
        $ClientHRSeparated  = $client
    }
}
$JsonDB

Now = is unambiguous both the first time and subsequently - the left-hand side operand is an array in either case.


As an alternative to looping through the whole collection manually, consider using the .Where() extension method in Split mode:

$JsonDB = Get-Content 'Q:\Technology\1AA\HardwareCollection.json' | Out-String | ConvertFrom-Json

$ClientNotHRSeparated, $ClientHRSeparated = @($JsonDB).Where({$_.HRSeparation -eq 'No'}, 'Split')

Much faster and more concise :-)

CodePudding user response:

ConvertFrom-Json parses a JSON string into PSObject(s). Since you did not define $ClientNotHRSeparated and $ClientHRSeparated anywhere, but immediately start adding ($client) objects to it, in the first iteration your variable $ClientNotHRSeparated will become that client object. The next time you do =, you're trying to add an object to another object which does not work.

Define the variables on top of the script, preferably as List object that has a .Add() method.

$ClientNotHRSeparated = [System.Collections.Generic.List[object]]::new()
$ClientHRSeparated = [System.Collections.Generic.List[object]]::new()

Then in your loop use that as

$ClientNotHRSeparated.Add($client)
# same for $ClientHRSeparated

P.S. Using a List is much faster/better that adding to a simple array (@()), because when you add items to an array (which has a fixed length) with =, the entire array needs to be rebuilt in memory, consuming memory and processing time

Although this works, you don't need a loop at all. Just do:

$ClientNotHRSeparated = $JsonDB | Where-Object { $_.HRSeparation -eq "No" }
$ClientHRSeparated = $JsonDB | Where-Object { $_.HRSeparation -ne "No" }

The first line can be rewritten as $JsonDB = Get-Content -Path 'Q:\Technology\1AA\HardwareCollection.json' -Raw | ConvertFrom-Json.
Switch -Raw makes the cmdlet read the content of the file as one single multilined string

  • Related