首页 > 解决方案 > Powershell - 使用 INVOKE-RESTMETHOD 通过多层 JSON 输出进行枚举

问题描述

我正在尝试从其他 API 的一些多层 JSON 输出中返回某个值,并且似乎无法正确使用返回的输出,尤其是当您不知道该输出中可能包含什么时(我拥有的大多数示例看到这个假设你已经知道返回的字段并且可以硬编码它们,但在这种情况下不是)。

有问题的 API 是 F5 Local Traffic Manager Rest API...

返回的 JSON 如下所示。我希望从中获得serverside.curConns的价值......

{
      "generation": 263285,
      "kind": "tm:ltm:pool:members:membersstats",
      "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Production~Frontend_App_pool/members/~Production~PROD_SERVER01:8080/stats?ver=12.1.3",
      "entries": {
        "https://localhost/mgmt/tm/ltm/pool/~Production~Frontend_App_pool/members/~Production~PROD_SERVER01:8080/~Production~PROD_SERVER01:8080/stats": {
          "nestedStats": {
            "kind": "tm:ltm:pool:members:membersstats",
            "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Production~Frontend_App_pool/members/~Production~PROD_SERVER01:8080/~Production~PROD_SERVER01:8080/stats?ver=12.1.3",
            "entries": {
              "serverside.curConns": {
                "value": 0
              }
          }
        }
      }
    }
    }

我的问题是,上面的第一个“条目”容器会在我运行它的每台服务器上发生变化,这就是我试图编写的代码,但到目前为止还没有成功。

我的 Powershell 脚本目前看起来像这样......

$f5partition = "Production"
# ======= CHANGE PER ENVIRONMENT ==========
$f5poolname = "Frontend_App_pool"
$f5port = 8080
$user = "myf5userid"
$pass = "myf5password"
$f5server = "myf5server.mydomain.local"
# ======= NO CHANGES BELOW THIS LINE! =======
$servername = $env:COMPUTERNAME
# ====== AUTHORISATION SECTION ==========
$pair = "$($user):$($pass)"
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair))
$basicAuthValue = "Basic $encodedCreds"
$Headers = @{
    Authorization = $basicAuthValue
}
#=== CONNECT TO F5 API =========
$reply = Invoke-RestMethod -Uri https://${f5server}/mgmt/tm/ltm/pool/~${f5partition}~${f5poolname}/members/~${f5partition}~${servername}:${f5port}/stats/?$select=serverside.curConns -Headers $Headers

当我第一次运行它时,有可能(使用 Powershell 的 ISE)对 $reply 的结果进行制表符,所以我最终得到了预期的 0 值......

Write-Host $reply.entries.'https://localhost/mgmt/tm/ltm/pool/~Production~Frontend-App_pool/members/~Production~PROD_SERVER01:8080/~Production~PROD_SERVER01:8080/stats'.nestedStats.entries.'serverside.curConns'.value

这很棒。但是对于服务器 PROD_SERVER01。例如,我无法保存该脚本并针对 PROD_SERVER02 运行它,因为它现在已硬编码在脚本中。

我真正需要的是 $reply.entries.*.nestedStats.entries.'serverside.curConns'.value 之类的东西,或者我可以通过某种方式询问和解决返回的 JSON 值,这些值不是以任何方式预先确定的。

在这方面收到任何帮助,谢谢

我正在尝试编写一个没有需要复制到其他服务器才能运行的包或工具的脚本,例如模块或其他 .exe。而这个 Invoke-RestMethod 几乎是在做我想做的事,但是当它使用一个不期望的字段时,我正在努力枚举输出。

谢谢

标签: powershell

解决方案


在这种情况下,您可以将 JSON 转换为 XML 并使用 XPath 来获取您需要的内容。测试和工作:

# question's original JSON sample above
$json = ConvertFrom-Json $s;

# change -depth to suit your needs
$xml = ConvertTo-Xml -NoTypeInformation $json -Depth 10;
# if you want to take a look at JSON => XML.
# pretty-print only works in PowerShell console, not ISE
$xml.Save([Console]::Out);

# 0, what you're looking for....
$wanted = $xml.DocumentElement.SelectSingleNode(
              '//Property[@Name="serverside.curConns"]'
          ).FirstChild.InnerText;

恕我直言,使用 PowerShell 解析 JSON 是痛苦的/严重缺乏 - 应该有内置的支持来解析嵌套的 JSON 对象。


推荐阅读