PowerShell中两次生成的JSON内容为何存在差异?
这问题我之前帮朋友排查过,核心原因主要有两个——Byte[]类型的序列化/反序列化行为差异,以及PowerShell对哈希表与PSCustomObject的有序性处理不同,咱们逐个说清楚:
1. Byte[]类型在JSON序列化链中的类型丢失
JSON本身没有原生的字节数组类型,所以当你第一次把包含Byte[]的哈希表$List1转成JSON时,PowerShell的ConvertTo-Json会自动把Byte[]序列化为Base64编码的字符串。
但当你用ConvertFrom-Json把JSON读成PSCustomObject时,这个Base64字符串并不会自动转回Byte[]——它会被保留为普通的System.String类型。后续你把这个PSCustomObject转成新的哈希表$List2时,存进去的其实是字符串,而不是原来的Byte[]。
虽然最终两次JSON里的字符串内容看起来可能一样,但如果后续你要把JSON转回Byte[],第二次生成的JSON就需要手动做Base64解码,而第一次的JSON如果是从原始Byte[]生成的,反序列化时(做对应处理)可以直接转回Byte[]——这本质是类型信息丢失导致的隐性差异。
2. 哈希表与PSCustomObject的有序性差异
在PowerShell 5.1及更早版本中,普通哈希表(Hashtable)是无序的,而PSCustomObject的属性是严格保持JSON序列化时的顺序的。
当你把$List1(普通哈希表)转成JSON时,键的顺序是哈希表内部存储的随机顺序;而当你把JSON反序列化为PSCustomObject后,再把它转成新的哈希表$List2,$List2的键顺序可能和$List1完全不同。最后$List2转成JSON时,键的顺序就会和第一次的JSON不一样,这就导致了肉眼可见的内容差异。
验证与修复方法
- 验证类型问题:执行下面的命令,就能看到明确的类型差异:
# 查看原始Byte[]的类型 $List1.YourByteKey.GetType().FullName # 查看反序列化后的类型 $tempHash.YourByteKey.GetType().FullName - 修复类型丢失:在反序列化后手动把Base64字符串转回
Byte[],再生成新哈希表:# 把PSCustomObject里的Base64字符串转回Byte[] $tempHash.YourByteKey = [Convert]::FromBase64String($tempHash.YourByteKey) # 创建新的哈希表 $List2 = @{ YourByteKey = $tempHash.YourByteKey } - 修复顺序差异:如果需要保持键的顺序,创建哈希表时改用有序哈希表(
[ordered]@{}):# 用有序哈希表创建$List1 $List1 = [ordered]@{ Key1 = $byteArr1; Key2 = $byteArr2 } # 转成PSCustomObject后,再用有序哈希表创建$List2 $List2 = [ordered]@{ Key1 = $tempHash.Key1 Key2 = $tempHash.Key2 }
内容的提问来源于stack exchange,提问作者thoudamchitaranjan

