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