How to get boolean result of md5sum from two files in powershell

I had this question after viewing md5sum check using powershell v 1.0.

Hi Experts,
this is an extension to my above question.

could you pls help how to loop thru a directory and get md5sum on each file and find the same file on another directory and run the md5sum and return true or false

Say directory1 has 3 files and directory2 has 10 files.
Loop through each file in directory1 get md5 and find same file in directory2 and get md5 too
Get a summary of each file to a output file

output.txt
file1 = success
file2 = success
file3 = failure (md5 value did not match)
enthuguyAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
David Johnson, CD, MVPConnect With a Mentor OwnerCommented:
Test-something -directory1 c:\temp -directory2 C:\test2
Test-something c:\temp C:\test2
Test-something c:\temp c:\test2 -verbose #shows files as compared
Test-something c:\temp c:\test2 -debug #opens output file when done

Function Get-FileHash
{
	[CmdletBinding(DefaultParameterSetName = 'Path')]
	param(
		[System.String[]]
		$Path,

		[Alias('PSPath')]
		[System.String[]]
		$LiteralPath,

		[System.String]
		$Algorithm='SHA256'
	)
	
	# Construct the strongly-typed crypto object
	$hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm)
	
	$pathsToProcess = @()
	
	if($PSCmdlet.ParameterSetName  -eq 'LiteralPath')
	{
		$pathsToProcess += Resolve-Path -LiteralPath $LiteralPath
	}
	else
	{
		$pathsToProcess += Resolve-Path $Path
	}
	
	foreach($filePath in $pathsToProcess)
	{
		if(Test-Path -LiteralPath $filePath -PathType Container)
		{
			continue
		}
		
		try
		{
			# Read the file specified in $FilePath as a Byte array
			[system.io.stream]$stream = [system.io.file]::OpenRead($FilePath)

			# Compute file-hash using the crypto object
			[Byte[]] $computedHash = $hasher.ComputeHash($stream)
		}
		catch [Exception]
		{
			$errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FileReadError -f $FilePath, $_
			Write-Error -Message $errorMessage -Category ReadError -ErrorId 'FileReadError' -TargetObject $FilePath
			return
		}
		finally
		{
			if($stream)
			{
				$stream.Close()
			}
		}
		
		# Convert to hex-encoded string
		[string] $hash = [BitConverter]::ToString($computedHash) -replace '-',''

		$retVal = [PSCustomObject] @{
			Algorithm = $Algorithm.ToUpperInvariant()
			Hash = $hash
			Path = $filePath
		}
		$retVal.psobject.TypeNames.Insert(0, 'Microsoft.Powershell.Utility.FileHash')

		$retVal
	}
}

function Test-Something
{
    <#
        .SYNOPSIS
        Short Description
        .DESCRIPTION
        Detailed Description
        .EXAMPLE
        Test-Something
        explains how to use the command
        can be multiple lines
        .EXAMPLE
        Test-Something
        another example
        can have as many examples as you like
        .EXAMPLE
        Test-something -directory1 c:\temp -directory2 C:\test2
         .EXAMPLE
        Test-something c:\temp C:\test2
    #>
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$false, Position=0)]
        [Object]
        $directory1 = (read-host('Input Directory 1 Location')),
        
        [Parameter(Mandatory=$false, Position=1)]
        [Object]
        $directory2 =(read-host('Input Directory 2 Location'))

    )
    
        
    if (!(test-path $directory1)) {
        write-output ('invalid path:{0}' -f $directory1)
        break
    }
   
    if (!(test-path $directory2)) {
        write-output ('invalid path:{0}' -f $directory2)
        break
    }
    if( $directory2[$directory2.Length -1] -ne '\'){
        $directory2 += '\'
    }
    $myobject = @()
    $files = get-childitem -path $directory1 -File
    foreach ($file in $files){
        $hash = Get-FileHash $file.fullname
        $object = new-object -Typename psobject 
        $object | add-member -MemberType NoteProperty -Name 'Filename' -Value $file.name
        $object | add-member -MemberType NoteProperty -Name 'Hash' -Value $hash.Hash
        $myobject += $object
    }
    $myobject2 = @()
    foreach ($file in $myobject)
    {
        
        $testfile = $directory2 + $file.filename
        if(!(Test-path $testfile)) {
            write-output ('{0} not found' -f $testfile)
            break
        }
        else {
            $successful = '= Success'
            $hash = Get-FileHash $testfile
            if ($file.hash -ne $hash.hash){
                $successful = '= Failure (md5 value not match)'
            }
            write-verbose('{0} = {1}' -f $file.fileName,$successful)
            $object = new-object -Typename psobject 
            $object | add-member -MemberType NoteProperty -Name 'Filename' -Value $file.Filename
            $object | add-member -MemberType NoteProperty -Name 'Success' -Value $successful
            $myobject2 += $object
        }
        $myobject2 | out-file c:\test2\ee.txt
       
    }
    if($DebugPreference -ne 'SilentlyContinue') {
     c:\test2\ee.txt
     }
}

Open in new window

1
 
Carlo-GiulianiCommented:
Try something like this

$directory1 = '\\server\share\folder1'
$directory2 = '\\server\share\folder2'

$files = GCI $directory1  

ForEach ($f in $files) {
    $hash1 = Get-FileHash $f.fullname
    $hash2 = Get-FileHash (Join-Path $directory2 $f.name)
    Write-Host $f.name ($hash1 -eq $hash2)
    }

Open in new window

2
 
David Johnson, CD, MVPOwnerCommented:
Function Get-FileHash
{
	[CmdletBinding(DefaultParameterSetName = 'Path')]
	param(
		[System.String[]]
		$Path,

		[Alias('PSPath')]
		[System.String[]]
		$LiteralPath,

		[System.String]
		$Algorithm='SHA256'
	)
	
	# Construct the strongly-typed crypto object
	$hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm)
	
	$pathsToProcess = @()
	
	if($PSCmdlet.ParameterSetName  -eq 'LiteralPath')
	{
		$pathsToProcess += Resolve-Path -LiteralPath $LiteralPath
	}
	else
	{
		$pathsToProcess += Resolve-Path $Path
	}
	
	foreach($filePath in $pathsToProcess)
	{
		if(Test-Path -LiteralPath $filePath -PathType Container)
		{
			continue
		}
		
		try
		{
			# Read the file specified in $FilePath as a Byte array
			[system.io.stream]$stream = [system.io.file]::OpenRead($FilePath)

			# Compute file-hash using the crypto object
			[Byte[]] $computedHash = $hasher.ComputeHash($stream)
		}
		catch [Exception]
		{
			$errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FileReadError -f $FilePath, $_
			Write-Error -Message $errorMessage -Category ReadError -ErrorId 'FileReadError' -TargetObject $FilePath
			return
		}
		finally
		{
			if($stream)
			{
				$stream.Close()
			}
		}
		
		# Convert to hex-encoded string
		[string] $hash = [BitConverter]::ToString($computedHash) -replace '-',''

		$retVal = [PSCustomObject] @{
			Algorithm = $Algorithm.ToUpperInvariant()
			Hash = $hash
			Path = $filePath
		}
		$retVal.psobject.TypeNames.Insert(0, 'Microsoft.Powershell.Utility.FileHash')

		$retVal
	}
}

$myobject = @()
$directory1 = read-host('Input Directory 1 Location')
if (!(test-path $directory1)) {
write-output ('invalid path:{0}' -f $directory1)
break
}
$directory2 = read-host('Input Directory 2 Location')
if (!(test-path $directory2)) {
write-output ('invalid path:{0}' -f $directory2)
break
}
if( $directory2[$directory2.Length -1] -ne '\'){
$directory2 += '\'
}
$files = get-childitem -path $directory1 -File
foreach ($file in $files){
$hash = Get-FileHash $file.fullname
$object = new-object -Typename psobject 
$object | add-member -MemberType NoteProperty -Name 'Filename' -Value $file.name
$object | add-member -MemberType NoteProperty -Name 'Hash' -Value $hash.Hash
$myobject += $object
}
$myobject2 = @()
foreach ($file in $myobject)
{

$testfile = $directory2 + $file.filename
if(!(Test-path $testfile)) {
write-output ('{0} not found' -f $testfile)
break
}
else {
$successful = '= Success'
$hash = Get-FileHash $testfile
if ($file.hash -ne $hash.hash){
$successful = '= Failure (md5 value not match)'
}
write-output('{0} = {1}' -f $file.fileName,$successful)
$object = new-object -Typename psobject 
$object | add-member -MemberType NoteProperty -Name 'Filename' -Value $file.Filename
$object | add-member -MemberType NoteProperty -Name 'Success' -Value $successful
$myobject2 += $object
}
$myobject2 | out-file c:\test2\ee.txt

}

Open in new window

1
Simplify Active Directory Administration

Administration of Active Directory does not have to be hard.  Too often what should be a simple task is made more difficult than it needs to be.The solution?  Hyena from SystemTools Software.  With ease-of-use as well as powerful importing and bulk updating capabilities.

 
enthuguyAuthor Commented:
Thanks Carlo, that looks neat but I believe 1.0 doesn't support this

thanks David, I will try tonight, as I'm away from my pc. btw how should call this function? how to pass the two directory as parameter  (sorry I'm sort of new to powershell)
0
 
David Johnson, CD, MVPOwnerCommented:
it will ask you.. read-host gets input from standard input which in this case is the keyboard
0
 
LearnctxEngineerCommented:
Using the same function from the other post, I would keep it simple create 2 arrays with a list of files and hashes and then use compare-object to find the differences.

Function Get-FileHash
{
	[CmdletBinding(DefaultParameterSetName = "Path")]
	param(
		[System.String[]]
		$Path,

		[Alias("PSPath")]
		[System.String[]]
		$LiteralPath,

		[System.String]
		$Algorithm="SHA256"
	)
	
	# Construct the strongly-typed crypto object
	$hasher = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm)
	
	$pathsToProcess = @()
	
	if($PSCmdlet.ParameterSetName  -eq "LiteralPath")
	{
		$pathsToProcess += Resolve-Path -LiteralPath $LiteralPath
	}
	else
	{
		$pathsToProcess += Resolve-Path $Path
	}
	
	foreach($filePath in $pathsToProcess)
	{
		if(Test-Path -LiteralPath $filePath -PathType Container)
		{
			continue
		}
		
		try
		{
			# Read the file specified in $FilePath as a Byte array
			[system.io.stream]$stream = [system.io.file]::OpenRead($FilePath)

			# Compute file-hash using the crypto object
			[Byte[]] $computedHash = $hasher.ComputeHash($stream)
		}
		catch [Exception]
		{
			$errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FileReadError -f $FilePath, $_
			Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath
			return
		}
		finally
		{
			if($stream)
			{
				$stream.Close()
			}
		}
		
		# Convert to hex-encoded string
		[string] $hash = [BitConverter]::ToString($computedHash) -replace '-',''

		$retVal = [PSCustomObject] @{
			Algorithm = $Algorithm.ToUpperInvariant()
			Hash = $hash
			Path = $filePath
		}
		$retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash")

		$retVal
	}
}

$arr1 = gci -Recurse c:\temp\folder1 | % {
	Get-FileHash $_.fullname} | select `
		@{n="Hash";e={$_.item("hash")}}, `
		@{n="algorithm";e={$_.item("algorithm")}}, `
		@{n="Path";e={$_.item("path")}
}

$arr2 = gci -Recurse c:\temp\folder2 | % {
	Get-FileHash $_.fullname} | select `
		@{n="Hash";e={$_.item("hash")}}, `
		@{n="algorithm";e={$_.item("algorithm")}}, `
		@{n="Path";e={$_.item("path")}
}

Compare-Object -ReferenceObject $arr1 -DifferenceObject $arr2 -Property hash | % {
	$indicator = $_
	if ($indicator.sideindicator -eq "<=")
	{
		$arr1 | ? {$_.hash -eq $indicator.hash}
	}
	else
	{
		$arr2 | ? {$_.hash -eq $indicator.hash}
	}
}

Open in new window


I find Compare-Object a simple way to compare arrays.
1
 
enthuguyAuthor Commented:
Hi David,
Thanks very much...that worked fine for me, I will attempt how to pass two directories as arguments to that function.

@Learnctx,
I changed the path in the function but I rece. below blank report. I'm sure I did something wrong...sorry :(

PS C:\parent\scripts> .\compareMD52.ps1

Hash                                                        algorithm                                                   Path
----                                                        ---------                                                   ----
0
 
enthuguyAuthor Commented:
Thanks very much!!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.