Find elements that are in array1 but NOT in array2
I pulled two lists of computers from two different tools: Array1
and Array2
.
Now I need to extract the ones that are in Array1
, but not in Array2
.
I managed to get all that fit by following these steps:
$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 found some solutions on SO with other languages (like Perl) but not for PowerShell.
UPDATE
I still am not getting the correct output in Excel with this formula:
the output looks like this:
means some are here and some are not. The result in powershell looks like this:
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 names (or whatever it was called) from SCCMcomptuers / eWPTcomputers are "Computername"
Any idea what I might be doing wrong? Both computer arrays are generated from SQL and in hashtables (I think it is called):, @{Computername=......}@{Computername....
something like this.
Update 2
foreach ($t in $sccmComputers) {
$Test1 += $t.computername
}
$Test2 = @()
foreach ($t in $ewptComputers) {
$Test2 += $t.computername
}
Removing the Hashtable header and just having arrays filled with strings works in fantasy ... does -Property computername
n't even work ...: S
source to share
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 <=
which means that the value "2" is on both objects "1" and "3" only on the "left side" (that is, on the control object), and "4" is only on the difference object
source to share
Use compare-object
like this
Compare-Object -ReferenceObject $sccm -DifferenceObject $wpt -passthru
This should only give you objects in $ sccm, not in $ wpt.
CORRECTION:
The above code will work for the case where the DifferenceObject is guaranteed to be a subset of the ReferenceObject. However, it will FAIL if there are additional objects in the DifferenceObject that are also not present in the ReferenceObject. The above code returns any objects that are present in the EOTER ReferenceObject OR DifferenceObject, but NOT in both.
To correctly return ONLY objects in a ReferenceObject that are also not present in a DifferenceObject, the following code is required:
Compare-Object -ReferenceObject $sccm -DifferenceObject $wpt |
Where-Object { $_.SideIndicator -eq '<=' } |
ForEach-Object { Write-Output $_.InputObject }
The clause where-object
ensures that only objects that are present in the ReferenceObject are piped.
The sentence foreach-object
returns the result back to a plain array (ref: Convert Custom Object Arrays to String Arrays in Powershell - thanks Keith)
source to share
Compare-Object method is really the best. What hasn't been covered yet is the clean output to your Excel file.
Compare-Object $sccm $ewpt | ?{ $_.SideIndicator -eq '<=' | Export-Csv sccm-only.csv -NoTypeInformation
will create two columns. One with "InputObject" and the names of your computer, and another column with "SideIndicator" and a bunch of strings with "<=".
An 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 one column labeled "InputObject" and the names of your computer.
If you want to change the column label, use a method from another thread, Windows Powershell Rename the column header CSV file :
Compare-Object $sccm $ewpt | ?{ $_.SideIndicator -eq '<=' | Select-Object @{ expression={$_.InputObject}; label='ComputerName' } | Export-Csv sccm-only.csv -NoTypeInformation
Also, just change the SideIndicator comparison to get these computers on 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
source to share