Ошибка данных Select-Object из-за успешного Invoke-RestMethod

У меня есть рабочий вызов службы отдыха с использованием Invoke-RestMethod -Uri https://.... Результат вызова в JSON может быть передан по каналу данных в Format-Table -Property ..., и данные будут показаны.

Но когда Select-Object -Property ... используется после вызова с теми же параметрами, PSObject имеет столбцы, но не содержит данных для них. Если я использую другой веб-сервис, вызов будет работать.

введите здесь описание изображения

Что может быть причиной того, что PSObject не показывает никаких значений?


Рабочий пример веб-сервисов общественного отдыха

Invoke-RestMethod -Uri https://jsonplaceholder.typicode.com/todos/1 |
Select-Object -Property title

Результат

@{title=delectus aut autem}

Новый сбой, другой API

Invoke-RestMethod -Uri https://cat-fact.herokuapp.com/facts | Select-Object -Property text

введите здесь описание изображения


person ΩmegaMan    schedule 06.07.2019    source источник
comment
наиболее распространенная причина, по которой Select-Object возвращает объекты с пустыми реквизитами, — это использование неправильного имени для рассматриваемых реквизитов. Итак ... проверьте, как называются ваши НАСТОЯЩИЕ реквизиты, и используйте их. если вы хотите изменить эти имена свойств, используйте вычисляемое выражение.   -  person Lee_Dailey    schedule 06.07.2019
comment
Я попробовал третий общедоступный API, который отправляет большие объемы данных, и он тоже не работает... Мне интересно, является ли это внутренней проблемой синтаксического анализа JSON с большими данными. Я видел, что с данными SQL Server sproc возвращает эту привязку с 2033 символами из-за используемого преобразователя XML.   -  person ΩmegaMan    schedule 06.07.2019
comment
ваше имя пользователя не набирается на моей клавиатуре. [вздох...] ///// в возвращаемых данных НЕТ text prop. единственным свойством является all, которое содержит массив, содержащий объекты со свойством .text.   -  person Lee_Dailey    schedule 06.07.2019
comment
@Lee_Dailey О, я ненавижу, когда другие пользователи делают @, чтобы пометить их. Извиняюсь. Позвольте мне взглянуть на свойство All. Мои исходные данные - это подобъекты в массиве. Интересно.   -  person ΩmegaMan    schedule 06.07.2019
comment
не серьезная проблема. [усмехается] ///// пожалуйста, взгляните на мой ответ. он охватывает только ссылку на кошек, но идея должна работать в другом месте. [усмехнуться]   -  person Lee_Dailey    schedule 06.07.2019


Ответы (2)


Вы наткнулись на ужасную комбинацию двух странностей PowerShell при преобразовании массивов JSON:

  • Invoke-RestMethod и ConvertFrom-Json отправляют преобразованные из JSON массивы в целом по конвейеру, а не поэлементно, как обычно:

    • Примечание. В PowerShell (Core) 7.0 поведение ComvertFrom-Json было изменено, чтобы привести его в соответствие с обычным поведением перечисления элементов, и переключатель -NoEnumerate был добавлен в качестве подписки к старому поведению. Обсуждение, которое привело к этому изменению, см. в разделе GitHub issue #3424.

    • Однако на момент написания этой статьи (PowerShell (Core 7.2) Invoke-RestMethod по-прежнему демонстрирует это неожиданное поведение, которое обсуждается в GitHub issue #15272.

  • Select-Object не выполняет перечисление членов, поэтому ищет указанное свойство (например, text) непосредственно в массиве там, где его нет.

Чтобы продемонстрировать проблему на простом примере:

# Windows PowerShell only:
# Because ConvertFrom-Json sends an *array* (of 2 custom objects) through
# the pipeline, Select-Object looks for property .text on the *array* -
# and can't find it.
# The same applies to Invoke-RestMethod (also still in 
# PowerShell (Core) as of v7.2)
PS> ConvertFrom-Json '[{ "text": "a" }, { "text": "b" }]' | Select-Object text

text
----
       # NO VALUES 

Простой обходной путь состоит в том, чтобы заключить вызов ConvertFrom-Json / Invoke-RestMethod в (...), что вынуждает перечислять массив, заставляя Select-Object работать должным образом.:

# (...) forces enumeration
PS> (ConvertFrom-Json '[{ "text": "a" }, { "text": "b" }]') | Select-Object text

text
----
a
b

Обратите внимание, что такая команда, как Select-Object -Property text (без -ExpandProperty), по-прежнему выводит пользовательские объекты, имеющие свойство .text, а не значения свойства .text.

Если все, что вас интересует, это значения свойств, решение проще, потому что вы можете использовать вышеупомянутое перечисление элементов непосредственно в массиве:

# Using .<propName> on an array (collection) implicitly returns the
# property values from the *elements* of that collection (member enumeration).
PS> (ConvertFrom-Json '[{ "text": "a" }, { "text": "b" }]').text
a
b

Обратите внимание, что вывод теперь не имеет заголовка text, потому что выводятся просто строковые значения, а не пользовательские объекты.

person mklement0    schedule 06.07.2019
comment
В моей ситуации размещение Invoke-RestMethod в скобках работает. Мне было интересно, придется ли мне вызывать Invoke-WebRequest, чтобы получить необработанный json, а затем скрывать, используя вместо этого ConvertFrom-Json в скобках; но к счастью нет. Спасибо за вашу помощь / идеи. - person ΩmegaMan; 07.07.2019

ваша проблема во втором примере заключается в том, что НЕТ реквизита с именем text. [усмехнуться]

единственной опорой является all, которая содержит массив объектов, которые ДЕЙСТВИТЕЛЬНО содержат опору с именем text. так что вам нужно что-то, что может получить эту более глубокую опору. один из способов — использовать два вызова Select-Object. что-то вроде этого ...

$Url = 'https://cat-fact.herokuapp.com/facts'
$RawIRM = Invoke-RestMethod -Uri $Url 
$SO_IRM = $RawIRM |
    Select-Object -ExpandProperty all |
    Select-Object -Property text

переменная $SO_IRM теперь имеет массив из 178 строк о кошках. [усмехнуться]

person Lee_Dailey    schedule 06.07.2019
comment
Я получаю ваш ответ, и имеет смысл разыменовать all для кошек. Но у моих исходных данных нет такого свойства над массивом объектов. [{…}, {…}] к сожалению, ExpandProperty не работает с моими данными, как со свойством all кошки. У меня есть возможность изменить веб-сервис для использования именованного свойства, но это может сломать разработчика реагирования на интерфейсе. Спасибо за вашу помощь. - person ΩmegaMan; 06.07.2019
comment
@ΩmegaMan - еще один способ получить эту информацию - запустить ее через .ForEach() или другой цикл и сослаться на нее с помощью $_.PropName. затем вы можете использовать различные реквизиты для создания PSCustomObject с нужными вам реквизитами. - person Lee_Dailey; 06.07.2019
comment
Ваш анализ вызова https://cat-fact.herokuapp.com/facts верен (и полезен), но он не связан с проблемой @ΩmegaMan; проблема в нашем старом друге, github.com/PowerShell/PowerShell/issues/3424 - person mklement0; 07.07.2019
comment
@mklement0 - ага! [усмехается], что имеет смысл... и довольно причудливо. Благодарю вас за информацию! - person Lee_Dailey; 07.07.2019
comment
Переносим ответ на mklement; Извините. Но вы помогли мне преодолеть первоначальный горб, и за это... спасибо! - person ΩmegaMan; 07.07.2019
comment
@ΩmegaMan - это хорошая новость... он настоящий! [усмехается] ... и добро пожаловать! - person Lee_Dailey; 07.07.2019