我有两个Excel电子表格我想比较:
$OleDbAdapter = New-Object System.Data.OleDb.OleDbDataAdapter “Select * from [Report$]“,”Provider=Microsoft.ACE.OLEDB.12.0;Data Source=S:\FIS-BIC Reporting\Report Output Files\Product-Marketing\TEST_XI\ECM - Pipeline by LOB_04182013_040544.xls;Extended Properties=”"Excel 12.0 Xml;HDR=YES”";”
$RowsReturned = $OleDbAdapter.Fill($DataTable)
$OleDbAdapter2 = New-Object System.Data.OleDb.OleDbDataAdapter “Select * from [Report$]“,”Provider=Microsoft.ACE.OLEDB.12.0;Data Source=S:\FIS-BIC Reporting\Report Output Files\Product-Marketing\ECM - Pipeline by LOB_04182013_074004.xls;Extended Properties=”"Excel 12.0 Xml;HDR=YES”";”
$RowsReturned2 = $OleDbAdapter2.Fill($DataTable2)
Compare-Object $DataTable $DataTable2
它什么都不返回。我知道在第6栏中,它们是不同的。如果我指定“-property F6”,它确实会返回差异。除非我指定属性,否则任何想法都没有?列数可以变化(虽然比较中的每个文件都相同),因此具体指定属性将不起作用。
如果未指定-Property参数,则Compare-Object不会比较所有属性,而是比较在两个对象上调用.ToString()方法的结果。因此,Compare-Object $DataTable $DataTable2
将$ DataTable1.ToString()与$ DataTable1.ToString()进行比较。在DataTable对象上调用时,.ToString()方法返回一个空字符串,因此报告没有区别。
例如:
$file1 = Get-Item somefilename
$file1 = Get-Item anotherfilename
Compare-Object $file1 $file2
这将返回两个文件的完整路径之间的差异,如下所示:
InputObject SideIndicator
----------- -------------
<path>\anotherfilename =>
<path>\somefilename <=
这是因为在FileInfo对象上调用.ToString()会返回其FullName属性,因此您要比较文件的完整路径名。
虽然-Property参数接受多个属性,但列出所有属性不是解决方案。除了非常乏味,它不会给你你想要的结果。如果列出多个属性,则Compare-Object会比较所有属性的组合,如果列出的属性中的任何一个不同,则返回显示所有列出属性的结果(两个属性相同且不同的属性)作为单一的差异。
您需要做的是迭代属性列表,并为每个属性调用一次Compare-Object:
$properties = ($DataTable | Get-Member -MemberType Property | Select-Object -ExpandProperty Name)
foreach ($property in $properties) {
Compare-Object $DataTable $DataTable2 -Property "$property" | Format-Table -AutoSize
}
Get-Member -MemberType Properties
,以覆盖所有属性类型。但是,如果您要比较DataTable对象,最好使用Get-Member -MemberType Property
,这样您只能比较与数据字段对应的属性,而不是与数据无关的DataTable对象的其他属性。($DataTable | Get-Member -MemberType Property).Count
与($DataTable2 | Get-Member -MemberType Property).Count
进行比较并使用更大的属性来从任何具有更多列的$ properties数组派生。-AutoSize
开关是可选的。那就是让事情看起来很漂亮。但是您必须将结果传递给格式化过滤器。如果您愿意,也可以使用Format-List。Adi Inbar's helpful answer包含有关Compare-Object
如何工作的良好背景信息。
但是,有一种方法可以通常使用-Property
来比较所有列值 - 假设两个输入表具有相同的列结构,或者表只应该通过第一个表的列进行比较:
# The original collection.
$coll1 = [pscustomobject] @{ one = '1a'; two = '2a'; three = '3a' },
[pscustomobject] @{ one = "1b"; two = "2b"; three = '3b' }
# The other collection to compare the original to.
# Note the difference in the 2nd object in column 'two'
$coll2 = [pscustomobject] @{ one = '1a'; two = '2a'; three = '3a' },
[pscustomobject] @{ one = "1b"; two = "2b!"; three = '3b' }
# PSv3+: Get the array of all property names to compare
# from the original collection.
# Note:
# * The assumption is that both collections have the same set of
# properties (or that the collections should only be compared by
# the *first* collection's properties).
# * In PSv2-, use the following instead:
# $propsToCompare = $coll1[0].psobject.properties | % { $_.name }
$propsToCompare = $coll1[0].psobject.properties.name
# Compare the 2 collections by all property values.
# -PassThru means that any input object in which a difference is found
# is passed through as-is.
Compare-Object $coll1 $coll2 -Property $propsToCompare -PassThru
以上产量:
one two three SideIndicator
--- --- ----- -------------
1b 2b! 3b =>
1b 2b 3b <=
请注意=>
如何告诉您所选对象对于<=
而言是右侧专有的,反之亦然。
需要注意的是Compare-Object
很慢,因为它无法对输入数据进行排序,因此必须完整地读取和比较两个输入集合。
使用排序输入,您可以使用-SyncWindow <Int32>
来加快速度,但这需要提前了解两个输入集合之间最多可以有多少项目,发现每个差异,如果-SyncWindow
值太小,则会出现虚假差异报道。