0

Hello all and good morning.

I'm just looking to see if I can format the output of Compare-Object into a pscustomobject. I have taken a look at the following questions that are similar:

...but, I just don't seem to grasp the concept of it. I hate to ask questions that are already have been answered that correlate to this but, im just a bit confused. The 3rd link was the only one I was beginning to understand but, still got lost in the sauce.

Just looking to separate the output based off the SideIndicator return property.

$Reference = Get-Content "C:\Users\Abe\Desktop\onj1.txt"
$Difference = Get-Content "C:\Users\Abe\Desktop\onj2.txt"


Compare-Object -ReferenceObject $Reference -DifferenceObject $Difference -IncludeEqual | Tee-Object -Variable CompareObject | Out-Null
$compareObject | Foreach { 
$ONJ1 = $_.SideIndicator -eq "<=" | Select $_.InputObject
$ONJ2 = $_.SideIndicator -eq "=>" | Select $_.InputObject
$Both = $_.SideIndicator -eq "==" | Select $_.inputobject

    [pscustomobject]@{
        ONJ1 = $ONJ1
        ONJ2 = $ONJ2
        Both = $Both
                }
        } 

Unfortunately, all 3 columns return the same output and im assuming its because im selecting the InputObject property but, it grabs them all.

EDIT: As explained by Zett42

$Reference = Get-Content "C:\Users\Abe\Desktop\onj1.txt"
$Difference = Get-Content "C:\Users\Abe\Desktop\onj2.txt"


Compare-Object -ReferenceObject $Reference -DifferenceObject $Difference -IncludeEqual | Tee-Object -Variable CompareObject | Out-Null

$null = [array]$ONJ1 = $compareObject | Where-Object {$_.SideIndicator -eq "<="} | Select-Object -ExpandProperty InputObject
$null = [array]$ONJ2 = $compareObject | Where-Object {$_.SideIndicator -eq "=>"} | Select-Object -ExpandProperty InputObject
$null = [array]$Both = $compareObject | Where-Object {$_.SideIndicator -eq "=="} | Select-Object -ExpandProperty InputObject


For($i=0; $i -lt ($ONJ1.Count + $ONJ2.Count + $Both.Count); $i++){
    [pscustomobject]@{
        ONJ1 = $ONJ1[$i]
        ONJ2 = $ONJ2[$i]
        Both = $Both[$i]
                }
        } 
Abraham Zinala
  • 4,267
  • 3
  • 9
  • 24
  • 1
    Great that you reference the questions you've already explored, but you seem to have forgotten to describe what you're hoping to accomplish :-) What is it you're hoping to see on screen, and what will you be using the resulting object for? – Mathias R. Jessen Feb 12 '21 at 16:25
  • Sorry! Thought I included it. Its not really being used for something specific, just to try and add the names in the text file to the corresponding column assigned to it by the var. – Abraham Zinala Feb 12 '21 at 16:48
  • So you want the output file to contain a formatted table with three variable-length "columns"? – Mathias R. Jessen Feb 12 '21 at 16:50
  • Well, the contents within the files themselves separated by the difference in sideindicators, but yes. Into its own separate columns based off that. If that makes sense? – Abraham Zinala Feb 12 '21 at 17:05
  • You can remove the `$null =`. Variable assignment doesn't produce output by default (you would have to enclose whole statement into parenthesis to make it produce output, e. g. `($a = 42)`). – zett42 Feb 12 '21 at 17:42

2 Answers2

4

You are grabbing the formatted output strings, not the actual data from Compare-Object. The formatted output will be hard to process, because it is just unstructured strings. Store direct output of Compare-Object into a variable, without piping to other cmdlets. Then you do further processing based on that data.

$reference = 'foo', 'bar', 'baz', 'bim'
$difference = 'bim', 'fop', 'bar'

$compareObject = Compare-Object -ReferenceObject $Reference -DifferenceObject $Difference -IncludeEqual 

Then separate the result based on the SideIndicator:

[array] $left  = $compareObject | Where-Object SideIndicator -eq '<=' | 
                                  Select-Object -ExpandProperty InputObject
[array] $right = $compareObject | Where-Object SideIndicator -eq '=>' | 
                                  Select-Object -ExpandProperty InputObject
[array] $both  = $compareObject | Where-Object SideIndicator -eq '==' |
                                  Select-Object -ExpandProperty InputObject

The variable $left is an array that contains only items that are in $Reference, $right contains only items that are in $Difference and $both obviously contains items that are in both $Reference and $Difference.

NOTE: I've explicitly set the type of the variables to [array] so we can treat single element output the same as multiple elements. Applying the index operator to a single string would select a single character, whereas applying the index operator to an array of strings would output a single string. By explicitly setting the variable type to [array] we handle both cases without extra code.

Now we can do further processing based on the separated results, e. g. stuffing them into a single array of [PSCustomObject]:

# Determine the total number of rows we need. -1 to make it a valid array index.
$maxIndex = ( $left.Count, $right.Count, $both.Count | Measure-Object -Maximum ).Maximum - 1

foreach( $i in 0..$maxIndex ) {
    [pscustomobject]@{
        ONJ1 = if( $i -lt $left.Count )  { $left[ $i ] }  else { $null }
        ONJ2 = if( $i -lt $right.Count ) { $right[ $i ] } else { $null }
        Both = if( $i -lt $both.Count )  { $both[ $i ] }  else { $null }
    }
}

The if/else on the right-hand side of an assignment is called conditional assignment (aka ternary operator). As each of the arrays $left, $right and $both may have different size (less than $maxIndex), we need to make sure to not "overshoot" and use an invalid index.

Actually this is only necessary when using strict mode >= v3.0 (e. g. Set-StrictMode -Version 3.0), in which case you would get a fatal "index out of bounds" error when specifying an invalid array index. Without strict mode, you could write ONJ1 = $left[ $i ] without checking the index. Personally I prefer to know that my indices are always correct and not rely on the programming language to silently "fix" my errors.

Output:

ONJ1 ONJ2 Both
---- ---- ----
foo  fop  bar
baz       bim
zett42
  • 25,437
  • 3
  • 35
  • 72
  • This is what I was looking for. It all makes sense to me now, see updated question for the code I did to complete it. Thank you! – Abraham Zinala Feb 12 '21 at 17:13
  • its so odd as i used the same method to index but, it spread one of the difference names into a new row until the name finished. Guess its because it wasn't listed as an array to begin with? Though it was read as such when specified through the `Get-Content` and stored in the variable `ONJ2`. – Abraham Zinala Feb 12 '21 at 17:16
  • 1
    @AbrahamZinala If you don't explicitly set the type of the variable to `[array]` (or use the array literal operator `@()`) it may be a single object instead. In case of a string you would then index into the individual characters. I've modified the code to use `[array]` instead of `@()`. It's a matter of preference, personally I think `[array]` is clearer. I don't like parenthesis. ;-) – zett42 Feb 12 '21 at 17:23
  • you and I both! – Abraham Zinala Feb 12 '21 at 17:34
1

Unsure what you expect as formatted output, but perhaps something ;ike this?

onj1.txt

Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor.

onj2.txt

Lorem ipsum dolor sit amet, 
sed do eiusmod tempor.
$Reference = Get-Content "C:\Users\Abe\Desktop\onj1.txt"
$Difference = Get-Content "C:\Users\Abe\Desktop\onj2.txt"

$compare = Compare-Object -ReferenceObject $Reference -DifferenceObject $Difference -IncludeEqual

[PsCustomObject]@{
    ONJ1 = ($compare | Where-Object {$_.SideIndicator -eq "<="}).InputObject -join [environment]::NewLine
    ONJ2 = ($compare | Where-Object {$_.SideIndicator -eq "=>"}).InputObject -join [environment]::NewLine
    Both = ($compare | Where-Object {$_.SideIndicator -eq "=="}).InputObject -join [environment]::NewLine
} | Format-Table -Wrap

Output:

ONJ1                                                      ONJ2                         Both                  
----                                                      ----                         ----                  
Lorem ipsum dolor sit amet,                               Lorem ipsum dolor sit amet,  sed do eiusmod tempor.
consectetur adipiscing elit,                                                                                 
Theo
  • 57,719
  • 8
  • 24
  • 41