【问题标题】:save powershell content in as JSON with empty value将 powershell 内容保存为 JSON 格式,值为空
【发布时间】:2020-04-14 15:14:28
【问题描述】:

我必须使用命令Get-NetFirewallRule 保存一些信息,并将它们保存在.JSON 文件中。我就是这样做的

Get-NetFirewallRule  |
select-object -Property Name,
DisplayName,
DisplayGroup,
@{Name='Protocol';Expression={($PSItem | Get-NetFirewallPortFilter).Protocol}},
@{Name='LocalPort';Expression={($PSItem | Get-NetFirewallPortFilter).LocalPort}},
@{Name='RemotePort';Expression={($PSItem | Get-NetFirewallPortFilter).RemotePort}},
@{Name='RemoteAddress';Expression={($PSItem | Get-NetFirewallAddressFilter).RemoteAddress}},
Enabled,
Profile,
Direction,
Action |
ConvertTo-Json | Out-File "C:\Users\Administrator\Desktop\firewall.txt"

输出文件是这个(这是文件的一小部分)

        "Name":  "Microsoft-Windows-PeerDist-WSD-Out",
        "DisplayName":  "BranchCache Peer Discovery (WSD-Out)",
        "DisplayGroup":  "BranchCache - Peer Discovery (Uses WSD)",
        "Protocol":  "UDP",
        "LocalPort":  "Any",
        "RemotePort":  "3702",
        "RemoteAddress":  "LocalSubnet",
        "Enabled":  2,
        "Profile":  0,
        "Direction":  2,
        "Action":  2
    },
    {
        "Name":  "Microsoft-Windows-PeerDist-HostedServer-In",
        "DisplayName":  "BranchCache Hosted Cache Server (HTTP-In)",
        "DisplayGroup":  "BranchCache - Hosted Cache Server (Uses HTTPS)",
        "Protocol":  "TCP",
        "LocalPort":  {
                          "value":  [
                                        "80",
                                        "443"
                                    ],
                          "Count":  2
                      },
        "RemotePort":  "Any",
        "RemoteAddress":  "Any",
        "Enabled":  2,
        "Profile":  0,
        "Direction":  1,
        "Action":  2
    }

如您所见,powershell 以两种不同的方式保存 LocalPort:第一种使用 1 值,第二种使用 2 值和 Count;在我的代码(C#)中,我写了这个来读取我的 JSON 文件

string file = File.ReadAllText(MainWindow.path + @"\..\..\misc\json\FirewallRules.json");
List<GetSetFRules> rulesList = JsonConvert.DeserializeObject<List<GetSetFRules>>(file);

但是有问题; GetSetFRules 类无法保存 JSON 的内容,因为每个规则的 JSON 格式都不相同

 class GetSetFRules
    {
        public string Name { get; set; }
        public string DisplayName { get; set; }
        public string DisplayGroup { get; set; }
        public string Protocol { get; set; }
        public Localport LocalPort { get; set; }
        public string RemotePort { get; set; }
        public string RemoteAddress { get; set; }
        public int Enabled { get; set; }
        public int Profile { get; set; }
        public int Direction { get; set; }
        public int Action { get; set; }
    }

    public class Localport
    {
        public string[] value { get; set; }
        public int Count { get; set; }
    }

所以,问题是,有没有办法像这样用空值保存每个规则?

[...]"LocalPort":  "Any",[...]

⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇

[...]"LocalPort":  {
                          "value":  [
                                        "Any",
                                    ],
                          "Count":  1
                      }[...]

或者这个

[...]"LocalPort":  {
                          "value":  [
                                        "",
                                    ],
                          "Count":  0
                      }[...]

【问题讨论】:

  • Teo230,我的建议是使用支持不同解析机制的 JSON 解析器,而不是(反)序列化。我会适当地使用支持JSONPath 的,比如JSON.NET。在这种情况下,您将完全控制如何构建加载了所需数据的实例。
  • 你能举个例子吗?
  • 是的,我认为(并希望)这可以帮助您:newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm

标签: c# json powershell


【解决方案1】:

您需要确保计算出的LocalPort 属性中($PSItem | Get-NetFirewallPortFilter).LocalPort 的输出是数组 类型的,您可以确保如下:

@{
  Name='LocalPort'
  Expression={ , [array] ($PSItem | Get-NetFirewallPortFilter).LocalPort }
}
  • Cast [array] 确保命令输出被视为一个数组,即使只输出一个 单个 值,例如 Any

  • 数组构造运算符, 的一元形式将生成的数组包装在辅助中。当脚本块的 ({ ... }) 输出分配给 Expression 哈希表条目时,防止 单个 元素数组解包的临时数组。

顺便说一句:正如 Theo 指出的 in his answer 以及优化,跨多个计算属性对同一输入对象调用 Get-NetFireWallPortFilter 多次 次,效率低下并且会减慢您的命令下来。


以上内容将始终如一地为您提供所需的 JSON 表示,但有一个警告

ConvertTo-Json 通过 object 为数组创建的 JSON 表示,包含带有数组元素的 value 属性和带有元素计数的 count 属性,应该被视为bug,因为数组应该简单地表示为 JSON 数组

也就是说,类似于:

, (80, 443) | ConvertTo-Json

应该屈服:

# OK: This is how it works in PowerShell v6+
[
  80,
  443
]

不是

# BUG in Windows PowerShell v5.1
{
    "value":  [
                  80,
                  443
              ],
    "Count":  2
}

This answer 讨论了详细信息,但请注意,在给定的 Windows PowerShell 会话中运行以下一次可用于解决问题:

# Run this once per session, before calling ConvertTo-Json, to 
# fix the JSON array serialization problem:
Remove-TypeData System.Array -ErrorAction Ignore

【讨论】:

    【解决方案2】:

    我想我找到了解决办法

    GetSetFRules 类替换为dynamic

    List<dynamic> rulesList = JsonConvert.DeserializeObject<List<dynamic>>(file);
    

    【讨论】:

    • 使用这种方法程序不会给你错误,但是在json文件中的输出是一样的
    • 我不确定你对 json 文件中的输出是什么意思。这是否意味着您仍然没有得到想要的输出?
    • 很高兴听到我的回答对你有用,@Teo230。鉴于此答案并不真正有效,请考虑修改或删除它,以及您的其他答案,实际上更多的是澄清而不是答案。
    【解决方案3】:

    在我的 Win10 机器上,使用您的 Powershell 代码还会显示 RemotePortProtocol 的数组输出。我认为最好不要尝试调整所有项目以具有那种输出,而是按原样列出所有规则对象,这样它们对于这些属性都有一个值。

    此外,您可以通过不多次执行 Get-NetFirewallPortFilter 来加快速度:

    # Retrieve every firewall rule object as single object.
    # All of these objects will have properties 'LocalPort', RemotePort, 'Protocol'
    # listed as single string values; not as array values in the output
    Get-NetFirewallRule | ForEach-Object {
        $portFilter = $_ | Get-NetFirewallPortFilter
        $_ | Select-Object -Property Name,
        DisplayName,
        DisplayGroup,
        @{Name='Protocol';Expression={$portFilter.Protocol}},
        @{Name='LocalPort';Expression={$portFilter.LocalPort}},
        @{Name='RemotePort';Expression={$portFilter.RemotePort}},
        @{Name='RemoteAddress';Expression={($_ | Get-NetFirewallAddressFilter).RemoteAddress}},
        Enabled,
        Profile,
        Direction,
        Action 
    } | Sort-Object DisplayName | ConvertTo-Json | Out-File "C:\Users\Administrator\Desktop\firewall.txt"
    

    部分输出:

    [
        {
            "Name":  "{56BC7333-582E-45E8-9249-F88002B598E9}",
            "DisplayName":  "Microsoft Management Console",
            "DisplayGroup":  null,
            "Protocol":  "TCP",
            "LocalPort":  "Any",
            "RemotePort":  "Any",
            "RemoteAddress":  "Any",
            "Enabled":  1,
            "Profile":  4,
            "Direction":  1,
            "Action":  4
        },
        {
            "Name":  "{C3F4E91A-65F5-4805-8F6B-86C6ECA5F4EE}",
            "DisplayName":  "Microsoft Management Console",
            "DisplayGroup":  null,
            "Protocol":  "UDP",
            "LocalPort":  "Any",
            "RemotePort":  "Any",
            "RemoteAddress":  "Any",
            "Enabled":  1,
            "Profile":  4,
            "Direction":  1,
            "Action":  4
        },
        {
            "Name":  "UDP Query User{A8997866-770C-417E-AE45-2436717836E8}C:\\windows\\system32\\mmc.exe",
            "DisplayName":  "Microsoft Management Console",
            "DisplayGroup":  null,
            "Protocol":  "UDP",
            "LocalPort":  "Any",
            "RemotePort":  "Any",
            "RemoteAddress":  "Any",
            "Enabled":  1,
            "Profile":  2,
            "Direction":  1,
            "Action":  2
        },
        {
            "Name":  "TCP Query User{C99F0EF2-8891-4B2D-B389-4A3F8B66638A}C:\\windows\\system32\\mmc.exe",
            "DisplayName":  "Microsoft Management Console",
            "DisplayGroup":  null,
            "Protocol":  "TCP",
            "LocalPort":  "Any",
            "RemotePort":  "Any",
            "RemoteAddress":  "Any",
            "Enabled":  1,
            "Profile":  2,
            "Direction":  1,
            "Action":  2
        }
    ]
    

    【讨论】:

    • @Teo230 是的,每个防火墙规则在结果数组中都是它自己的对象,因为ForEach-Object
    猜你喜欢
    • 1970-01-01
    • 2020-07-06
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 2018-03-14
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多