Сценарий PowerShell 2.0 для извлечения данных json

#powershell #powershell-2.0

Вопрос:

ОБНОВЛЕНИЕ — Решение было очень простым с Powershell 5.1. Я опубликовал ответ отдельно»

Я пытаюсь создать свой первый сценарий Powershell (версия 2.0 в Windows 7). Я читаю следующий текст json из файла (эта часть работает). Я хочу получить значение «public_url». Ошибка, которую я получаю с помощью приведенного ниже сценария, заключается в следующем»

 Select-Object : Property "tunnels" cannot be found
 

Поскольку я впервые использую Powershell, я не совсем понимаю, как перемещаться по объектам. Заранее спасибо,

Содержимое моего файла json:

   {
     "tunnels":[
        {
           "name":"command_line",
           "uri":"/api/tunnels/command_line",
           "public_url":"tcp://8.tcp.ngrok.io:12716",
           "proto":"tcp",
           "config":{
              "addr":"localhost:32400",
              "inspect":false
           },
           "metrics":{
              "conns":{
                 "count":0,
                 "gauge":0,
                 "rate1":0,
                 "rate5":0,
                 "rate15":0,
                 "p50":0,
                 "p90":0,
                 "p95":0,
                 "p99":0
              },
              "http":{
                 "count":0,
                 "rate1":0,
                 "rate5":0,
                 "rate15":0,
                 "p50":0,
                 "p90":0,
                 "p95":0,
                 "p99":0
              }
           }
        }
     ],
     "uri":"/api/tunnels"
  }
 

Мой Сценарий Powershell:

 function ConvertFrom-Json20([object] $item){ 
  add-type -assembly system.web.extensions
  $ps_js=new-object system.web.script.serialization.javascriptSerializer

  #The comma operator is the array construction operator in PowerShell
  return ,$ps_js.DeserializeObject($item)
}

$content = get-content -path "c:pathtojson.txt"
$json = ConvertFrom-Json20($content)

$url = $json | select -expand tunnels | select public_url

echo "url=>" $url
 

Комментарии:

1. Новичок в PS, на WIn7, если это ваша личная машина, почему бы просто не перейти на PS5x, которая является последней версией Windows Powershell ? MS заявила, что это последняя версия, но она будет во всех будущих версиях ОС в обозримом будущем, так же как cmd.exe есть. Кросс-платформенное ядро PowerShell (в настоящее время v7) — это будущее, и оно регулярно обновляется. Чем Windows PowerShell является сегодня, тем она и останется навсегда. Ядро PowerShell не является обновлением или заменой Windows PowerShell. Это параллельная установка в Windows, которая также работает в Linux и OSX и используется в M365/Azure.

2. WInPS опирается на полную платформу Windows .Net, PowerShell Core использует только .Net Core. В WinPSv5/PSCore уже есть встроенные командлеты JSON. Поэтому не напрягайтесь на устаревших PS, которые больше не поддерживаются и действительно должны быть отключены в системах.

3. Я рад перейти на PS5x. Насколько я понимаю, функция ConvertFrom-Json20 была многозначной, поэтому в конце концов я имел бы дело с одним и тем же объектом. Правильно? Итак, следует url = $json | select -expand tunnels | select public_url ли работать с PS5x?

4. Быть новичком-это прекрасно, но сначала вам действительно следует потратить время на то, чтобы освоиться с PowerShell в целом. Youtube-ваш друг. Запуск PowerShell что касается Powershell с использованием JSON или другого, Youtube по-прежнему является разумным .

5. Смотрите мои обновления для вас.

Ответ №1:

Продолжая мои комментарии. Просто обновитесь до последней версии WINPS с помощью командлетов JSON, не пытайтесь изобретать велосипед.

Среда управления Windows 5.1

https://www.microsoft.com/en-us/download/details.aspx?id=54616

Среда управления Windows 5.1 включает обновления для Windows PowerShell, Конфигурации желаемого состояния Windows PowerShell (DSC), удаленного управления Windows (WinRM), Инструментария управления Windows (WMI). Примечания к выпуску: https://go.microsoft.com/fwlink/?linkid=839460

 Get-Command -Name '*json*' | Format-Table -AutoSize
# Results
<#
CommandType Name             Version Source                      
----------- ----             ------- ------                      
Cmdlet      ConvertFrom-Json 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      ConvertTo-Json   3.1.0.0 Microsoft.PowerShell.Utility
#>
 

PowerShell изначально использует JSON, XML, и у вас есть доступ ко всей .Net, поэтому вы можете использовать .Чистые пространства имен для JSON.

Просто посмотрите файлы справки о том, как их использовать. Есть полные объяснения и примеры.

 # Get specifics for a module, cmdlet, or function
(Get-Command -Name Get-Help).Parameters
(Get-Command -Name Get-Help).Parameters.Keys
Get-help -Name Get-Help -Examples
Get-help -Name Get-Help -Full
Get-help -Name Get-Help -Online


(Get-Command -Name ConvertFrom-Json).Parameters
(Get-Command -Name ConvertFrom-Json).Parameters.Keys
Get-help -Name ConvertFrom-Json -Examples
Get-help -Name ConvertFrom-Json -Full
Get-help -Name ConvertFrom-Json -Online


(Get-Command -Name ConvertTo-Json).Parameters
(Get-Command -Name ConvertTo-Json).Parameters.Keys
Get-help -Name ConvertTo-Json -Examples
Get-help -Name ConvertTo-Json -Full
Get-help -Name ConvertTo-Json -Online
 

Обновите в соответствии с вашим комментарием

Используя вышесказанное, вы можете просто перемещаться по объекту JSON по точечной ссылке и / или индексу.

 $JsonData = '
{
     "tunnels":[
        {
           "name":"command_line",
           "uri":"/api/tunnels/command_line",
           "public_url":"tcp://8.tcp.ngrok.io:12716",
           "proto":"tcp",
           "config":{
              "addr":"localhost:32400",
              "inspect":false
           },
           "metrics":{
              "conns":{
                 "count":0,
                 "gauge":0,
                 "rate1":0,
                 "rate5":0,
                 "rate15":0,
                 "p50":0,
                 "p90":0,
                 "p95":0,
                 "p99":0
              },
              "http":{
                 "count":0,
                 "rate1":0,
                 "rate5":0,
                 "rate15":0,
                 "p50":0,
                 "p90":0,
                 "p95":0,
                 "p99":0
              }
           }
        }
     ],
     "uri":"/api/tunnels"
  }
' | 
ConvertFrom-Json

$JsonData
# Results
<#
tunnels                                                                                                                    uri         
-------                                                                                                                    ---         
{@{name=command_line; uri=/api/tunnels/command_line; public_url=tcp://8.tcp.ngrok.io:12716; proto=tcp; config=; metrics=}} /api/tunnels
#>

$JsonData.tunnels
# Results
<#
name       : command_line
uri        : /api/tunnels/command_line
public_url : tcp://8.tcp.ngrok.io:12716
proto      : tcp
config     : @{addr=localhost:32400; inspect=False}
metrics    : @{conns=; http=}
#>

$JsonData.uri
# Results
<#
/api/tunnels
#>

$JsonData.uri.Split('/')
# Results
<#
api
tunnels
#>

$JsonData.uri.Split('/')[-1]
# Results
<#
tunnels
#>
 

Что касается твоих вещей… Ну, это никогда не бывает предметом. просто веревочка.

Это работает не так, как вы думаете

 function ConvertFrom-Json20([object] $item)
{ 
  Add-Type -Assembly System.Web.Extensions

  $ps_js = New-Object System.Web.Script.Serialization.JavascriptSerializer
  return
  $ps_js.DeserializeObject($item)
}

($content = Get-Content -path 'D:Scriptsjson.txt')

($json = ConvertFrom-Json20($content))
# Results
<#
Nothing is returned
#>

# So this would never work
# Results
<#
$url = $json | select -expand tunnels | select public_url

echo "url=>" $url
#>
 

Итак, просто прочитайте данные и возьмите строку

 (Get-Content -path 'D:Scriptsjson.txt').Trim() | 
Select-String -Pattern 'uri.*'
# Results
<#
"uri":"/api/tunnels/command_line",
"uri":"/api/tunnels"
#>

((Get-Content -path 'D:Scriptsjson.txt').Trim() | 
Select-String -Pattern 'uri.*')[-1] -replace '"' -split('/')
# Results
<#
uri:
api
tunnels
#>
(((Get-Content -path 'D:Scriptsjson.txt').Trim() | 
Select-String -Pattern 'uri.*')[-1] -replace '"' -split('/'))[-1]
# Results
<#
tunnels
#>
 

Чтобы получить объект из этого файла JSON в PSv2, вы бы сказали сделать что-то вроде этого.

 [void][System.Reflection.Assembly]::LoadWithPartialName('System.Web.Extensions')

$JsonData    = Get-Content -Path 'D:ScriptsJson.txt'
$Serializer  = New-Object System.Web.Script.Serialization.JavaScriptSerializer
($JsonObject = $Serializer.DeserializeObject($JsonData))
# Results
<#
Key     Value                                                                 
---     -----                                                                 
tunnels {System.Collections.Generic.Dictionary`2[System.String,System.Object]}
uri     /api/tunnels 
#>
 

Или вот так…

 ($JsonObject = New-Object PSObject -Property $Serializer.DeserializeObject($JsonData))
# Results
<#
tunnels                                                                uri         
-------                                                                ---         
{System.Collections.Generic.Dictionary`2[System.String,System.Object]} /api/tunnels
#>
 

… затем точечная ссылка

 $JsonObject.tunnels
# Results
<#
Key        Value
---        -----
name       command_line
uri        /api/tunnels/command_line
public_url tcp://8.tcp.ngrok.io:12716 
proto      tcp
config     {[addr, localhost:32400], [inspect, False]}
metrics    {[conns, System.Collections.Generic.Dictionary
#>

$JsonObject.uri
# Results
<#
/api/tunnels
#>
 

Комментарии:

1. Это было довольно просто, как только у меня появился доступ к ссылке dot. Спасибо — это сэкономило много времени!

2. Не беспокойтесь, рад, что это помогло.

Ответ №2:

Вот простой ответ с помощью Powershell 5.1

 $json = get-content -path "c:pathtojson.txt" | ConvertFrom-Json
$url = $json.tunnels.public_url