O que é a propriedade ParameterizedProperty Chars no tipo de string adicionado pelo Powershell?
Por favor, observe:
C:\> ''|Get-Member |? { $_.MemberType -eq 'ParameterizedProperty' }
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Chars ParameterizedProperty char Chars(int index) {get;}
C:\>
Esta é uma propriedade muito estranha. Em primeiro lugar, é adicionado pelo Powershell, a seguir contém uma propriedade recursiva infinita:
C:\> ''.Chars
IsSettable : False
IsGettable : True
OverloadDefinitions : {char Chars(int index) {get;}}
TypeNameOfValue : System.Char
MemberType : ParameterizedProperty
Value : char Chars(int index) {get;}
Name : Chars
IsInstance : True
C:\> ''.Chars.Value
IsSettable : False
IsGettable : True
OverloadDefinitions : {char Chars(int index) {get;}}
TypeNameOfValue : System.Char
MemberType : ParameterizedProperty
Value : char Chars(int index) {get;}
Name : Chars
IsInstance : True
C:\> ''.Chars.GetHashCode()
56544304
C:\> ''.Chars.Value.GetHashCode()
34626228
C:\> ''.Chars.Value.Value.GetHashCode()
3756075
C:\> ''.Chars.Value.Value.Value.GetHashCode()
49108342
C:\> ''.Chars.Value.Value.Value.Value.GetHashCode()
62340979
C:\> ''.Chars.Value.Value.Value.Value.Value.GetHashCode()
24678148
C:\>
O código hash é diferente a cada vez, portanto, deve ser gerado dinamicamente.
Por que eu me importo? Estou tentando usar um módulo Newtonsoft.Json PowerShell de PSGallery e ele bloqueia com essa propriedade, mas apenas quando executado no Desktop PowerShell (5.1), não no Core (7.0.3). O problema é que não tenho uma reprodução mínima, o objeto de entrada é bastante grande. O erro que recebo é:
ConvertTo-JsonNewtonsoft : Exception calling "SerializeObject" with "2" argument(s): "Self referencing loop detected for property 'Value' with type 'System.Management.Automation.PSParameterizedProperty'. Path 'environments[4].conditions.name.Chars'."
Esse problema não existe no PS Core.
Alguém pode me explicar o que é essa propriedade, por que precisamos dela e como podemos nos livrar dela?
EDITAR 1
Acho que é um problema com o Newtonsoft.Jsonmódulo. Observar:
[DBG]> [pscustomobject]@{ a = 1} | ConvertTo-Json
{
"a": 1
}
[DBG]> [pscustomobject]@{ a = 1} | ConvertTo-JsonNewtonsoft
{
"CliXml": "<Objs Version=\"1.1.0.1\" xmlns=\"http://schemas.microsoft.com/powershell/2004/04\">\r\n <Obj RefId=\"0\">\r\n <TN RefId=\"0\">\r\n
<T>System.Management.Automation.PSCustomObject</T>\r\n <T>System.Object</T>\r\n </TN>\r\n <ToString>@{a=1}</ToString>\r\n <Obj RefId=\"1\">\r\n <TNRef RefId=\"0\" />\r\n <MS>\r\n <I32 N=\"a\">1</I32>\r\n </MS>\r\n </Obj>\r\n <MS>\r\n <I32 N=\"a\">1</I32>\r\n </MS>\r\n </Obj>\r\n</Objs>"
}
[DBG]>
Ele é incapaz de interpretar objetos PowerShell adequadamente. Torna inutilizável.
Respostas
tl; dr
Seu verdadeiro problema é que nem a Newtonsoft.Jsonbiblioteca nem o módulo de wrapper do PowerShell suportam [pscustomobject]instâncias :
A biblioteca pede que as [pscustomobject]instâncias se serializem , com base em [pscustomobject]( [psobject]) que implementa a ISerializableinterface.
No Windows PowerShell, isso falha completamente, provavelmente devido ao fato de a versão agrupada do
Newtonsoft.Json.dllassembly ser muito antiga (no momento em que este texto foi escrito, a versão agrupada é8.0, embora12.0seja a atual) e ter um bug- A manifestação desse bug é o
Self referencing loop detected for property 'Value' ...bug que você viu.
- A manifestação desse bug é o
No PowerShell [Core] v6 +, a versão mais recente
Newtonsoft.Json.dllque vem com o PowerShell se antecipa à versão obsoleta, portanto, o erro não ocorre, mas o problema de serialização se torna óbvio:O
{ "CliXml": "<Objs Version=\"1.1.0.1\" .. }texto JSON resultante mostra que a[pscustomobject]instância foi serializada no formato CLIXML, o formato de serialização baseado em XML nativo do PowerShell, usado principalmente pelo recurso remoto do PowerShell.É hipoteticamente possível - embora muito complicado - desserializar manualmente tal JSON, pós-processando-o e substituindo objetos com apenas uma
CliXmlpropriedade com o valor de retorno de[System.Management.Automation.PSSerializer]::Deserialize()
Soluções :
Se sua intenção é simplesmente comparar representações serializadas em uma forma agnóstica de edição PS, independentemente do formato de serialização específico , considere o uso de CLIXML diretamente, via
Export-CliXmleImport-CliXml.Se você deseja uma forma agnóstica de edição PS para serializar para JSON , você terá que lançar seu próprio
[pscustomobject]conversor de hashtable -to-encomendado, porque serializar hashtables ordenados ([ordered] @{ ... }, System.Collections.Specialized.OrderedDictionary) via Newtonsoft.Json faz o round-trip corretamente no PowerShell (é, na verdade, a estrutura de dados usada pelosConvertFrom/To-JsonNewtonsoftcmdlets do wrapper).
Ambas as abordagens são demonstradas nesta resposta relacionada .