Recurse Drive: One-Line Output Stating Filename, Size, Date, Hash

With considerable assistance, I have developed a batch script that, for each file in a drive or folder, prints file date, time, size, hash, and path on a single line. Problem: the batch script uses nested FOR loops that may be the cause of the script’s very slow processing.

I had previously tried to devise a PowerShell command to the same end. The command I developed was as follows:

Get-FileHash -Algorithm SHA512 -LiteralPath (Get-ChildItem 'D:\folder\*.*' -Force -Recurse) | Select-Object Hash,Path | Format-Table -AutoSize | Out-File -filePath 'D:\Current\PSOut.txt' -Encoding ASCII -Width 400

This command seemed OK for getting the hash, at least, but as I recall it mostly neglected the other desired bits of file information (e.g., size). Its other problem was that it seemed to abort whenever it failed to find a file that it expected to find. That was problematic. Over the hours that it may take to hash a large drive, some files are likely to change or move.

I’m no PowerShell programmer. I can probably come to understand a relatively simple (or at least not absurdly long and/or complex) PowerShell solution. Batch is more familiar to me; I would also welcome insights into the slowness of that batch script.

Hi, welcome to the forum :wave:

While you could do this on one line a script is going to be easier to read and manage. You can use the power of custom objects to get your desired output.

I have assigned it all to a variable which could be displayed in the console, or output to a CSV. But you could output the objects to the pipeline for further processing, or export them one at a time to a CSV file.

$rootPath = 'E:\Temp\Files'

$fileList = Get-ChildItem $rootPath -Recurse -File

$fileInfo = foreach ($file in $fileList) {
    $hash = Get-FileHash -Algorithm SHA512 -Path $file.FullName
    [PSCustomObject] @{
        Path = $hash.Path
        Hash = $hash.Hash
        Size = $file.Length
    }
}

$fileInfo

I think that’s fairly self-explanatory and is not too different to your one-liner solution, but if you would like more details or clarification, please ask.

1 Like

Hi, Matt, and thanks for the quick response.

I have just one question: how does it work?

I guess $fileList is a variable - you could have called it @Goldfish - that contains the recursed list of files. Then $fileInfo becomes an array holding one row per hashed file.

Then [PSCustomObject] pretty much loses me. I guess it is defined as the concatenation of Path, Hash, and Size. And those are outputs or aspects of Get-FileHash?

And then $fileInfo is a print command?

In the vast majority of the cases you’re not first one with a particular question. So it makes sense to search for it first to get some insight.

Here you have some information about [PSCustomObject]

We PowerShellers do not call it printing. We just say “to output somethinh to the console”. :wink:

I did search, of course, and didn’t find an explanation. That’s why I asked.

You’re right, though. I could spend a few hours trying to piece it together. And you could have used fewer words to just answer the question.

Thanks for the information you did add.

If you excuse me being a bit pedantic: no, you couldn’t call it at @Goldfish because that’s not a valid variable name. $Goldfish would be OK though :).

One object per hashed file.

[PSCustomObject] is a type accelerator and is used for creating an object of type PSCustomObject. I recommend reading the article @Olaf linked for detailed information on that subject.

Suffice to say we are creating an object with three properties. We get two of those properties from the output of Get-FileHash (Get-FileHash outputs an object of type FileHash and Path and Hash are properties of that object), and we get the Length property from the FileInfo object representing the current file.

Implicitly, yes. PowerShell outputs it to the console because it’s not been told what to do with it. However, you could pipe it to another cmdlet such as Export-Csv, or Out-File, or Format-List.

2 Likes

Thanks, Matt. As I know, once a person gets familiar with something, it can be difficult to remember what it was like to know nothing about it.

Some questions, seeking brief answers as your time permits:

  • Short of checking the lists every time you want to define a variable, how can you know if your chosen variable is already a system variable? I guess you just get familiar with the fact that variables beginning with “root” or “file” are not taken?
  • Why doesn’t it say, Get-ChildItem -Path $rootPath -Recurse -File? If the provision of a valid path makes it obvious, why would anyone ever include -Path?
  • Why would someone use ForEach-Object if (as it appears) foreach does the same thing?
  • Where or how is the $file.FullName variable defined? Why include a period in its name?
  • I suspect the answer to the preceding question will also shed light on $hash.Path etc.

You’re right - that PSCustomObject article is definitely good for “detailed information on that subject.” The suggestion to start there was like handing someone a textbook titled, “Statistical Procedures for Population Analysis,” when they merely asked whether Ohio contains more resettled refugees than Michigan.

I disagree. It’s a very easy to read and follow page that collects tons of information that one would otherwise have to spend exponentially more time to learn then the ~10 minutes it took to read.

[PSCustomObject] is a type accelerator and is used for creating an object of type PSCustomObject . I recommend reading the article @Olaf linked for detailed information on that subject.

He gave you the answer to the Ohio question and suggested the article for more detailed information.

Were you not able to determine what the [PSCustomObject] type accelerator does/where it’s useful?

2 Likes

Sorry, Crazy Doug, these responses don’t address my questions.

Your profile describes you as a long-time IT pro. I appreciate that that technical article on PowerShell is easy for you - requiring, you say, only ten minutes to read and understand what you rightly describe as its “tons of information.” As I said before, I realize that an expert in a subject may have no concept of what it is like to be a beginner.

You’re certainly entitled to your opinions about the PSCustomObject article, and so forth. But if you could restrain yourself from preaching at me, and just answer the specific questions I have posed, that would actually be helpful.

I never claimed to answer any of your questions. I just joined in with throwing opinions around, as you’ve done quite well throughout this post. Sorry if I’m not allowed to partake, my mistake.

Speaking of not answering questions.

Did you get the understanding of PSCustomObject you were hoping to get, or are there specific questions you still have?

1 Like

Doug, if I understand correctly, you feel that I found the PSCustomObject article helpful - that it answered my questions - and that you’re not sure what those questions are.

If you use a decent IDE, like VSCode, it will warn you.

Best practice, especially when writing code that others will read, is to be as verbose as possible and I should have included the parameter name. However, it’s not always necessary to include the parameter name. See Get-Help about_ Parameters.

They are different. This is a common ‘gotcha’ that you need to be aware of:

As the foreach loop iterates through the collection of files in $fileList the file currently being worked on is assigned to the variable $file.
FullName is a property of FileInfo objects and one way of accessing that property’s value is using the dot notation.

Yes, Path and Hash are properties of a FileHashInfo object. Get-FileHash returns an object of type FileHashInfo, this object is referenced by the variable $hash.

Try this:

Get-FileHash -Algorithm SHA512 -Path C:\Windows\System32\notepad.exe | Get-Member

If you want to get started with PowerShell, I recommend Learn Windows PowerShell in a Month of Lunches. If you work cross-platform, consider Learn PowerShell in a month of Lunches instead.

If you prefer video learning, Jon Savill has a great introduction on YouTube:

You should also familiarise yourself with Get-Help, Get-Command, and Get-Member.

3 Likes

Thank you again for your kind help, Matt. If I make a start in PowerShell, I will begin with the study resources you’ve recommended.

I have compiled much of this information into a blog post. As described there, my present impression is that I will have to devote considerable study to reach a point of using PowerShell effectively. This is the impression that has kept me using batch.

Take care.