1

So I have two servers and two folders which should contain the same *.jar, meaning same hash. I am trying to compare ex 2 jars from first to the 2 jars from the second server. Using the following always return Different because it is not taking each file separately.

$FileHash1 = (Get-FileHash '\\server1\c$\some_folder\*jar').Hash
$FileHash2 = (Get-FileHash '\\server2\c$\some_folder\*jar').Hash
if($FileHash1 -eq $FileHash2) {
    Write-Host "Equal"
} Else {
    Write-Host "Different"
}

I understand that somewhere there should be foreach but cant seem to find how exactly to make it work.

Delyan
  • 75
  • 1
  • 7
  • 1
    You can compare two collections with `Compare-Object`: `if(!(Compare-Object $FileHash1 $FileHash2)){ "Equal" }else{ "Different" }` – Mathias R. Jessen May 11 '23 at 15:57
  • @MathiasR.Jessen can you post this as an answer so I can click as solved? Just tested with same and different files, works like charm – Delyan May 11 '23 at 16:12
  • @MathiasR.Jessen just tried with 4 servers and returns an error ```Compare-Object : A positional parameter cannot be found that accepts argument 'System.Object[]'``` is there a way to make it work with more than 2 with this approach? – Delyan May 11 '23 at 16:29
  • Compare the first set against the second, then the first against the third, then the first against the fourth, etc. – Mathias R. Jessen May 11 '23 at 16:29
  • @MathiasR.Jessen how should this look as one liner? – Delyan May 11 '23 at 16:42
  • I'd never write it as a one-liner, I enjoy being able to read my own code :) – Mathias R. Jessen May 11 '23 at 16:43
  • Using this [`Join-Object script`](https://www.powershellgallery.com/packages/Join)/[`Join-Object Module`](https://www.powershellgallery.com/packages/JoinModule) (see also: [In Powershell, what's the best way to join two tables into one?](https://stackoverflow.com/a/45483110/1701026)): `Get-FileHash '\\server1\c$\some_folder\*jar' |FullJoin (Get-FileHash '\\server2\c$\some_folder\*jar') -on hash -name *1,*2`. But you might also have alook here: [Powershell Speed: How to speed up ForEach-Object MD5/hash check](https://stackoverflow.com/a/59916692/1701026) – iRon May 11 '23 at 16:49
  • @MathiasR.Jessen Yeah, I understand, but the need is a single response after the comparison of all servers. – Delyan May 11 '23 at 16:53
  • @Delyan what kind of response? A boolean (yes/no) answer? Do you not care about _which_ server or file differs? – Mathias R. Jessen May 11 '23 at 19:27

3 Answers3

3

So you could probably use Group-Object for this, group the array of hashes of and if there is a group whose .Count is 1 then you know for sure there is a difference between the folders. This assumes that there aren't duplicates in the source folders.

[array] $FileHash1 = (Get-FileHash '\\server1\c$\some_folder\*jar').Hash
[array] $FileHash2 = (Get-FileHash '\\server2\c$\some_folder\*jar').Hash

# If there is output from here, then for sure there is a difference between the folders
$FileHash1 + $FileHash2 | Group-Object | ? Count -EQ 1 

Another approach would be to use cmdlets designed for this:

# Create a source Catalog (only once)
$newFileCatalogSplat = @{
    Path            = '\\server1\c$\some_folder\*.jar'
    CatalogFilePath = 'path\to\mycatalog.cat'
}
New-FileCatalog @newFileCatalogSplat

# Then you can use it to test against any other path
$testFileCatalogSplat = @{
    CatalogFilePath = 'path\to\mycatalog.cat'
    Path            = '\\server2\c$\some_folder\*.jar'
    Detailed        = $true
}
Test-FileCatalog @testFileCatalogSplat
mklement0
  • 382,024
  • 64
  • 607
  • 775
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • works but it is more complex than the one suggested by Mathias which I will use - ```if(!(Compare-Object $FileHash1 $FileHash2)){ "Equal" }else{ "Different" } ``` The files should be exactly the same and cannot be different count between servers. – Delyan May 11 '23 at 16:21
  • also it was a sample, I have more than 2 servers to compare between. – Delyan May 11 '23 at 16:24
  • 1
    Not sure what you want me to answer to those comments, if you think `Compare-Object` is better then just use that. For the catalogs you just need a source catalog, then you can use that one to test it against any other path @Delyan – Santiago Squarzon May 11 '23 at 16:27
2

As mentioned in the comments, you can use Compare-Object to compare two collections - if they're symmetrical Compare-Object won't output anything, so testing for asymmetry is as easy as testing for any output:

if(-not(Compare-Object $fileHash1 $fileHash2 |Select -First 1)) {
    "Equal"
}

If you need to test multiple servers, pick one for reference, and compare all the others to it:

$reference,$rest = 'server1', 'server2', 'server3', 'server4'

$referenceList = @(Get-FileHash "\\${reference}\c$\some_folder\*jar" |ForEach-Object Hash)

foreach($otherServer in $rest) {
    $otherList = @(Get-FileHash "\\${otherServer}\c$\some_folder\*jar" |ForEach-Object Hash)
    $differences = Compare-Object $referenceList $otherList
    if ($differences) {
        Write-Warning "At least one file on '${otherServer}' is different from '${reference}'"
        # you might want to log $differences to a file here 
    }
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
0

If your files have the same name, you can create a list of file names actually an array), and compare them:

$Files = ("name1.jar", "name2.jar")

Foreach ($File in $Files) {
    $FileHash1 = (Get-FileHash "\\server1\c$\some_folder\$($File)").Hash
    $FileHash2 = (Get-FileHash "\\server2\c$\some_folder\$(File)").Hash
    if($FileHash1 -eq $FileHash2) {
        Write-Host $File "are equal"
    } Else {
        Write-Host $File "are different"
    }
}

Victor Silva
  • 723
  • 4
  • 17