2017-06-09 12 views
0

2つのExcelファイルまたはシートを比較できるスクリプトを作成する必要があります。また、セルの1つが同じでない場合は、どちらのファイルであるかを教えてくださいこれを行う方法を知っている、私はこのような別の状況を見たが、私はあなたが私を助けることができませんでしたか? 私のファイルはtest1.csvとtest2.csvですPowerShell:Excelファイル2枚または2枚を比較する

答えて

1

これを試してください。

$file1 = Import-Csv test1.csv 
$file2 = Import-Csv test2.csv 
Compare-Object $file1 $file2 -property "HeaderProperty" -IncludeEqual 
0

@Vivekクマールは:注意してください、Compare-Objectはデフォルトで値を持っており、それは結果の一部のみを与えることができ-SyncWindowパラメータがあります。

ここでは非常に良い説明は:http://community.idera.com/powershell/powershell_com_featured_blogs/b/tobias/posts/tipps-amp-tricks-using-compare-object

この「問題」を回避する一つの方法は、2で-ReferenceObjectを分割することで-SyncWindowを設定することです:

$file1 = Import-Csv test1.csv 
$file2 = Import-Csv test2.csv 
Compare-Object -ReferenceObject $file1 -DifferenceObject $file2 -SyncWindow ($file1.length/2) 
+1

それは興味深い記事だが、それだけで '-SyncWindow'は_version 2では5にデフォルト設定とabove_ PowerShellの_version 1_、に適用される、しかし、"既定値は[Int32] :: MaxValueです。つまり、このコマンドレットはオブジェクトコレクション全体を検査します。 - https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/compare-object – mklement0

0

あなたはファイルがCSVある言及しているので、あなたは標準的なPS機能で必要なすべてを行うことができます。
ただし、Excel(XLSX/XLS)ファイルを使用している場合は、https://github.com/RamblingCookieMonster/PSExcelというライブラリに興味があるかもしれません。 Import-XLSXの場合はImport-CSVに切り替えてください。

以下は、これを実行する方法の非常に基本的な例です。テストため

コード

function Report-OffendingCell { #NB: doesn't follow good naming conventions 
    [CmdletBinding()] 
    param (
     [Parameter(Mandatory=$true, ValueFromPipeline = $true)] 
     [long]$ColumnIndex 
     , 
     [Parameter(Mandatory=$true)] 
     [long]$RowIndex 
     , 
     [Parameter(Mandatory=$true)] 
     [string]$SheetName 
     , 
     [Parameter(Mandatory=$false)] 
     [string]$Explanation 
    ) 
    process {  
     #If you want column letters instead of numbers, use something like Convert-NumberToA1 from https://gallery.technet.microsoft.com/office/Powershell-function-that-88f9f690 
     #"[{0}]!{1}{2}" -f $SheetName, (Convert-NumberToA1 $ColumnIndex + 1), ($RowIndex + 1) 
     #I've returned an object instead, since that's more useful for any further PS automation 
     (New-Object -TypeName PSObject -Property @{ 
      ColumnNo = $ColumnIndex + 1 
      RowNo = $RowIndex + 1 
      SheetName = $SheetName 
      Explanation = $Explanation 
     }) 
    } 
} 

function Compare-Tables { 
    [CmdletBinding()] 
    param (
     [Parameter(Mandatory=$true)] 
     [PSObject[]]$Table1 
     , 
     [Parameter(Mandatory=$true)] 
     [PSObject[]]$Table2 
     , 
     [Parameter(Mandatory=$false)] 
     [string]$Table1Name = 'Table1' 
     , 
     [Parameter(Mandatory=$false)] 
     [string]$Table2Name = 'Table2' 
    ) 
    begin { 
     [long]$t1Cols = ($Table1[0].PSObject.Properties | Measure-Object).Count - 1 
     [long]$t2Cols = ($Table2[0].PSObject.Properties | Measure-Object).Count - 1 
     [long]$t1Rows = $Table1.Count - 1 
     [long]$t2Rows = $Table2.Count - 1 
     [long]$minCols = [System.Math]::Min($t1Cols, $t2Cols) 
     [long]$maxCols = [System.Math]::Max($t1Cols, $t2Cols) 
     [long]$minRows = [System.Math]::Min($t1Rows, $t2Rows) 
     [long]$maxRows = [System.Math]::Max($t1Rows, $t2Rows) 
     [string]$offendingColTable = if ($maxCols -eq $t1Cols){$Table1Name}else{$Table2Name} 
     [string]$offendingRowTable = if ($maxRows -eq $t1Rows){$Table1Name}else{$Table2Name} 
     write-verbose $offendingColTable 
     write-verbose $offendingRowTable 
     write-verbose $maxCols 
     write-verbose $t1Cols 
     write-verbose $t2Cols 
    } 
    process { 
     0..$minRows | %{ #loop through each row which is populated in both sheets 
      [long]$row = $_ 
      0..$minCols | 
       ?{(@($Table1[$row].PSObject.Properties)[$_].Value) -ne (@($Table2[$row].PSObject.Properties)[$_].Value)} | 
       Report-OffendingCell -RowIndex $row -SheetName $Table2Name -Explanation 'Values differ between sheets!' #sheetname could be Table1 or Table2 here; since the cell exists in both sheets 
      ($minCols + 1)..$maxCols | Report-OffendingCell -RowIndex $row -SheetName $offendingColTable -Explanation 'Entire Column only exists on one sheet!' 
     } 
     ($minRows + 1)..$maxRows | %{ #for any rows which don't exist in one of the sheets, output that 
      [long]$row = $_ 
      0..$maxCols | Report-OffendingCell -RowIndex $row -SheetName $offendingRowTable -Explanation 'Entire Row only exists on one sheet!' 
     } 
    } 
} 

$test1 = Import-CSV -Path '.\test1.csv' 
$test2 = Import-CSV -Path '.\test2.csv' 
Compare-Tables -Table1 $test1 -Table2 $test2 -Table1Name 'test1' -Table2Name 'test2' -Verbose | ft SheetName, ColumnNo, RowNo, Explanation 

#just so I don't mess up your session with my mock 
if((Get-Command Import-Csv).Source -ne 'Microsoft.PowerShell.Utility') { 
    Remove-Item 'function:Import-Csv' 
} 

コード

次のコードを使用することができ、以下の例の出力を提供します。これにより、Import-CSV関数は固定値のデータを単に返す関数の模擬バージョンで上書きされます。このコードは実際のシナリオでは必須ではありません。試してみたいものがある適切なテスト用のCSVファイルを持っていない人のためだけです。

#region 'Mocked Standard Functions' 
#you don't need this function; this is just to make testing simple 
function Import-CSV { 
    param($Path) 
    switch ($Path) { 
     '.\test1.csv' { 
      @(
       @{ 
        'Column A Heading'='Row 1 Cell 1'; 
        'Column B Heading'='Row 1 Cell 2'; 
        'Column C Heading'='Row 1 Cell 3'; 
        'Column D Heading'='Row 1 Cell 4'; 
       } 
       , @{ 
        'Column A Heading'='Row 2 Cell 1'; 
        'Column B Heading'='Row 2 Cell 2'; 
        'Column C Heading'='Row 2 Cell 3'; 
        'Column D Heading'='Row 2 Cell 4'; 
       } 
       , @{ 
        'Column A Heading'='Row 3 Cell 1'; 
        'Column B Heading'='Row 3 Cell 2'; 
        'Column C Heading'='Row 3 Cell 3'; 
        'Column D Heading'='Row 3 Cell 4'; 
       } 
      ) | %{(New-Object -TypeName PSObject -Property $_)} | select 'Column A Heading', 'Column B Heading', 'Column C Heading', 'Column D Heading' #select needed to ensure columns are returned in the correct order 
     } 
     '.\test2.csv' { 
      @(
       @{ 
        'Column Heading 1'='Row 1 Cell 1'; 
        'Column B Heading'='Row 1 Cell 2'; 
        'Column C Heading'='Row 1 Cell 3 difference'; 
        'Column D Heading'='Row 1 Cell 4'; 
       } 
       , @{ 
        'Column Heading 1'='Row 2 Cell 1'; 
        'Column B Heading'='Row 2 Cell 2'; 
        'Column C Heading'='Row 2 Cell 3'; 
        'Column D Heading'='Row 2 Cell 4'; 
        'Column E Heading'='Row 2 Cell 5 bonus ball!'; #note that though we've not defined on the previous "row", the import function assumes a table, so we'll still have a property on the previous row; only it'll be null 
       } 
      ) | %{(New-Object -TypeName PSObject -Property $_)}| select 'Column Heading 1', 'Column B Heading', 'Column C Heading', 'Column D Heading', 'Column E Heading' #select needed to ensure columns are returned in the correct order 

     } 
     default {throw "no dummy data defined for $Path"} 
    } 
} 
#endregion 'Mocked Standard Functions' 

出力例

SheetName ColumnNo RowNo Explanation        
--------- -------- ----- -----------        
test2   3  1 Values differ between sheets!   
test2   5  1 Entire Column only exists on one sheet! 
test2   5  2 Entire Column only exists on one sheet! 
test1   1  3 Entire Row only exists on one sheet! 
test1   2  3 Entire Row only exists on one sheet! 
test1   3  3 Entire Row only exists on one sheet! 
test1   4  3 Entire Row only exists on one sheet! 
test1   5  3 Entire Row only exists on one sheet! 
+0

申し訳ありませんが、データでこれを行うにはどうすればいいですか? – charlo

+0

確か;上記のコードを実行しますが、 '#region 'Mocked Standard Functions'セクションにコードを含めないでください。すなわち、 'import-csv'関数を上書きして、それらのCSVファイルがない場合でも、次のコードが誰かのために働くようにします。私はその追加のコードを分けることで、より明確にしようとします。 – JohnLBevan

+0

私は少し問題があります。私はスクリプトを実行すると結果がセルごとに表示されますが、2つのセルと各列に同じことが表示されます1:値はシートとセルの間で値が異なります – charlo

関連する問題