0

I have been attempting to replicate the output of the Unix command find . -type f -exec md5sum {} + to compute hashes for all files in a directory and its subdirectories in PowerShell (i.e. two columns: MD5 hashes in lowercase and relative file paths). Is there a better way to have newlines marked with a line feed instead of a carriage return and a line feed than in the following code?

$Result = Get-FileHash -Algorithm MD5 -Path (Get-ChildItem "*.*" -Recurse) | Select-Object @{N='Hash';E={$_.Hash.ToLower()}},@{N='Path';E={$_.Path | Resolve-Path -Relative}}
($Result | Format-Table -AutoSize -HideTableHeaders | Out-String).Trim() + "`n" -replace ' *\r\n',"`n" | Set-Content -NoNewline -Encoding ascii $ENV:USERPROFILE\Desktop\MYFOLDER\hashes.txt

The first line returns the hashes in lowercase and the relative paths.

The second line uses Format-Table to exclude the column headings (with the option -HideTableHeaders plus it uses the option -AutoSize to avoid truncating long relative file paths).

Out-String converts the output to a string and .Trim() removes the preceding and trailing blank lines.

Presently, I add a line feed

`+ "`n"`

then use

`-replace ' *\r\n',"`n"`

to do the replacement and eliminate any extra spaces at the end of each line. Finally, Set-Content uses the option -NoNewline to avoid a newline with a carriage return.

I've seen these similar questions: Replace CRLF using powershell and In PowerShell how to replace carriage return

Stacey
  • 81
  • 2
  • 9
  • What is the question? A better place to present working code is [CodeReview](https://codereview.stackexchange.com/) –  Jun 08 '19 at 07:20
  • Nevrtheless a one liner `(Get-FileHash -Algorithm md5 -Path (Get-ChildItem "*.*" -Recurse)|ForEach-Object{"{0} {1}" -f $_.Hash.ToLower(),(Resolve-Path $_.Path -Relative)}|Out-String) -replace '\r(?=\n)'|Set-Content -NoNewline -Encoding Ascii sample.md5` –  Jun 08 '19 at 08:01

1 Answers1

0

Instead of replacing all "\r\n" newlines afterwards, this approach builds a list of strings and joins them together with the wanted newline character:

$path = 'YOUR ROOT DIRECTORY'
$algo = 'MD5'

$list = Get-ChildItem -Path $Path -File -Recurse | Get-FileHash -Algorithm $algo | ForEach-Object {
    "{0} {1}" -f $_.Hash.ToLower(), (Resolve-Path $_.Path -Relative)
}
Set-Content -Path 'D:\checksums.txt' -Value ($list -join "`n") -NoNewline -Encoding Ascii -Force

Another way of doing this could be to use a StringBuilder object together with its AppendFormat method:

$path = 'YOUR ROOT DIRECTORY'
$algo = 'MD5'

$sb = New-Object -TypeName System.Text.StringBuilder
Get-ChildItem -Path $Path -File -Recurse | Get-FileHash -Algorithm $algo | ForEach-Object {
    [void]$sb.AppendFormat("{0} {1}`n", $_.Hash.ToLower(), (Resolve-Path $_.Path -Relative))
}
# trim off the final "`n"
$sb.Remove($sb.Length -1, 1)

Set-Content -Path 'D:\checksums.txt' -Value $sb.ToString() -NoNewline -Encoding Ascii -Force
Theo
  • 57,719
  • 8
  • 24
  • 41