I'm using custom objects to hold the name and schema from a set of SQL Server objects. I put the objects into an array, then I get another set of objects and put those into another array. What I'd like to do now is find all exact matches between the two arrays.
I'm currently using this:
$filteredSQLObjects = @()
foreach ($SQLObject1 in $SQLObjects1)
{
    foreach ($SQLObject2 in $SQLObjects2)
    {
        if ($SQLObject1.Name   -eq $SQLObject2.Name -and
            $SQLObject1.Schema -eq $SQLObject2.Schema)
        {
            $filteredSQLObjects += $SQLObject1
        }
    }
}
Is there a better/faster/cleaner way to do this? Originally when I was just working with arrays of strings I could just loop through one of the arrays and use -contains on the second, but with objects that doesn't seem possible.
Thanks!
I think its better if you define the equality condition in an IsEqualTo method on your custom object. So something like this:
$myObject = New-Object PSObject
$myObject | Add-Member -MemberType NoteProperty -Name Name -Value $name
$myObject | Add-Member -MemberType NoteProperty -Name Schema -Value $schema
$myObject | Add-Member -MemberType ScriptMethod -Name IsEqualTo -Value {
    param (
        [PSObject]$Object
    )
    return (($this.Name -eq $Object.Name) -and ($this.Schema -eq $Object.Schema))
}
Then you can either do a one-liner like Keith showed us, or just do your double foreach iteration. Whichever you think is more readable:
$filteredSQLObjects = $SQLObjects1 | Where-Object { $SQLObject1 = $_; $SQLObjects2 | Where-Object { $_.IsEqualTo($SQLOBject1) } }
foreach ($SQLObject1 in $SQLObjects1)
{
    foreach ($SQLObject2 in $SQLObjects2)
    {
        if ($SQLObject1.IsEqualTo($SQLObject2))
        {
            $filteredSQLObjects += $SQLObject1
        }
    }
}
EDIT
OK, for a start, you can't add an Equals member because it already exists on System.Object (doh!). So I guess IsEqualTo will have to do instead.
What you can do is define your own function called Intersect-Object (the equivalent of .NET's Enumerable.Intersect method) which accepts pipeline input and returns the set intersection of two sequences (the ones that appear in both sequences). Be aware that I haven't fully-implemented this function (assumes each item in the collection specified by Sequence has an IsEqualTo method, doesn't check for duplicates before adding to $filteredSequence etc), but I hope you get the idea.
function Intersect-Object
{
    param (
        [Parameter(ValueFromPipeline = $true)]
        [PSObject]$Object,
        [Parameter(Mandatory = $true)]
        [PSObject[]]$Sequence
    )
    begin
    {
        $filteredSequence = @()
    }
    process
    {
        $Sequence | Where-Object { $_.IsEqualTo($Object) } | ForEach-Object { $filteredSequence += $_ }
    }
    end
    {
        return $filteredSequence
    }
}
Then your double foreach loop turns into this:
$filteredSQLObjects = $SQLObjects1 | Intersect-Object -Sequence $SQLObjects2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With