Discussion
File hashes provide a useful way to check for damage or modification to a file. Adigital hash acts like the fingerprint of a file and detects even minor modifications. If the content of a file changes, then so does its hash. Many online download services provide the hash of a file on that file’s download page so that you can determine whether the transfer somehow corrupts the file.
There are three common ways to generate the hash of a file: MD5, SHA1, SHA256. The two most common are MD5, followed by SHA1. While popular, these hash types can be trusted to detect only accidental file modification. They can be fooled if somebody wants to tamper with the file without changing its hash. The SHA256 algorithm can be used to protect against even intentional file tampering.
Example 173 lets you determine the hash of a file (or of multiple files if provided by the pipeline).
Example 173. GetFileHash.ps1
############################################################################## ## ## GetFileHash.ps1 ## ## Get the hash of an input file. ## ## ie: ## ## PS >GetFileHash myFile.txt ## PS >dir | GetFileHash ## PS >GetFileHash myFile.txt Hash SHA1 ## ##############################################################################
param( $path, $hashAlgorithm = "MD5" )
## Create the hash object that calculates the hash of our file. If they ## provide an invalid hash algorithm, provide an error message. if($hashAlgorithm eq "MD5") {
$hasher = [System.Security.Cryptography.MD5]::Create() } elseif($hashAlgorithm eq "SHA1") {
$hasher = [System.Security.Cryptography.SHA1]::Create() } elseif($hashAlgorithm eq "SHA256") {
$hasher = [System.Security.Cryptography.SHA256]::Create() } else {
$errorMessage = "Hash algorithm $hashAlgorithm is not valid. Valid " +
"algorithms are MD5, SHA1, and SHA256." WriteError $errorMessage return
}
Example 173. GetFileHash.ps1 (continued)
## Create an array to hold the list of files $files = @()
## If they specified the file name as a parameter, add that to the list ## of files to process if($path) {
$files += $path } ## Otherwise, take the files that they piped in to the script. ## For each input file, put its full name into the file list else {
$files += @($input | ForeachObject { $_.FullName }) }
## Go through each of the items in the list of input files foreach($file in $files) {
## Convert it to a fullyqualified path $filename = (ResolvePath $file ErrorAction SilentlyContinue).Path
## If the path does not exist (or is not a file,) just continue if((not $filename) or (not (TestPath $filename Type Leaf))) {
continue }
## Use the ComputeHash method from the hash object to calculate ## the hash $inputStream = NewObject IO.StreamReader $filename $hashBytes = $hasher.ComputeHash($inputStream.BaseStream) $inputStream.Close()
## Convert the result to hexadecimal $builder = NewObject System.Text.StringBuilder $hashBytes | ForeachObject { [void] $builder.Append($_.ToString("X2")) }
## Return a custom object with the important details from the ## hashing $output = NewObject PsObject $output | AddMember NoteProperty Path ([IO.Path]::GetFileName($file)) $output | AddMember NoteProperty HashAlgorithm $hashAlgorithm $output | AddMember NoteProperty HashValue ([string] $builder.ToString()) $output
}