【问题标题】:Convert PSObjects (or PS Command) to JSON in C#在 C# 中将 PSObject(或 PS 命令)转换为 JSON
【发布时间】:2015-11-10 16:41:12
【问题描述】:

我正在尝试创建一个 Web API,它将 PowerShell 命令的输出转换为 JSON。是否有可以执行此操作或将 PSObject 转换为 JSON 的库?

PSObject 属性根据生成它的命令而变化。我尝试将 PSObject 传递给“ConvertTo-Json”,但我得到了额外的对象信息。

PowerShell 命令:

Get-Process | Select -Property Handles,ProcessName | ConvertTo-Json

JsonConvert.SerializeObject()之后的输出:

"{\"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.String</T>\\r\\n      <T>System.Object</T>\\r\\n    </TN>\\r\\n    <ToString>[_x000D__x000A_    {_x000D__x000A_\\\"Handles\\\":163,_x000D__x000A_\\\"ProcessName\\\":\\\"AppleMobileDeviceService\\\"_x000D__x000A_},_x000D__x000A_    {_x000D__x000A_\\\"Handles\\\":  972,_x000D__x000A_\\\"ProcessName\\\":\\\"CcmExec\\\"_x000D__x000A_},_x000D__x000A_{_x000D__x000A_\\\"Handles\\\":  1838,_x000D__x000A_\\\"ProcessName\\\":\\\"ccSvcHst\\\"_x000D__x000A_}"

用于 BeginInvoke 的 PowerShell 命令。

PowerShell 命令:

Get-Process | Select -Property Handles,ProcessName

JsonConvert.SerializeObject(PSObj)之后的输出:

"[{\"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>Selected.System.Diagnostics.Process</T>\\r\\n      <T>System.Management.Automation.PSCustomObject</T>\\r\\n      <T>System.Object</T>\\r\\n    </TN>\\r\\n    <ToString>@{Handles=163; ProcessName=AppleMobileDeviceService}</ToString>\\r\\n    <Obj RefId=\\\"1\\\">\\r\\n      <TNRef RefId=\\\"0\\\" />\\r\\n      <MS>\\r\\n        <I32 N=\\\"Handles\\\">163</I32>\\r\\n        <S N=\\\"ProcessName\\\">AppleMobileDeviceService</S></Objs>\"}}]

【问题讨论】:

  • ConvertTo-JSON 听起来正是您所追求的......额外的属性是什么?如果要删除属性,可以使用 select-object 在转换为 json 之前仅指定要使用的属性。
  • 那没有用数据更新帖子。
  • Convert-Json 在我看来不是一个好的解决方案,因为它将枚举转换为它们的序数值。看到这个答案stackoverflow.com/questions/44494409/…

标签: c# json powershell


【解决方案1】:

如果您可以使用第三方库,那么JSON.NET 具有JsonConvert 类。使用起来相当简单:JsonConvert.SerializeObject(myObj) 将返回一个包含 JSON 的字符串。

我发现这比尝试从 C# 代码以编程方式调用 PowerShell 要容易一些。

如果您想省略额外的属性,那么 JsonConvert 允许您实现 IContractResolver 来指定您想要的属性。

它最终看起来像这样:

JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new MyContractResolver() });

ContractResolver 看起来像这样:

public class MyContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        properties = properties.Where(p => p.PropertyName != "OmittedProperty").ToList();
        return properties;
    }
}

当然,您可以为属性设置任何您喜欢的条件。

【讨论】:

  • 请记住,在 Visual Studio 中检查字符串时,它会添加前导引号和尾随引号,以及转义引号和反斜杠。所以 " 和 \ 将分别显示为 \" 和 \\。这是您在输出中注意到的问题吗?
  • 我会检查您发布的代码。谢谢你帮忙。这不仅仅是在 VS 中。我将数据输出到控制台窗口,然后还将数据输出到网络浏览器并看到了同样的问题。
  • 你有没有设法解决这个问题?我一直遇到同样的问题。原因在于始终将 PSObject 的属性序列化为 CliXML 的 PSObject 的序列化程序。我尝试枚举属性(同时将它们添加到集合中)取得了一些成功,但是当您调用尝试从对象读取属性时,某些 cmdlet(例如 get-childitem 和 get-command)会引发 runspaceexception。
  • 请注意,“ConvertTo-Json”不是一个独立的模块。它是 Powershell 的一部分。将其分解为一个单独的库是一个悬而未决的问题。见:github.com/PowerShell/PowerShell/issues/3995
【解决方案2】:

对于仍在寻找解决方案的任何人,都可以使用 Powershell 的内置 JSON 转换器 (ConvertTo-Json):

using System;
using System.Management.Automation;
using Microsoft.PowerShell.Commands;
using System.Collections.ObjectModel;

namespace PowerJson
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create the Powershell instance, and adds command to be executed
            PowerShell ps = PowerShell.Create();
            ps.AddCommand("Get-Process");
            Collection<PSObject> _ps_results = ps.Invoke();

            // Create a JSON Context Object
            JsonObject.ConvertToJsonContext _json_context = new JsonObject.ConvertToJsonContext(maxDepth: 12, enumsAsStrings: false, compressOutput: false);

            // Converts the PSObject into JSON
            string json_result = JsonObject.ConvertToJson(_ps_results, _json_context);

            // Outputs the result to console
            Console.WriteLine(json_result);
        }
    }
}

【讨论】:

    【解决方案3】:

    这对我有用。试试看。

    if (item.TypeNames.FirstOrDefault() == "System.String")
    {
        return item.BaseObject.ToString();
    }
    else
    {
        var settings = new Newtonsoft.Json.JsonSerializerSettings
            { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
    
        var dict = new Dictionary<string, object>();
        var objMembers = typeof(object).GetMembers();
        var ignoreMembers = new List<string>();
    
        ignoreMembers.AddRange(
            item.Members.Where(
                i => i.TypeNameOfValue.StartsWith("Deserialized.")).Select(i => i.Name).ToList());
    
        ignoreMembers.AddRange(objMembers.Select(i => i.Name));
    
        var filteredMembers =
            item.Members.Where(
                i => ignoreMembers.All(
                    ig => ig.ToLower() != i.Name.ToLower())).ToList();
    
        foreach (var mem in filteredMembers)
        {
            if (!dict.ContainsKey(mem.Name))
            {
                dict.Add(mem.Name, "");
            }
            dict[mem.Name] = mem.Value;
        }
    
        try
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(dict, settings);
        }
        catch (Exception e)
        {
        }
    }
    return null;
    

    【讨论】:

    • 这是一个代码 sn-p。它应该在什么情况下工作?
    • 抱歉,错过了这条评论。它接受项目,这是从 powershell 进程返回的项目。然后遍历那些以序列化对 json 的响应。从那以后,我对这段代码进行了一些改进,但它仍然可以达到目的。
    猜你喜欢
    • 1970-01-01
    • 2011-03-15
    • 2020-06-10
    • 2021-06-26
    • 2013-08-06
    • 2016-02-03
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    相关资源
    最近更新 更多