Find items which are in array1 but NOT in array2

19,022

Solution 1

use compare-object cmdlet

Compare-Object -ReferenceObject $sccm -DifferenceObject $wpt | ?{$_.sideIndicator -eq "<="} |select inputobject

example :

$sccm=@(1,2,3)   
$wpt=@(2,4)

Compare-Object -ReferenceObject $sccm -DifferenceObject $wpt -IncludeEqual   

will output :

InputObject SideIndicator


      2 ==            
      4 =>            
      1 <=            
      3 <=

that means value "2" is on both objects, "1" and "3" only on "the left side" (ie the reference object), while "4" is only on the difference object

Solution 2

Use compare-object as follows

Compare-Object -ReferenceObject $sccm -DifferenceObject $wpt -passthru

This should give you just the objects in $sccm but not in $wpt.

CORRECTION:

The above code WILL work for the case where DifferenceObject is guaranteed to be a subset of ReferenceObject. It will FAIL, though, if there are additional objects in DifferenceObject that are not also present in ReferenceObject. The above code returns any objects which are present in EITHER ReferenceObject OR DifferenceObject but NOT in both.

To properly return ONLY objects in ReferenceObject that are not also present in DifferenceObject, the following code is required:

Compare-Object -ReferenceObject $sccm  -DifferenceObject $wpt | 
    Where-Object { $_.SideIndicator -eq '<=' } | 
    ForEach-Object  { Write-Output $_.InputObject }

The where-object clause ensures only objects that are present in ReferenceObject are passed down the pipeline.

The foreach-object clause forces the output back to a simple array (ref: Converting Custom Object arrays to String arrays in Powershell - thanks Keith)

Solution 3

You can use -contains and -notcontains

$A1 ="asd","zxc","qwe",'a'
$A2 = "asd","zxc","bqwe",'b'
$A1,$A2 | 
%{
    $_| 
        %{
        If ($A1 -contains $_ -and $A2 -notcontains $_) {$_}
        }
}

Solution 4

The Compare-Object method is indeed the best. What hasn't been addressed yet is clean output to your Excel file.

Compare-Object $sccm $ewpt | ?{ $_.SideIndicator -eq '<=' | Export-Csv sccm-only.csv -NoTypeInformation

will produce two columns. One with "InputObject" and your computer names, and another column with "SideIndicator" and a bunch of rows with "<=".

The easy fix is to select only the column you want:

Compare-Object $sccm $ewpt | ?{ $_.SideIndicator -eq '<=' | Select-Object InputObject | Export-Csv sccm-only.csv -NoTypeInformation

This will give you a single column labeled "InputObject" and your computer names.

If you want to change the column label, use the method from another thread, Windows Powershell Rename Column Heading CSV file:

Compare-Object $sccm $ewpt | ?{ $_.SideIndicator -eq '<=' | Select-Object @{ expression={$_.InputObject}; label='ComputerName' } | Export-Csv sccm-only.csv -NoTypeInformation

Also, simply change the SideIndicator comparison to get those computers in both systems, or only in eWPT:

# Only in eWPT
Compare-Object $sccm $ewpt | ?{ $_.SideIndicator -eq '=>' | Select-Object @{ expression={$_.InputObject}; label='ComputerName' } | Export-Csv sccm-only.csv -NoTypeInformation

# In both SCCM and eWPT
Compare-Object $sccm $ewpt | ?{ $_.SideIndicator -eq '==' | Select-Object @{ expression={$_.InputObject}; label='ComputerName' } | Export-Csv sccm-only.csv -NoTypeInformation
Share:
19,022
Michael
Author by

Michael

Updated on June 17, 2022

Comments

  • Michael
    Michael almost 2 years

    I extracted two lists of computers from two different tools, Array1 and Array2.

    Now I need to extract the ones which are in Array1, but not in Array2.

    I managed to get all the matching ones by doing this:

    $matchingComp = @()
    
    foreach ($SCCMcomputer in $SCCMcomputers) {
        foreach ($eWPTcomputer in $eWPTcomputers) {
            if ($SCCMcomputer.Computername -eq $eWPTComputer.Computername) {
                $obj = New-Object PSObject
                $obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $SCCMcomputer.Computername
                $matchingComp +=$obj
            }
        }
    }
    
    $matchingComp | Export-Csv $inEWPT -Delimiter "," -NoTypeInformation
    

    But I still need the ones that are in $SCCMcomputer but NOT in $eWPTcomputers...

    I've found some solutions on SO with other languages (e.g. Perl) but not for PowerShell.

    UPDATE

    I still don't get the correct output, in Excel with this formula:

    enter image description here

    the output looks like:

    enter image description here

    means some are here, some not. The output in powershell is like this

    enter image description here

    means 0KB is emtpy.

    $SCCMcomputers | Export-Csv $sccmexport -Delimiter "," -NoTypeInformation
    $eWPTcomputers | Export-Csv $ewptexport -Delimiter "," -NoTypeInformation
    Compare-Object -ReferenceObject $SCCMcomputers -DifferenceObject $eWPTcomputers | ?{$_.sideIndicator -eq "=>"} |select inputobject | Export-Csv $inEWPT -NoTypeInformation
    Compare-Object -ReferenceObject $SCCMcomputers -DifferenceObject $eWPTcomputers | ?{$_.sideIndicator -eq "=="} |select inputobject | Export-Csv $inBoth -NoTypeInformation
    Compare-Object -ReferenceObject $SCCMcomputers -DifferenceObject $eWPTcomputers | ?{$_.sideIndicator -eq "<="} |select inputobject | Export-Csv $inSCCM -NoTypeInformation
    

    And both Column Name (or what it's called) from SCCMcomptuers/eWPTcomputers is "Computername"

    Any idea what I could be doing wrong? Both computer arrays are generated from SQL and in hashtables (I think it's called): @{Computername=......}@{Computername...., something like this.

    Update 2

    foreach ($t in $sccmComputers) {
        $Test1 += $t.computername
    }
    
    $Test2 = @()
    foreach ($t in $ewptComputers) {
        $Test2 += $t.computername
    }
    

    By removing the Header of the Hashtable and just having arrays full of strings works fantasctic..... even -Property computername did not work... :S

  • Michael
    Michael over 9 years
    hey, first of all, thanks for your help.... I tried it and the output is quiet messy... I cannot see the logic behind what it did, some computers are handled correctly (avail. in 1 and 2, so sorted out) but some are in both files and still get exported to this list -- any idea how this comes?
  • Loïc MICHEL
    Loïc MICHEL over 9 years
    +1 for passthru but you lack the side indicator Compare-Object -ReferenceObject $sccm -DifferenceObject $wpt -PassThru | ?{$_.sideIndicator -eq "<="}