为什么此字符串不在 PowerShell 中序列化为简单的 JSON 字符串 [英] Why doesn't this string serialize to a simple JSON string in PowerShell

查看:66
本文介绍了为什么此字符串不在 PowerShell 中序列化为简单的 JSON 字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

见下文,$a$s 都是包含文本 String" 的字符串,但每个字符串都使用 ConvertTo-JSON 进行不同的序列化.

See below both $a and $s are strings containing the text "String" but each serializes differently with ConvertTo-JSON.

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

Why won't $s | ConvertToJson produce "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"
}

背景故事

$s 是使用 Get-Help 检查的 .ps1parameterValue:

Back-Story

$s is the parameterValue of a .ps1 inspected with 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

dosdir.ps1:

param(
    [String]$Path
)
CMD /C "DIR /B $Path"

推荐答案

PowerShell 的 ETS(扩展类型系统) 允许您使用附加属性(只能由 PowerShell 代码直接访问)来修饰任何对象.

PowerShell's ETS (Extended Type System) allows you to decorate any object with additional properties (that are directly accessible only to PowerShell code).

如果你使用 [string] 实例(无论是你自己做还是其他命令为你做的[1]),这些额外的属性就会出现当对象使用 ConvertTo-Json 序列化时:

If you do so with a [string] instance (whether you do it yourself or another command does it for you[1]), these additional properties will surface when the object is serialized with 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

以上产生:

hi
---
{
  "value": "hi",
  "foo": "bar"
}

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

This GitHub issue discusses this surprising behavior.

解决方法:

# .psobject.BaseObject returns the underlying, undecorated object.
PS> $decoratedString.psobject.BaseObject | ConvertTo-Json
hi


[1] 正如 js2010 指出的那样,数据检索 PowerShellprovider cmdlets - Get-ChildItem, Get-Item, Get-Content, ... - 都添加了固定数量的NoteProperty 成员为它们输出的对象,即PSPathPSParentPathPSChildNamePSDrive>, PSProvider.


[1] As js2010 points out, the data-retrieving PowerShell provider cmdlets - Get-ChildItem, Get-Item, Get-Content, ... - all add a fixed number of NoteProperty members to the objects they output, namely PSPath, PSParentPath, PSChildName, PSDrive, PSProvider.

因此,如果您对使用 Get-Content 获得的字符串进行序列化,则会遇到上面详述的相同问题:

Therefore, you'll run into the same problem detailed above if you serialize a string that was obtained with 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",
...

请注意,在字符串的情况下,这些额外的属性在构造 new 字符串时丢失,通过字符串连接或应用字符串运算符(例如 <代码>-替换:

Note that in the case of a string these extra properties are lost when a new string is constructed, either by string concatenation or by applying a string operator such as -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

另请注意,这种每个输出对象的装饰增加了相当多的内存和性能开销;对于 Get-ContentGitHub issue #7537 建议提供选择退出.

Also note that this per-output-object decorating adds quite a bit of memory and performance overhead; for Get-Content, GitHub issue #7537 suggests offering an opt-out.

这篇关于为什么此字符串不在 PowerShell 中序列化为简单的 JSON 字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆