Powershell - Compare two lists of files and their content

时间:2021-12-13 22:51:28

While this might seem simple (and it might be!) I can't seem to find a way to solve it.

虽然这可能看起来很简单(而且可能是!)但我似乎无法找到解决问题的方法。

What I am trying to do is compare two lists of filtered files by their content. A example of this would be if two lists came back saying that they had a item called file.config at the location Stuff\files\morefiles then this would compare those files together and output where and what the changes were. Essentially, doing a diff of the .config files and showing where the changes are. This is normally simple for comparing two files (compare-object and such can be used) but because it is two lists of files rather then individual ones I am at a loss.

我想要做的是比较两个过滤文件列表的内容。这样做的一个例子是,如果两个列表回来说他们在Stuff \ files \ morefiles位置有一个名为file.config的项目,那么这会将这些文件进行比较并输出更改的位置和内容。本质上,执行.config文件的差异并显示更改的位置。这对于比较两个文件通常很简单(比较对象等可以使用)但是因为它是两个文件列表而不是单个文件我不知所措。

I need to do this to show a list of all changes needed to config files in a upgrade of software, so from one version of the software to the next, what are the changes made to the config files. I'm doing this in powershell because of the ability to easily interact with HG mercurial and be run by less experienced users (via a bat file).

我需要这样做以显示在软件升级中配置文件所需的所有更改的列表,因此从一个版本的软件到下一个版本,对配置文件进行了哪些更改。我在powershell中这样做是因为它能够轻松地与HG mercurial交互并由经验不足的用户(通过bat文件)运行。

The goal is to have a .txt file listing all the files that are changed in the new installation compared with the old one, or something similar.

目标是使用.txt文件列出新安装中与旧版本相比更改的所有文件或类似内容。

Here's what I have so far:

这是我到目前为止所拥有的:

$A = Get-ChildItem -Recurse -path "C:\repos\Dev\Projects\Bat\CurrentVersionRepoCloneTemp" -filter "*.config"

$B = Get-ChildItem -Recurse -path "C:\repos\Dev\Projects\Bat\UpgradeVersionRepoCloneTemp" -filter "*.config"

$C = Compare-Object $A $B -Property ('Name', 'Length') -PassThru | Where-Object {$_.FullName -eq $_.FullName} | ForEach-Object 
{    
    Compare-Object (Get-Content FileA)(Get-Content FileB) #I know this doesn't work 
}$C

Ideas or solutions?

想法或解决方案?

Thank you all in advance

谢谢大家

2 个解决方案

#1


3  

You could do a checksum of each file and compare that...

你可以对每个文件做一个校验和并比较一下......

$md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($file)))

#2


2  

Tim Ferrill's idea for checking updated files seems like a much better way to compare the files. Do something like

Tim Ferrill检查更新文件的想法似乎是比较文件的更好方法。做点什么

$A = Get-ChildItem -Recurse -path "C:\repos\Dev\Projects\Bat\CurrentVersionRepoCloneTemp" -filter "*.config"
$B = Get-ChildItem -Recurse -path "C:\repos\Dev\Projects\Bat\UpgradeVersionRepoCloneTemp" -filter "*.config"
$A | %{$_ | Add-Member "MD5" ([System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($_))))}
$B | %{$_ | Add-Member "MD5" ([System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($_))))}

Then I'd do the compare and group by directory.

然后我会做比较和分组目录。

$C = Compare-Object $A $B -Property ('Name', 'MD5') - Passthrough | Group Directory

After that, getting actual changes, that's going to be a little slow. Doing a line-by-line match of file contents is rough, but if they aren't too large it should still happen in a blink of an eye. I'd suggest something like:

在那之后,获得实际的变化,这将会有点慢。对文件内容进行逐行匹配是很粗略的,但如果它们不是太大,它仍然应该在眨眼之间发生。我建议像:

$Output = @()
ForEach($File in $C[1].Group){
    $OldData = GC $File
    $C[0].Group | ?{$_.Name -eq $File.Name} | %{
        $NewData = GC $_
        $UpdatedLines = $NewData | ?{$OldData -inotcontains $_}
        $OldLines = $OldData | ?{$NewData -inotcontains $_}
        $Output += New-Object PSObject -Property @{
            UpdatedFile=$_.FullName
            OriginalFile=$File.FullName
            Changes=$UpdatedLines
            Removed=$OldLines
        }
    }
}

Once you have that you just have to output it in something readable. Maybe something like this:

一旦你有了,你只需要输出可读的东西。也许是这样的:

Get-Date | Out-File "C:\repos\Dev\Projects\Bat\UpgradeVersionRepoCloneTemp\ChangeLog.txt"
$Output|%{$_|FT OriginalFile,UpdatedFile; "New/Changed Lines"; "-----------------"; $_.Changes; " "; "Old/Removed Lines"; "-----------------"; $_.Removed} | Out-File "C:\repos\Dev\Projects\Bat\UpgradeVersionRepoCloneTemp\ChangeLog.txt" -Append

#1


3  

You could do a checksum of each file and compare that...

你可以对每个文件做一个校验和并比较一下......

$md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($file)))

#2


2  

Tim Ferrill's idea for checking updated files seems like a much better way to compare the files. Do something like

Tim Ferrill检查更新文件的想法似乎是比较文件的更好方法。做点什么

$A = Get-ChildItem -Recurse -path "C:\repos\Dev\Projects\Bat\CurrentVersionRepoCloneTemp" -filter "*.config"
$B = Get-ChildItem -Recurse -path "C:\repos\Dev\Projects\Bat\UpgradeVersionRepoCloneTemp" -filter "*.config"
$A | %{$_ | Add-Member "MD5" ([System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($_))))}
$B | %{$_ | Add-Member "MD5" ([System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($_))))}

Then I'd do the compare and group by directory.

然后我会做比较和分组目录。

$C = Compare-Object $A $B -Property ('Name', 'MD5') - Passthrough | Group Directory

After that, getting actual changes, that's going to be a little slow. Doing a line-by-line match of file contents is rough, but if they aren't too large it should still happen in a blink of an eye. I'd suggest something like:

在那之后,获得实际的变化,这将会有点慢。对文件内容进行逐行匹配是很粗略的,但如果它们不是太大,它仍然应该在眨眼之间发生。我建议像:

$Output = @()
ForEach($File in $C[1].Group){
    $OldData = GC $File
    $C[0].Group | ?{$_.Name -eq $File.Name} | %{
        $NewData = GC $_
        $UpdatedLines = $NewData | ?{$OldData -inotcontains $_}
        $OldLines = $OldData | ?{$NewData -inotcontains $_}
        $Output += New-Object PSObject -Property @{
            UpdatedFile=$_.FullName
            OriginalFile=$File.FullName
            Changes=$UpdatedLines
            Removed=$OldLines
        }
    }
}

Once you have that you just have to output it in something readable. Maybe something like this:

一旦你有了,你只需要输出可读的东西。也许是这样的:

Get-Date | Out-File "C:\repos\Dev\Projects\Bat\UpgradeVersionRepoCloneTemp\ChangeLog.txt"
$Output|%{$_|FT OriginalFile,UpdatedFile; "New/Changed Lines"; "-----------------"; $_.Changes; " "; "Old/Removed Lines"; "-----------------"; $_.Removed} | Out-File "C:\repos\Dev\Projects\Bat\UpgradeVersionRepoCloneTemp\ChangeLog.txt" -Append