0

I want to avoid inserting duplicates into an array in powershell. Trying to use -notcontains doesn't seem to work with a PSCUstomObject array.

Here's a code sample

$x = [PSCustomObject]@{
    foo = 111
    bar = 222
}

$y = [PSCustomObject]@{
    foo = 111
    bar = 222
}

$collection = @()

$collection += $x

if ($collection -notcontains $y){
    $collection += $y
}


$collection.Count #Expecting to only get 1, getting 2
PBG
  • 8,944
  • 7
  • 34
  • 48
  • The answer is effectively the same as i [Comparing two arrays & get the values which are not common](https://stackoverflow.com/a/35872835/1701026) except that you don't care about the results only whether there is any result: (`@($collection).count`, you will need to **force an array** otherwise you counting characters in case of a singleton). – iRon Dec 27 '19 at 08:44

1 Answers1

1

I would use Compare-Object for this.

$x = [PSCustomObject]@{
    foo = 111
    bar = 222
}

$y = [PSCustomObject]@{
    foo = 111
    bar = 222
}
$collection = [System.Collections.Arraylist]@()

[void]$collection.Add($x)

if (Compare-Object -Ref $collection -Dif $y -Property foo,bar | Where SideIndicator -eq '=>') {
    [void]$collection.Add($y)
}

Explanation:

Comparing a custom object to another using comparison operators is not trivial. This solution compares the particular properties you care about (foo and bar in this case). This can be done simply with Compare-Object, which will output differences in either object by default. The SideIndicator value of => indicates the difference lies in the object passed into the -Difference parameter.

The [System.Collections.Arraylist] type is used over an array to avoid the inefficient += typically seen when growing an array. Since the .Add() method produces an output of the index being modified, the [void] cast is used to suppress that output.


You could be dynamic with the solution regarding the properties. You may not want to hard code the property names into the Compare-Object command. You can do something like the following instead.

$x = [PSCustomObject]@{
    foo = 111
    bar = 222
}

$y = [PSCustomObject]@{
    foo = 111
    bar = 222
}
$collection = [System.Collections.Arraylist]@()

[void]$collection.Add($x)
$properties = $collection[0] | Get-Member -MemberType NoteProperty |
                  Select-Object -Expand Name

if (Compare-Object -Ref $collection -Dif $y -Property $properties | Where SideIndicator -eq '=>') {
    [void]$collection.Add($y)
}
AdminOfThings
  • 23,946
  • 4
  • 17
  • 27
  • That's what I was looking for. And thank you for offering a solution on how not to hardcode property names. – PBG Dec 27 '19 at 02:35