1

I have a working call to a rest service using Invoke-RestMethod -Uri https://.... The call's result, in JSON, can be piped the data to Format-Table -Property ... and data is shown.

But when Select-Object -Property ... is used after the invoke with the same parameters, the PSObject has the columns but no data for them. If I use a different webservice the call will work.

enter image description here

What could be causing the PSObject to not show any values?


Working Example on public rest web services

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

Result

@{title=delectus aut autem}

New Failure Different API

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

enter image description here

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
  • the most common reason for `Select-Object` to return objects with empty props is using the wrong name for the props in question. so ... check what your ACTUAL props are named & use those. if you want to change those prop names, use a calculated expression. – Lee_Dailey Jul 06 '19 at 19:30
  • I tried a third public API which sends large amounts of data and it fails too...I am wondering if it is an internal JSON parsing issue with larger data. I have seen that with SQL Server data sproc returns that peg at 2033 characters due to a XML converter used. – ΩmegaMan Jul 06 '19 at 19:58
  • your user name is not type-able on my keyboard. [*sigh ...*] ///// there IS NO `text` prop in the returned data. the only property is `all` & that contains an array that contains objects that have a `.text` property. – Lee_Dailey Jul 06 '19 at 20:24
  • @Lee_Dailey Oh I hate that on other users when doing the `@` to tag them. Sorry. Let me look at the `All` property. My initial data is subobjects in an array. Interesting. – ΩmegaMan Jul 06 '19 at 20:28
  • not a serious problem. [*grin*] ///// please take a look at my answer. it only covers the cats link, but the idea otta work elsewhere. [*grin*] – Lee_Dailey Jul 06 '19 at 20:30

2 Answers2

4

You've stumbled upon an unholy combination of two PowerShell oddities when converting JSON arrays:

  • Invoke-RestMethod and ConvertFrom-Json send converted-from-JSON arrays as a whole through the pipeline, instead of element by element, as usual:

    • Note: In PowerShell (Core) 7.0, ComvertFrom-Json's behavior was changed to align with the usual enumeration-of-elements behavior, and a -NoEnumerate switch was added as an opt-in to the old behavior. For the discussion that led to this change, see GitHub issue #3424.

    • However, as of this writing (PowerShell (Core 7.2) Invoke-RestMethod still exhibits this unexpected behavior, which is discussed in GitHub issue #15272.

  • Select-Object does not perform member-access enumeration, so it looks for the specified property (e.g., text) directly on the array, where it doesn't exist.

To demonstrate the problem with a simple example:

# 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 

A simple workaround is to enclose the ConvertFrom-Json / Invoke-RestMethod call in (...), which forces enumeration of the array, causing Select-Object to work as expected.:

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

text
----
a
b

Note that a command such as Select-Object -Property text (without -ExpandProperty) still output custom objects that have a .text property, not the .text property values.

If all you're interested in is property values, the solution is simpler, because you can use the above-mentioned member-access enumeration directly on the array:

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

Note how the output now has no text header, because it is mere string values that are being output, not custom objects.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    For my situation, placing `Invoke-RestMethod` in parenthesis is working. I was wondering if I would have to call `Invoke-WebRequest` to get the raw json and then covert using `ConvertFrom-Json` in parenthesis instead; but fortunately not. Thanks for your help/insights. – ΩmegaMan Jul 07 '19 at 14:42
3

your problem in the 2nd example is that there is NO prop named text. [grin]

the only prop is all and that contains an array of objects that DO contain a prop named text. so you need something that can get that deeper prop. one way is to use two Select-Object calls. something like this ...

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

the $SO_IRM var now has an array of 178 strings about cats. [grin]

Lee_Dailey
  • 7,292
  • 2
  • 22
  • 26
  • I am getting your answer and it makes sense to dereference `all` for the cats. But my initial data does not have such a property over the array of objects. `[{…}, {…}]` so sadly the `ExpandProperty` doesn't work on my data like on the cat's `all` property. I do have the ability to change the webservice to use a named property, but it might break the react developer on the front end. Thanks for your help. – ΩmegaMan Jul 06 '19 at 20:40
  • @ΩmegaMan - another way to get that info would be to run it thru a `.ForEach()` or other loop, and refer to it with `$_.PropName`. you could then use the various props to build a `PSCustomObject` that has the props you want. – Lee_Dailey Jul 06 '19 at 20:54
  • Your analysis of the `https://cat-fact.herokuapp.com/facts` call is correct (and helpful), but it is incidental to @ΩmegaMan's problem; the problem is our old friend, https://github.com/PowerShell/PowerShell/issues/3424 – mklement0 Jul 06 '19 at 21:28
  • 1
    @mklement0 - aha! [*grin*] that makes sense ... and is rather freaky. thank you for the info! – Lee_Dailey Jul 06 '19 at 21:41
  • 2
    Moving the answer to mklement; sorry. But you helped me over the initial hump and to that end...thanks! – ΩmegaMan Jul 07 '19 at 14:19
  • @ΩmegaMan - that is _good_ news ... his is the real one! [*grin*] ... and you are quite welcome! – Lee_Dailey Jul 07 '19 at 19:07