Someone, somewhere, sent me down a path. At the end of it, while it is not where I needed to be, I learned — or relearned rather — about the Get-FileHash
cmdlet. Whether you know about it or not, we will quickly cover it and walk through some examples, as well. Get-FileHash
, and I quote, “Computes the hash value for a file by using a specified hash algorithm.” This is what it does, but is not the why. Here is its reference page, however: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-filehash, and the why, is definitely in there; you should read it.
The idea, for those that are not going to read it, is that we can obtain a file’s hash and then check the hash to ensure the file has not been changed. At this point in your career, you have likely seen file hashes near, or alongside, a file download. Checking the file hash against the file, after it is downloaded, allows you to be certain that the file is the right one and that it was not altered by the download process, or anything else. It is what you were expecting.
If you are going to run any of my below commands, first be certain you know your working directory and that it is a location where you have permissions to write. We will start by creating a new file, adding a sentence to it, and then returning that content to ensure it is properly in place.
New-Item -Name hashfile.txt -ItemType File Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 4/19/2022 7:06 PM 0 hashfile.txt
Add-Content -Path .\hashfile.txt -Value 'This is our file at the beginning.' Get-Content -Path .\hashfile.txt This is our file at the beginning.
That all works and so now we have a file with which can experiment. If you are wondering how you learn PowerShell, this is how you do it. Follow along, as there is a goodie further down below. In this example we invoke Get-FileHash
against our file, only returning the algorithm used and the hash. We are using Format-List
in order to better display this content.
Get-FileHash -Path .\hashfile.txt | Tee-Object -Variable SaveMeForLater | Format-List -Property Algorithm,Hash
Algorithm : SHA256 Hash : 3C55E3C7D4C2EEF6910CB70FC425549981528CBBC0400A705104DC09A9391356
In this example, we do the same as we did above, however, now we are going to try out the other parameter values that the Algorithm
parameter will accept. By default it uses SHA256
, but it will accept SHA1
, SHA384
, SHA512
, and MD5
, too.
Get-FileHash -Algorithm SHA1 -Path .\hashfile.txt | Format-List -Property Algorithm,Hash Algorithm : SHA1 Hash : BD002AAE71BEEBB69503871F2AD3793BA5764097 Get-FileHash -Algorithm SHA256 -Path .\hashfile.txt | Format-List -Property Algorithm,Hash Algorithm : SHA256 Hash : 3C55E3C7D4C2EEF6910CB70FC425549981528CBBC0400A705104DC09A9391356 Get-FileHash -Algorithm SHA384 -Path .\hashfile.txt | Format-List -Property Algorithm,Hash Algorithm : SHA384 Hash : E6BC50D6465FE3ECD7C7870D8A510DC8071C7D1E1C0BB069132ED712857082E34801B20F462E4386A6108192C076168A Get-FileHash -Algorithm SHA512 -Path .\hashfile.txt | Format-List -Property Algorithm,Hash Algorithm : SHA512 Hash : C0124A846506B57CE858529968B04D2562F724672D8B9E2286494DB3BBB098978D3DA0A9A1F9F7FF0D3B862F6BD1EB86D301D025B80C0FC97D5B9619A1BD7D86 Get-FileHash -Algorithm MD5 -Path .\hashfile.txt | Format-List -Property Algorithm,Hash Algorithm : MD5 Hash : 30091603F57FE5C35A12CB43BB32B5F5
For fun, let’s loop through these values and pump out all the hashes, one right after another. Notice that we are using hard-coded values for the Algorithm
parameter. Obnoxious. We will get to another way, which is/was the goodie I mentioned above. The more I think about it though — as I have been in the last 10 minutes — the more I think it might need its own post. Anyway, more on that soon.
'SHA1','SHA256','SHA384','SHA512','MD5' | ForEach-Object {Get-FileHash -Algorithm $_ -Path '.\hashfile.txt' | Select-Object -Property Algorithm,Hash} Algorithm Hash --------- ---- SHA1 BD002AAE71BEEBB69503871F2AD3793BA5764097 SHA256 3C55E3C7D4C2EEF6910CB70FC425549981528CBBC0400A705104DC09A9391356 SHA384 E6BC50D6465FE3ECD7C7870D8A510DC8071C7D1E1C0BB069132ED712857082E34801B20F462E4386A6108192C076168A SHA512 C0124A846506B57CE858529968B04D2562F724672D8B9E2286494DB3BBB098978D3DA0A9A1F9F7FF0D3B862F6BD1EB86D301D025B80C0FC97D5B9619A1BD7D86 MD5 30091603F57FE5C35A12CB43BB32B5F5
And, there they are again. The various hashes for our file. Now, let’s add some new files. All we are going to do is copy and paste our hashfile.txt
to the same directory two times. Rename them so that in addition to hashfile.txt
, you have hashfilecopy.txt
and hashfile.copy
. Watch those names and file extensions, although really, how important do you have to be? Think about it…
When checking the hash of a file, we verify the file contents have not changed. And they have not been changed! Only the file name and file extension have. You are starting to see how this can be a useful tool and guess what? It is built-in.
Get-ChildItem | Get-FileHash | Format-List Algorithm : SHA256 Hash : 3C55E3C7D4C2EEF6910CB70FC425549981528CBBC0400A705104DC09A9391356 Path : C:\Users\tommymaynard\Documents\PowerShell_Get-FileHash\hashfile.copy Algorithm : SHA256 Hash : 3C55E3C7D4C2EEF6910CB70FC425549981528CBBC0400A705104DC09A9391356 Path : C:\Users\tommymaynard\Documents\PowerShell_Get-FileHash\hashfile.txt Algorithm : SHA256 Hash : 3C55E3C7D4C2EEF6910CB70FC425549981528CBBC0400A705104DC09A9391356 Path : C:\Users\tommymaynard\Documents\PowerShell_Get-FileHash\hashfilecopy.txt
Now real quick, let’s make another change. I am going to copy and paste hashfile.txt
one last time. This copy I have renamed to hashfilechanged.txt
. I opened it up and added a second sentence to it. Beneath the first line, I wrote, “This is our file at the end.”
Get-Content -Path .\hashfilechanged.txt
This is our file at the beginning. This is our file at the end.
Get-FileHash -Path .\hashfilechanged.txt | Tee-Object -Variable SaveMeForNow | Format-List -Property Algorithm,Hash
Algorithm : SHA256 Hash : 6998575555A0B7086E43376597BBB52582A4B9352AD4D3D642F38C6E612FDA76
I used Tee-Object
a couple of times in this post to capture the original hash and this one, after adding a second sentence. As you can see, the file contents are indeed different now, even though the files could have had the same name, were they in different directories.
$SaveMeForLater.Hash $SaveMeForNow.Hash 3C55E3C7D4C2EEF6910CB70FC425549981528CBBC0400A705104DC09A9391356 6998575555A0B7086E43376597BBB52582A4B9352AD4D3D642F38C6E612FDA76
And, the goodie I mentioned. It is official; it will get its own post. Why not? I make the rules. I’ll link it from here once it is up and published!