Often we come across situation to compare two reports. Report may be of any format and without knowing schema, it is difficult to process programmatically. One of the effective solution is to create XML reports and then write a powershell to compare the XMLs knowing the schema. Below is powershell script that basically reads data from two XML files and parses through the data for comparison. You have to specify the Node List object Name that you need to compare and works only for Node List with depth of 2 levels.
###################################################################################################################################################
# Configure the Variables before executing script.
# C:\Temp is location configured and XML reports should be named as <Computer1>_Report.xml and <Computer2>_Report.xml
###################################################################################################################################################
param (
$Computer1,
$Computer2,
$NodeListName
)
#Initializing Variables
cls
# Create header for HTML Report
$Head = ""
$Head +="BODY{background-color:#CCCCCC;font-family:Calibri,sans-serif; font-size: small;}"
$Head +="TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse; width: 98%;}"
$Head +="TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:#293956;color:white;padding: 5px; font-weight: bold;text-align:left;}"
$Head +="TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:#F0F0F0; padding: 2px;}"
$Head +="TD:nth-child(3) {width: 10%;}"
$Head +="TD:nth-child(2) {width: 45%;}"
$Head +="TD:nth-child(1) {width: 45%;}"
$Head +=""
$ComputerName = hostname
$ReportOutput = $null
$FilePath = "C:\Temp\" + $ComputerName + "_Comparison_Report.htm"
$a = "C:\Temp\" + $Computer1 + "_Report.xml"
$b = "C:\Temp\" + $Computer2 + "_Report.xml"
If (Test-Path $FilePath){ Remove-Item $FilePath -Force}
[XML]$Comp1 = Get-Content $a
[XML]$Comp2 = Get-Content $b
$C1 = $Comp1.SelectNodes("//$NodeListName")
$C2 = $Comp2.SelectNodes("//$NodeListName")
for ($i = 0; $i -lt $C2.ChildNodes.Count; $i++){
# Either Computer's Node has Empty Value
If (($C1.ChildNodes[$i].ChildNodes.Count -eq "") -or ($C1.ChildNodes[$i].ChildNodes.Count -eq $null) -or (($C2.ChildNodes[$i].ChildNodes.Count -eq "") -or ($C2.ChildNodes[$i].ChildNodes.Count -eq $null))){
$NodeName = $C1.ChildNodes[$i].LocalName
If (($C1.ChildNodes[$i].ChildNodes.Count -gt 0) -or ($C2.ChildNodes[$i].ChildNodes.Count -gt 0)) { $Hash = @{"Parameter" = "$NodeName"; "Computer1" = $C1.ChildNodes[$i].ChildNodes.innerXML ; "Computer2" = $C2.ChildNodes[$i].ChildNodes.innerXML ; "Result" = "Failure" } }
Else {$Hash = @{"Parameter" = "$NodeName"; "Computer1" = "No Data" ; "Computer2" = "No Data" ; "Result" = "Success" }}
$ReportOutput += New-Object psobject -Property $Hash | Select Computer1,Computer2,Result | ConvertTo-Html -Fragment -PreContent "$NodeName"
}
#Both Computer's Node has text value
ElseIf (($C1.ChildNodes[$i]."#text") -and ($C2.ChildNodes[$i]."#text")){
#Compare
$NodeName = $C1.ChildNodes[$i]|select -ExpandProperty name
$Value1 = $C1.ChildNodes[$i]."#text"
$Value2 = $C2.ChildNodes[$i]."#text"
If ($Value2 -eq $Value1) {$Hash = @{"Parameter" = "$NodeName"; "Computer1" = $Value1 ; "Computer2" = $Value2 ; "Result" = "Success" }}
Else {$Hash = @{"Parameter" = "$NodeName"; "Computer1" = $Value1 ; "Computer2" = $Value2 ; "Result" = "Failure" }}
$ReportOutput += New-Object psobject -Property $Hash | Select Computer1,Computer2,Result | ConvertTo-Html -Fragment -PreContent "$NodeName"
}
#Both Computer's Node has 1 Child Count
ElseIf (($C1.ChildNodes[$i].ChildNodes.Count -eq $C2.ChildNodes[$i].ChildNodes.Count) -and ($C1.ChildNodes[$i].ChildNodes.Count -eq 1)){
$Name = $C2.ChildNodes[$i].Name
$NodeName = $C2.SelectNodes("//$Name/*")|select -ExpandProperty LocalName
$Value1 = $C1.SelectNodes("//$NodeName")
$Value2 = $C2.SelectNodes("//$NodeName")
$Props = $C2.SelectNodes("//$NodeName/*")|select -Unique -ExpandProperty Localname
$Status = "Success"
foreach ($Prop in $props){
$Results = Compare-Object -ReferenceObject $value1 -DifferenceObject $Value2 -Property $prop -IncludeEqual
If (($Results.SideIndicator -Contains "")) { $Status = "Failure" }
}
$Hash = @{"Parameter" = "$NodeName"; "Computer1" = $Value1.InnerXml ; "Computer2" = $Value2.InnerXml ; "Result" = "$Status" }
$ReportOutput += New-Object psobject -Property $Hash | Select Computer1,Computer2,Result | ConvertTo-Html -Fragment -PreContent "$NodeName"
}
#Both Computer has equal number of Child Count
ElseIf (($C1.ChildNodes[$i].ChildNodes.Count -gt 1) -or ($C2.ChildNodes[$i].ChildNodes.Count -gt 1)){
#Compare
$Name1 = $C2.ChildNodes[$i].Name
$Name2 = $C2.SelectNodes("//$Name1/*")|select -Unique -ExpandProperty LocalName
$Values1 = $C1.SelectNodes("//$Name2")
$Values2 = $C2.SelectNodes("//$Name2")
$Props = $C2.SelectNodes("//$Name2/*")|select -Unique -ExpandProperty Localname
$Results = Compare-Object -ReferenceObject $values1 -DifferenceObject $Values2 -Property $Props -IncludeEqual -passThru
$Objects = @()
foreach ($result in $results) {
$var = $null
for ($j=0;$j -lt $props.count; $j++){
$prop = $props[$j]
$Var += $Result.$prop + ":"
}
$var = $var.Trim(":")
If ($result.SideIndicator -eq "") { $Hash = @{"Parameter" = $Name2; "Computer1" = "Mismatch/NotFound" ; "Computer2" = "$var" ; "Result" = "Failure" }}
If ($result.SideIndicator -eq "==") { $Hash = @{"Parameter" = $Name2; "Computer1" = "$var" ; "Computer2" = "$var" ; "Result" = "Success" }}
$obj = new-object psobject -Property $Hash
$Objects += $obj
}
$ReportOutput += $Objects | Select Computer1,Computer2,Result | ConvertTo-Html -Fragment -PreContent "$Name2"
}
}
ConvertTo-HTML -head $Head -body "$ReportOutput" | Out-File $FilePath
You can download sample Input XML for which the script works perfectly. I hope you can take this script and develop further to suit your needs.
Happy Coding!