【问题标题】:Recreating a linux md5 checksum on Windows在 Windows 上重新创建 linux md5 校验和
【发布时间】:2021-11-09 20:26:59
【问题描述】:

我正在我们的 linux 机器上执行一些非常简单的校验和,但我现在需要为我们的 Windows 用户重新创建类似的东西。为了给我一个校验和,我只运行:

md5sum *.txt | awk '{ print $1 }' | md5sum

我正在努力在 Windows 中使用批处理文件或 Powershell 重新创建它。我得到的最接近的是:

Get-ChildItem $path -Filter *.txt | 
Foreach-Object {
   $hash =  Get-FileHash -Algorithm MD5 -Path ($path + "\" + $_) | Select -ExpandProperty "Hash"
   $hash = $hash.tolower()  #Get-FileHash returns checksums in uppercase, linux in lower case (!)
   Write-host $hash
}

这会将每个文件的校验和结果打印到控制台,就像 linux 命令一样,但是通过管道将其返回到 Get-FileHash 以获得与 linux 等效项匹配的单个输出,这让我望而却步。写入文件让我陷入了回车差异

作为字符串流回 Get-FileHash 不会返回相同的校验和:

$String = Get-FileHash -Algorithm MD5 -Path (Get-ChildItem -path $files -Recurse) | Select -ExpandProperty "Hash"
$stringAsStream = [System.IO.MemoryStream]::new()
$writer = [System.IO.StreamWriter]::new($stringAsStream)
$writer.write($stringAsStream)
Get-FileHash -Algorithm MD5 -InputStream $stringAsStream

我是否过度设计了这个?我相信这不应该这么复杂! TIA

【问题讨论】:

  • Get-FileHash -Algorithm MD5 -Path ($_.FullName)
  • 感谢您的回复。除非我误解了,否则它将返回单个文件的校验和。这是我正在努力解决的“校验和的校验和”。谢谢。

标签: powershell md5sum get-filehash


【解决方案1】:

魔鬼在细节中:

  • (已知)Get-FileHash 以大写形式返回校验和,而 Linux md5sum 以小写形式返回 (!);
  • FileSystem 提供程序的过滤器 *.txt 在 PowerShell 中不区分大小写,而在 Linux 中则取决于选项 nocaseglob如果设置 (shopt -s nocaseglob),则 Bash 在执行文件名扩展时以不区分大小写的方式匹配文件名。否则 (shopt -u nocaseglob),文件名匹配区分大小写;
  • 顺序:Get-ChildItem 输出按照 Unicode collation algorithm 排序,而在 Linux 中 *.txt 过滤器按照 LC_COLLATE 类别的顺序展开(在我的系统上为 LC_COLLATE="C.UTF-8")。

在以下(部分注释)脚本中,三个# Test 块演示了我对最终解决方案的调试步骤:

Function Get-StringHash {
    [OutputType([System.String])]
    param(
        # named or positional: a string
        [Parameter(Position=0)]
        [string]$InputObject
    )
    $stringAsStream = [System.IO.MemoryStream]::new()
    $writer = [System.IO.StreamWriter]::new($stringAsStream)
    $writer.write( $InputObject)
    $writer.Flush()
    $stringAsStream.Position = 0
    Get-FileHash -Algorithm MD5 -InputStream $stringAsStream |
        Select-Object -ExpandProperty Hash
    $writer.Close()
    $writer.Dispose()
    $stringAsStream.Close()
    $stringAsStream.Dispose()
}

function ConvertTo-Utf8String {
    [OutputType([System.String])]
    param(
        # named or positional: a string
        [Parameter(Position=0, Mandatory = $false)]
        [string]$InputObject = ''
    )
    begin {
        $InChars  = [char[]]$InputObject
        $InChLen  = $InChars.Count
        $AuxU_8 = [System.Collections.ArrayList]::new()
    }
    process {
        for ($ii= 0; $ii -lt $InChLen; $ii++) {
            if ( [char]::IsHighSurrogate( $InChars[$ii]) -and
                    ( 1 + $ii) -lt  $InChLen             -and
                    [char]::IsLowSurrogate( $InChars[1 + $ii]) ) {
                $s = [char]::ConvertFromUtf32(
                     [char]::ConvertToUtf32( $InChars[$ii], $InChars[1 + $ii]))
                $ii ++
            } else {
                $s = $InChars[$ii]
            }
            [void]$AuxU_8.Add( 
                ([System.Text.UTF32Encoding]::UTF8.GetBytes($s) | 
                    ForEach-Object { '{0:X2}' -f $_}) -join ''
            )
        }
    }
    end { $AuxU_8 -join '' }
}

# Set variables
$hashUbuntu = '5d944e44149fece685d3eb71fb94e71b'
$hashUbuntu   <# copied from 'Ubuntu 20.04 LTS' in Wsl2:
              cd `wslpath -a 'D:\\bat'`
              md5sum *.txt | awk '{ print $1 }' | md5sum | awk '{ print $1 }'
              <##>
$LF = [char]0x0A   # Line Feed (LF)
$path = 'D:\Bat'   # testing directory


$filenames = 'D:\bat\md5sum_Ubuntu_awk.lst'
<# obtained from 'Ubuntu 20.04 LTS' in Wsl2:
    cd `wslpath -a 'D:\\bat'`
    md5sum *.txt | awk '{ print $1 }' > md5sum_Ubuntu_awk.lst
    md5sum md5sum_Ubuntu_awk.lst | awk '{ print $1 }' # for reference
<##>

# Test #1: is `Get-FileHash` the same (beyond character case)?
$hashFile = Get-FileHash -Algorithm MD5 -Path $filenames |
                Select-Object -ExpandProperty Hash
$hashFile.ToLower() -ceq $hashUbuntu

# Test #2: is `$stringToHash` well-defined? is `Get-StringHash` the same?
$hashArray = Get-Content $filenames -Encoding UTF8
$stringToHash = ($hashArray -join $LF) + $LF
(Get-StringHash -InputObject $stringToHash) -eq $hashUbuntu 

# Test #3: another check: is `Get-StringHash` the same?
Push-Location -Path $path
$filesInBashOrder = bash.exe -c "ls -1 *.txt"
$hashArray = $filesInBashOrder |
    Foreach-Object {
        $hash = Get-FileHash -Algorithm MD5 -Path (
                        Join-Path -Path $path -ChildPath $_) |
                    Select-Object -ExpandProperty "Hash"
        $hash.tolower()
    }
$stringToHash = ($hashArray -join $LF) + $LF
(Get-StringHash -InputObject $stringToHash) -eq $hashUbuntu
Pop-Location

# Solution - ordinal order assuming `LC_COLLATE="C.UTF-8"` in Linux
Push-Location -Path $path
$hashArray = Get-ChildItem -Filter *.txt -Force -ErrorAction SilentlyContinue |
    Where-Object {$_.Name -clike "*.txt"} | # only if `shopt -u nocaseglob`
    Sort-Object -Property { (ConvertTo-Utf8String -InputObject $_.Name) } |
    Get-FileHash -Algorithm MD5 |
        Select-Object -ExpandProperty "Hash" |
    Foreach-Object {
        $_.ToLower()
    }
$stringToHash = ($hashArray -join $LF) + $LF
(Get-StringHash -InputObject $stringToHash).ToLower() -ceq $hashUbuntu
Pop-Location

输出(在 278 个文件上测试):.\SO\69181414.ps1

5d944e44149fece685d3eb71fb94e71b
True
True
True
True

【讨论】:

    【解决方案2】:

    您需要在从Get-FileHash 返回的对象上引用.Hash 属性。如果您想要与md5hash 类似的视图,您也可以使用Select-Object 来策划:

    # Get filehashes in $path with similar output to md5sum
    $fileHashes = Get-ChildItem $path -File | Get-FileHash -Algorithm MD5
    
    # Once you have the hashes, you can reference the properties as follows
    # .Algorithm is the hashing algo
    # .Hash is the actual file hash
    # .Path is the full path to the file
    foreach( $hash in $fileHashes ){
      "$($hash.Algorithm):$($hash.Hash) ($($hash.Path))"
    }
    

    对于$path 中的每个文件,上述foreach 循环将产生类似于以下内容的行:

    MD5:B4976887F256A26B59A9D97656BF2078 (C:\Users\username\dl\installer.msi)
    

    算法、哈希和文件名显然会根据您选择的哈希算法和文件系统而有所不同。

    【讨论】:

      猜你喜欢
      • 2021-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多