Reputation: 1180
I have 2 text files that contains a list of SQL function names. I want to be able to compare a list in $A and $B. I then want a list of the SQL function names which are in $B and not in $A i.e. list $C to be send as an attachment to an email address.
Here is my code:
$A = "c:\ReferenceFunctions.txt"
$B = "c:\GeneratedFunctions.txt"
$C = "c:\FileWithDifferences.txt"
$fromaddress = "noreply@xyz"
$toaddress = "123@hhh"
$bccaddress = "[email protected]"
$login = "yourlogin"
$password = "password" | Convertto-SecureString -AsPlainText -Force
$smtpserver = "gggg.com"
$smtp = new-object Net.Mail.SmtpClient($smtpserver, 800)
$smtp.EnableSsl = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($login,
$password);
$body = "see attached "
$Subject = "checking differences"
$message = new-object System.Net.Mail.MailMessage
$message.From = $fromaddress
$message.To.Add($toaddress)
#$message.CC.Add($CCaddress)
$message.Bcc.Add($bccaddress)
$message.IsBodyHtml = $True
$message.Subject = $Subject
$message.body = $body
$message.Priority = [System.Net.Mail.MailPriority]::High
Compare-object (Get-Content $A) (Get-Content $B) | Out-File $C
#Attach the eported file with differences
$attachment = $C
$attach = new-object Net.Mail.Attachment($attachment)
$message.Attachments.Add($attach)
IF (Compare-Object -ReferenceObject (Get-Content $A) -DifferenceObject (Get-Content $B)){
$smtp.Send($message);
}
Variable $A has information as below:
fn_StatementEndOfMonth
fn_Performance_Sql
fn_DailyReturns
Variable $B has the following info:
fn_Performance_Sql
fn_DailyReturns
fn_SQLPerfomance_Monitor
$C Should then contain
fn_SQLPerfomance_Monitor
The problem with this code is that, it is sending an attachment with all the SQL Function names in both file $A and $B instead of the difference. I can't seem to figure out where am going wrong. Any one who can assist please? Been trying to figure out the whole day but no luck.
Upvotes: 2
Views: 571
Reputation: 439597
You must filter the difference objects that Compare-Object
outputs by their .SideIndicator
property in order to only get the items that are unique to a given side (PSv3+ syntax):
Compare-Object (Get-Content $A) (Get-Content $B) -PassThru |
Where-Object Sideindicator -eq '=>' |
Out-File $C
Where-Object Sideindicator -eq '=>'
outputs only those difference objects representing item that are unique to the right side (i.e., the second argument, the lines of file $B
in this case).
[pscustomobject]
instance that represents a single difference between the input collections. It has two properties:
.SideIndicator
contains an arrow (string) that points toward the side that the input object at hand is unique to: <=
or =>
; if you use the -IncludeEqual
switch, objects present in both collections are represented with ==
.InputObject
represent the input object at hand.-PassThru
results in Compare-Object
outputting the input objects themselves rather than the usual difference objects:
-PassThru
, Out-File
would write the difference objects as a whole, resulting in a table representation; you'd have to access the .InputObject
property in order to get the string only..SideIndicator
property is still present, because PowerShell adds a NoteProperty
member with that name to each object, so the Where-Object
filter still works as intended.Upvotes: 1
Reputation: 30173
The following code snippet shows how Compare-Object
cmdlet works, and importance of SideIndicator
property:
$a = @'
fn_StatementEndOfMonth
fn_Performance_Sql
fn_DailyReturns
'@ -split [environment]::NewLine ### ReferenceFunctions
$b = @'
fn_Performance_Sql
fn_DailyReturns
fn_SQLPerfomance_Monitor
'@ -split [environment]::NewLine ### GeneratedFunctions
[environment]::NewLine ### for better output readability
'Compare-Object $a $b'
Compare-Object $a $b
[environment]::NewLine
'Compare-Object $a $b | ? SideIndicator -ne ''<='''
Compare-Object -ReferenceObject $a -DifferenceObject $b|
Where-Object { $_.SideIndicator -ne '<=' }
[environment]::NewLine
'Compare-Object $a $b | ? SideIndicator -ne ''=>'''
Compare-Object -ReferenceObject $a -DifferenceObject $b |
Where-Object { $_.SideIndicator -ne '=>' }
[environment]::NewLine
'Compare-Object $a $b -PassThru'
Compare-Object $a $b -PassThru
[environment]::NewLine
'Compare-Object $a $b -PassThru | ? SideIndicator -ne ''<='''
Compare-Object -ReferenceObject $a -DifferenceObject $b -PassThru |
Where-Object { $_.SideIndicator -ne '<=' }
[environment]::NewLine
'Compare-Object $a $b -PassThru | ? SideIndicator -ne ''=>'''
Compare-Object -ReferenceObject $a -DifferenceObject $b -PassThru |
Where-Object { $_.SideIndicator -ne '=>' }
Output:
PS D:\PShell> D:\PShell\SO\50510142.ps1
Compare-Object $a $b
InputObject SideIndicator
----------- -------------
fn_SQLPerfomance_Monitor =>
fn_StatementEndOfMonth <=
Compare-Object $a $b | ? SideIndicator -ne '<='
fn_SQLPerfomance_Monitor =>
Compare-Object $a $b | ? SideIndicator -ne '=>'
fn_StatementEndOfMonth <=
Compare-Object $a $b -PassThru
fn_SQLPerfomance_Monitor
fn_StatementEndOfMonth
Compare-Object $a $b -PassThru | ? SideIndicator -ne '<='
fn_SQLPerfomance_Monitor
Compare-Object $a $b -PassThru | ? SideIndicator -ne '=>'
fn_StatementEndOfMonth
For those confused about Compare-Object
output:
$x = Compare-Object $a $b
$x[0].Gettype()
$y = Compare-Object $a $b -PassThru
$y[0].Gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
True True String System.Object
Above is valid despite of documentation (wrongly) says
Outputs
None, or the objects that are different.
When you use the
PassThru
parameter,Compare-Object
returns the objects that differed. Otherwise, this cmdletdoes not generate any output.
Upvotes: 0
Reputation: 2835
It seems like you actually want to do the exact opposite of compare-object. To get exactly what you said you needed in $C (I'm not sure why 'fn_StatementEndOfMonth' shouldn't be there as well), you can do the following:
$a = 'fn_StatementEndOfMonth
fn_Performance_Sql
fn_DailyReturns' -split '[\r\n]'
$b = 'fn_Performance_Sql
fn_DailyReturns
fn_SQLPerfomance_Monitor' -split '[\r\n]'
$c = $b | % { if($_ -notin $a){$_} }
$c
fn_SQLPerfomance_Monitor
Upvotes: 0
Reputation: 110
You're missing -PassThru switch on the Compare-Object command:
$A = Get-Content 'C:\temp\test1.txt'
$B = Get-Content 'C:\temp\test2.txt'
$C = 'c:\temp\diff.txt'
Compare-Object $A $B -PassThru | Out-File -FilePath $C
Upvotes: 0