在PowerShell中将十六进制字符串转换为Base64

3

我正在尝试在PowerShell中复制以下Python代码段的功能:

allowed_mac_separators = [':', '-', '.']
for sep in allowed_mac_separators:
    if sep in mac_address:
        test = codecs.decode(mac_address.replace(sep, ''), 'hex')
        b64_mac_address = codecs.encode(test, 'base64')
        address = codecs.decode(b64_mac_address, 'utf-8').rstrip()

它接受一个MAC地址,去掉分隔符,将其转换为十六进制,然后转换为base64。(我没有编写Python函数,对它或其工作方式没有任何控制。)
例如,MAC地址AA:BB:CC:DD:E2:00将被转换为AABBCCDDE200,然后转换为b'\xaa\xbb\xcc\xdd\xe2\x00',最后输出b'qrvM3eIA'。我尝试了类似以下的操作:
$bytes = 'AABBCCDDE200' | Format-Hex
[System.BitConverter]::ToString($bytes);

但是这会产生一个“MethodException:找不到重载为'ToString'且参数计数为'1'的方法。”我不太确定它在寻找什么。我找到的所有使用该调用的示例都只有一个参数。这个可以工作:

[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('AABBCCDDE200'))

但显然它没有先转换为十六进制,因此得出了不正确的结果。非常感谢您的帮助。

使用$bytes.Bytes方法怎么样? 例如运行:[System.Convert]::ToBase64String($bytes.Bytes) - undefined
1
MAC地址已经是十六进制的了。这个Python脚本看起来像是将MAC地址从十六进制解码为UTF8,然后将字节编码为Base64,就像你在PowerShell中使用[System.Convert]代码一样。 - undefined
此外,使用$bytes.Bytes将修复您所见到的错误,但它等同于UTF8.GetBytes方法。 - undefined
很高兴了解到.Bytes,@Cpt.Whale;请注意,在Windows PowerShell中,它是有损的ASCII.GetBytes方法。 虽然在这种情况下这个区别并不重要,但请注意,在这种情况下使用.Bytes是行不通的,因为你实际上会得到反映字符(如A)的ASCII码值的字节值,而需要的是将这些字符解释为十六进制数字。 - undefined
1个回答

9
# Remove everything except word characters from the string.
# In effect, this removes any punctuation ('-', ':', '.')
$sanitizedHexStr = 'AA:BB:CC:DD:E2:00' -replace '\W'

# Convert all hex-digit pairs in the string to an array of bytes.
$bytes = [byte[]] -split ($sanitizedHexStr -replace '..', '0x$& ')

# Get the Base64 encoding of the byte array.
[System.Convert]::ToBase64String($bytes)

关于用来创建$bytes数组的技术解释,以及一个简单的PowerShell(Core) 7.1+/.NET 5+替代方法 (简而言之: [System.Convert]::FromHexString('AABBCCDDE200')),请参见这个答案


至于你所尝试的:

Format-Hex并没有直接返回字节数组,它的主要目的是为了将输入数据以十六进制格式可视化展示给人类观察者

通常情况下,Format-*命令产生的对象唯一的目的就是向PowerShell的输出格式系统提供格式指令。有关详细信息,请参阅这个答案。简而言之,只能使用Format-*命令将数据格式化用于显示,而不能用于后续的程序处理

话虽如此,在Format-Hex这个特定的情况中,输出的对象类型为[Microsoft.PowerShell.Commands.ByteCollection]确实包含有用的数据,并且也包含了.Bytes属性的输入字符串的转码字符的字节,就像Cpt.Whale指出的那样。

但是,$bytes = ($sanitizedHexStr | Format-Hex).Bytes在你的情况下将不会起作用,因为你最终将获得反映诸如A之类字符的ASCII码点的字节值 - 而你需要的是将这些字符解释为十六进制数字

但即使在一般情况下,我建议不要依赖Format-Hex进行转换为字节数组的操作:

  • 在哲学层面上,正如所述,Format-* 命令旨在生成用于显示的输出,而不是数据,并且值得注意这种区别,尽管有例外 - 输出对象的类型可以被认为是实现细节。

  • Format-Hex 根据首先应用固定字符转码将字符串转换为字节(例如,无法直接使用 UTF-16 代码单元获取 .NET 字符串的字节表示形式),而该固定转码在 Windows PowerShellPowerShell (Core) 之间存在差异:

    • 在 Windows PowerShell 中,.NET 字符串被转换为 ASCII(!),导致非 ASCII 范围字符的丢失 - 它们被转码为字面量 ?

    • 在 PowerShell (Core) 中,通过转码为 UTF-8 避免了这个问题。


System.BitConverter.ToString 失败了,因为你代码中的 $bytes 不是一个字节数组([byte[]]),它只是其 .Bytes 属性值(但未包含感兴趣的值)。

话虽如此,你不是要将字节重新转换为 字符串,而是要直接将字节转换为 Base64 编码,如上所示。


1
好知道。我绝对觉得这应该是标准的,所以我很高兴他们更新了API来支持它。PS Core 明显是未来。再次感谢你的回答。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接