#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