Solved

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

Posted on 2016-10-01
8
66 Views
Last Modified: 2016-10-06
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)
0
Comment
Question by:enthuguy
8 Comments
 
LVL 12

Expert Comment

by:Carlo-Giuliani
Comment Utility
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
 
LVL 78

Expert Comment

by:David Johnson, CD, MVP
Comment Utility
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
 

Author Comment

by:enthuguy
Comment Utility
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
 
LVL 78

Expert Comment

by:David Johnson, CD, MVP
Comment Utility
it will ask you.. read-host gets input from standard input which in this case is the keyboard
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 16

Expert Comment

by:Learnctx
Comment Utility
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
 

Author Comment

by:enthuguy
Comment Utility
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
 
LVL 78

Accepted Solution

by:
David Johnson, CD, MVP earned 500 total points
Comment Utility
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
 

Author Closing Comment

by:enthuguy
Comment Utility
Thanks very much!!
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

New Windows 7 Installations take days for Windows-Updates to show up and install. This can easily be fixed. I have finally decided to write an article because this seems to get asked several times a day lately. This Article and the Links apply to…
Possible fixes for Windows 7 and Windows Server 2008 updating problem. Solutions mentioned are from Microsoft themselves. I started a case with them from our Microsoft Silver Partner option to open a case and get direct support from Microsoft. If s…
This tutorial will give a an overview on how to deploy remote agents in Backup Exec 2012 to new servers. Click on the Backup Exec button in the upper left corner. From here, are global settings for the application such as connecting to a remote Back…
This tutorial will walk an individual through the steps necessary to enable the VMware\Hyper-V licensed feature of Backup Exec 2012. In addition, how to add a VMware server and configure a backup job. The first step is to acquire the necessary licen…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now