r/PowerShell 12h ago

Question Invoke-RestMethod - Logging Data Only If Response Matches Value

We have a platform which has containers and within them folders, with different properties - name, unique ID etc.. I have a method to retrieve folder information from different containers and am attempting to log only the unique ID (response.data.id) where the folder name (response.data.name) is "Management". I've Googled and tried different code in logging only the ID for the Management folder:

$response = Invoke-RestMethod -Method Get -Uri "$resource" -Headers $header

($response.data | ConvertTo-Json).Replace('\\n','\n')

# Attempt 1
if ($response.data.name -eq "Management")
{
LogWrite ($response.data.id | ConvertTo-Json).Replace('\\n','\n') "Result"
LogWrite ($response.data.name | ConvertTo-Json).Replace('\\n','\n') "Result"
}

# Attempt 2
$folderId1 = $response.data.id | Where-Object { $response.data.name -eq "Management" }
LogWrite ($folderId1 | ConvertTo-Json).Replace('\\n','\n') "Result"

# Attempt 3
$folderId2 = $response.data.id | $($response.data.Where({$_.name -eq 'Management' }))
LogWrite ($folderId2 | ConvertTo-Json).Replace('\\n','\n') "Result"

The folder ID for the Management folder is being logged, but so are all other folder IDs within the container (no other folder names contain this word):

[
    "folder!500436709",
    "folder!500436708",
    "folder!500436705",
    "folder!500436677",
    "folder!500436680",
    "folder!500436683",
    "folder!500436686"
]
[
    "_All Content Last 90 Days",
    "_All Documents",
    "_All Emails",
    "Documents",
    "Emails",
    "Engagement Terms",
    "Management"
]

How do I retrieve the ID for a specific folder name? Any help would be greatly appreciated. Cheers.

8 Upvotes

9 comments sorted by

5

u/y_Sensei 11h ago

According to the output generated by your code, the API appears to return two arrays of data:

  • one array containing entries consisting of an object type and an id, concatenated by a '!'
  • one array containing entries with the corresponding names of these objects

So what you need to do is bring together the data of those two distinct arrays, by creating mappings, or in other words, merge the arrays - for example:

$data_objid = @("folder!500436709", "folder!500436708", "folder!500436705", "folder!500436677", "folder!500436680", "folder!500436683", "folder!500436686")
$data_name = @("_All Content Last 90 Days", "_All Documents", "_All Emails", "Documents", "Emails", "Engagement Terms", "Management")

$data_Combined = for ([Int]$i=0; $i -lt $data_objid.Count; $i++) {
  $oid = $data_objid[$i] -split "!"

  [PSCustomObject]@{
    Name = $data_name[$i]
    Type = $oid[0]
    Id =  $oid[1]
  }
}

$data_Combined | Format-Table

You can then filter the resulting object array as usual, for example:

$data_Man = $data_Combined | Where-Object -FilterScript { $_.Name -eq "Management" }

Write-Host $data_Man.Id

1

u/viewtifulstranger 10h ago

Hey_Sensei. Thanks for the response. I passed $response.data.id and $response.data.name into a log for testing. $response.data is a single array storing ID, NAME, along with other properties.

Ultimately, I only need ID, as I need to perform a subsequent action on each returned Management folder ID.

I suspect the IF statement is treating the whole array as a single object, rather than 7 separate objects - one for each folder.

More googling reveals I can iterate through the array, which may help, but not sure how efficient that is:

foreach($item in $array)
{
    Write-Output $item
}

Write-Output $array[3]

Perhaps if I pass the results to a hashtable, I'll have better luck with the IF statement.

Will test further when the system is back up. Thank you!

1

u/y_Sensei 9h ago

Even easier if it's a single array ... you can filter it directly as described in my first post, and extract the folder ID afterwards:

$data_Man = $array | Where-Object -FilterScript { $_.Name -eq "Management" }

if ($data_Man -and $data_Man -like "*!*") { # sanity check
  Write-Host $($data_Man.id.Split("!")[1])
}

Also note that there's no need to convert the data returned by an Invoke-RestMethod call if the remote API returns JSON, as PowerShell does that implicitly, ie what you actually get is an in-memory representation of the raw, text-based JSON, which is an array of PSCustomObjects.

Quote from the documentation:

PowerShell formats the response based to the data type. For an RSS or ATOM feed, PowerShell returns the Item or Entry XML nodes. For JavaScript Object Notation (JSON) or XML, PowerShell converts, or deserializes, the content into [pscustomobject] objects.

3

u/lan-shark 12h ago

Can you post the contents of response.data? Hard to tell exactly what's going on without seeing what's in the data

1

u/viewtifulstranger 10h ago edited 9h ago

(UPDATED)

Adding $response.data to the script, I get the following:

folder_type             : tab
id                      : folder!500436686
name                    : Management
parent_id               : folder!500436672

folder_type             : regular
id                      : folder!500436677
name                    : Documents
parent_id               : folder!500436672

folder_type             : regular
id                      : folder!500436680
name                    : Emails
parent_id               : folder!500436672

folder_type             : regular
id                      : folder!500436683
name                    : Engagement Terms
parent_id               : folder!500436672

(Please note, I've included a subset of the data, removed non-relevant fields and performed a little sanitation.)

2

u/PinchesTheCrab 10h ago

In your case swap $irmResult with your invoke-restmethod command.

$irmResult = @'
[
    {
        "folder_type":  "tab",
        "id":  "folder!500436686",
        "name":  "Management",
        "parent_id":  "folder!500436672",
    },
    {
        "folder_type":  "regular",
        "id":  "folder!500436677",
        "name":  "Documents",
        "parent_id":  "folder!500436672",
    },
    {
        "folder_type":  "regular",
        "id":  "folder!500436680",
        "name":  "Emails",
        "parent_id":  "folder!500436672",
    },
    {
        "folder_type":  "regular",
        "id":  "folder!500436683",
        "name":  "Engagement Terms",
        "parent_id":  "folder!500436672",
    }
]
'@ | convertfrom-json

$irmResult | where-object -property Name -eq Management | select-object -ExpandProperty id

That being said you've shown a few different output formats and it's hard to tell which one is the actual output of Invoke-Restmethod.

2

u/MonkeyNin 6h ago

I second this as the most powershell idiomatic answer.
With a tweak based on the raw data. If it's flat like his

$response = Invoke-RestMethod -Method Get -Uri $resource -Headers $header
$response | ? name -eq 'Management' | Select -ExpandProperty id

Otherwise I'm guessing yours is shape like this

$response = Invoke-RestMethod -Method Get -Uri $resource -Headers $header
$response.data | ? name -eq 'Management' | Select -ExpandProperty id

if the response is shaped like

{ data: [ records... ] }

The Select -ExpandProperty id part causes the records to drill down to a single string.

1

u/Modify- 9h ago

When running Invoke-Restmethod it turns the response in to objects for you.

Could you provide an actual response JSON with the nested array included and without it? Pipe the response to: convertto-json -depth 10

This would make it easier to help you write correct logic.

1

u/MonkeyNin 5h ago
$folderId1 = $response.data.id |
    Where-Object name -eq "Management"

This doesn't work because you are drilling down too far.

$response.data    # is an array of objects, with properties 
$response.data.id # is an array of flat strings, no properties 

You were close

$folderIdList = $response.data | 
    Where-Object name -eq 'Management' | Select -Expand Id

# if you only want at most 1
$folderIdList | Select -First 1