为什么在PowerShell中此字符串未序列化为简单的JSON字符串

Mar*_*arc 3 powershell json

两者均见下方$a$s是包含文本的字符串,"String"但每个字符串的转换方式与ConvertTo-JSON不同。

为什么不$s | ConvertToJson生产"String"??

PS W:\PowerShell\powowshell> $a="String"
PS W:\PowerShell\powowshell> $a
String
PS W:\PowerShell\powowshell> $a.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object


PS W:\PowerShell\powowshell> $a | ConvertTo-Json
"String"


PS W:\PowerShell\powowshell> $s
String
PS W:\PowerShell\powowshell> $s.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object


PS W:\PowerShell\powowshell> $s | ConvertTo-Json
{
    "value":  "String",
    "required":  "true"
}
Run Code Online (Sandbox Code Playgroud)

背景故事

$sparameterValue一个.ps1检查用Get-Help

PS W:\PowerShell\powowshell> $cmd = (get-help -full W:\PowerShell\powowshell\examples\components\dosdir.ps1).Syntax.syntaxItem[0].parameter
PS W:\PowerShell\powowshell> $cmd | convertto-json
{
    "description":  [
                        {
                            "Text":  "The path to the directory to be listed"
                        }
                    ],
    "parameterValue":  {
                           "value":  "String",
                           "required":  "true"
                       },
...
$s = $cmd.parameterValue
Run Code Online (Sandbox Code Playgroud)

dosdir.ps1

param(
    [String]$Path
)
CMD /C "DIR /B $Path"
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 5

使用PowerShell的ETS(扩展类型系统),您可以用其他属性(仅可通过PowerShell代码直接访问装饰任何对象。

如果您使用[string]实例来执行此操作(无论您自己执行还是通过其他命令为您执行此操作[1]),则在使用以下对象序列化对象时,这些附加属性将浮出水面ConvertTo-Json

# Add a .foo property with value 'bar' to a string.
$decoratedString = 'hi' | Add-Member -PassThru foo bar

# Output the string as-is.
# The added property does NOT show.
$decoratedString

'---'

# Serialize the string to JSON.
# The added property DOES show and the string's actual content
# is presented as pseudo-property .value
$decoratedString | ConvertTo-Json
Run Code Online (Sandbox Code Playgroud)

以上收益:

# Add a .foo property with value 'bar' to a string.
$decoratedString = 'hi' | Add-Member -PassThru foo bar

# Output the string as-is.
# The added property does NOT show.
$decoratedString

'---'

# Serialize the string to JSON.
# The added property DOES show and the string's actual content
# is presented as pseudo-property .value
$decoratedString | ConvertTo-Json
Run Code Online (Sandbox Code Playgroud)

这个GitHub问题讨论了这种令人惊讶的行为。

解决方法

# .psobject.BaseObject returns the underlying, undecorated object.
PS> $decoratedString.psobject.BaseObject | ConvertTo-Json
hi
Run Code Online (Sandbox Code Playgroud)

[1]作为js2010指出,数据检索的PowerShell提供者小命令 - ,,Get-ChildItem ,... -所有添加的固定数量的成员对象它们输出,即,,,,。Get-ItemGet-ContentNotePropertyPSPathPSParentPathPSChildNamePSDrivePSProvider

因此,如果序列化通过以下方式获得的字符串,则会遇到上述相同的问题Get-Content

PS> 'hi' > t.txt; Get-Content t.txt | ConvertTo-Json
{
  "value": "hi",
  "PSPath": "/Users/jdoe/t.txt",
  "PSParentPath": "/Users/jdoe",
  "PSChildName": "t.txt",
  "PSDrive": {
    "CurrentLocation": "Users/jdoe",
    "Name": "/",
    "Provider": {
      "ImplementingType": "Microsoft.PowerShell.Commands.FileSystemProvider",
      "HelpFile": "System.Management.Automation.dll-Help.xml",
      "Name": "FileSystem",
      "PSSnapIn": "Microsoft.PowerShell.Core",
...
Run Code Online (Sandbox Code Playgroud)

注意,在一个字符串这些额外性质的情况下丢失当一个新的或者通过字符串连接或通过施加一个字符串操作者例如字符串构成,-replace

# String concatenation
PS> 'hi' > t.txt; (Get-Content t.txt) + '!' | ConvertTo-Json
hi!

# Using -replace
PS> (Get-Content t.txt) -replace 'i', 'o' | ConvertTo-Json
ho
Run Code Online (Sandbox Code Playgroud)