Getting response from REST API calls

Hi there everyone!

I am trying to make powershell run commands through an external management site (wordpress multi-site-management dashboard), and i cant seem to be able to retrieve the response from the website.

The foreach loop which is not returning any response (even though it runs the exact same call) is found here:
https://gist.github.com/jtn-webkoncept/c7efb31b07474e6af7f2b525ec42db97

Can someone tell me what i’m missing?

If i run this, i get the write response back by default (running Powershell ISE):

$pluginpath = “forminator/forminator.php”
$cosandsec = “consumer_key=ck_df&consumer_secret=cs_8f745gd”
$siteid =“977”

$Url = “https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id=$($siteid)&type=plugin&slug=$($pluginpath)&$($cosandsec)

Invoke-RestMethod -Method ‘Put’ -Uri $url


I would greatly appreciate some feedback!

The reponse is in JSON format, perhaps this is why my error-catch attempts are failing?

My first guess would be this:

$FileList = (Get-ChildItem 'C:\Users\Dern\Desktop\PS2020\MainWP\PUT-Pluginupdate\updatelist\updateme.txt').fullname

It is referencing a specific file, which would be Get-Item. Also, here is a better way to build the string, imho:

$Url = "https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id={0}&type=plugin&slug={1}&{2}" -f $websiteid,$pluginpath,$cosandsec

and getting results from the the for loop, everything should roll up (no +=) …

$myOutput = foreach ($blah in $blahs) {
    foreach ($foo in $foos) {

    }
}

$myOutput #| Export-Csv ...

Hi Rob!

Thank you for your swift response :slight_smile:

Regarding the $Filelist ( i forgot to mention that ) - It is supposed to take one ID, going on a list in the txt file:
1232
6543
4563

  • and so on

Each of the ID’s represent a site to have this specific plugin updated, mentioned in $pluginpath.
So i want it to loop each line inside the file, which seems to work.

The call itself, also seems to work now. ( I tried to use your replacement for $Url, but for some reason that broke the call, and i actually did get an error message saying the request failed ).

I just cant seem to figure out, if i make a simple call, without looping, i get the response i want (just printet out in the console), but i cant seem to catch it in this loop :frowning:
When there is a “normal error” it does get reported back to me, if the URL does not match for an example, but when i am supposed to get a “succes response” in JSON format, i just get nothing.

Maybe i am not supposed to try and get a JSON response with Exception.message?

The response error i do get, to clarify, are not from any JSON format. These are just 404, 403 etc.

If i launch this code in a seperate file:

$pluginpath = "forminator/forminator.php"
$cosandsec = "consumer_key=ck_5939575f46dd2cb401b1183e8b8&consumer_secret=cs_8f7452d67154e056"
$siteid ="977"

$Url = "https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id=$($siteid)&type=plugin&slug=$($pluginpath)&$($cosandsec)"

Invoke-RestMethod -Method 'Put' -Uri $url

write-host $url

 

I get this response:

https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id=977&type=plugin&slug=forminator/forminator.php&consumer_key=ck_52f401b1183e8b8&consumer_secret=cs_8f7452

SUCCESS
-------
Process ran.

And its the same thing i’m doing in the loop, pretty much.

Just to simplify things, look at this structure. First you need to have ErrorAction set to capture errors from Invoke-RunBook. Next, in the try block, you are going to parse $updateprocess, not the exception:

$pluginpath = "forminator/forminator.php"
$cosandsec = "consumer_key=ck_5daadfa8&consumer_secret=cs_8adfa97b10d1b8056"

$list = Get-Content -Path 'C:\Users\Dern\Desktop\PS2020\MainWP\PUT-Pluginupdate\updatelist\updateme.txt'

$myOutput = foreach ($listedid in $FileList) {
    foreach ($websiteid in (Get-Content $listedid)) {

        try {
            $Url = "https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id={0}&type=plugin&slug={1}&{2}" -f $websiteid, $pluginpath, $cosandsec
            $updateprocess = Invoke-RestMethod -Method 'Put' -Uri $url - ErrorAction Stop
            write-host "dette er url $url"
            # create custom objects and run API call
            [PSCustomObject]@{
                websiteid              = $websiteid
                Exceptionmessage       = $updateProcess.success
                Exceptionresponse      = $updateProcess.success
                StatusdescriptionValue = '200'
                Statusdescription      = 'SUCCESS'
            }

        } catch {
            # catcherrors
            [PSCustomObject]@{
                websiteid              = $websiteid
                Exceptionmessage       = $_.Exception.Message
                Exceptionresponse      = $_.Exception.Response
                StatusdescriptionValue = $_.Exception.Response.StatusCode.value__ 
                Statusdescription      = $_.Exception.Response.StatusDescription
            }
        }
    }
}

Hi again Rob!

Thank you so much for you details!

It works perfectly now :slight_smile:

This is the final structure:
https://gist.github.com/jtn-webkoncept/5fa2b0f1b8fde93932006491c89352da

My CSV output now looks like this:

“websiteid”,“Exceptionmessage”,“Exceptionresponse”,“StatusdescriptionValue”,“Statusdescription”
“977”,“Process ran.”,“200”,“SUCCESS”

Have a fantastic day :slight_smile:

As a sidenote, i could not make the script work with your suggested section:

$Url = https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id={0}&type=plugin&slug={1}&{2} -f $websiteid, $pluginpath, $cosandsec

  • so i just the one from the prior version which seems to do the trick :slight_smile:

That is just a string format. The curly brackets represent array position for the passed arguments:

$websiteId = 1234
$pluginPath = 'myPluginPath'
$cosandsec = 'myCosAndSec'

“https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id={0}&type=plugin&slug={1}&{2}” -f $websiteid, $pluginpath, $cosandsec

https://test.dk/wp-json/mainwp/v1/site/site-update-item?site_id=1234&type=plugin&slug=myPluginPath&myCosAndSec

Personal preference over concatenating by putting variables or $($var) in a string.

Ah, i see :slight_smile:

I have tested it a couple of times now this script, and it works, however i was hoping i could ask for some input on the next issue i am fighting aswell.

The script runs, but it runs very slowly, as it awaits response before initiating the next foreach loop.
I have tried using PoshRSJob and ForEach-Object (which i have never used before) to allow the function to loop in parallel, testing with 5 parallel processes.

I keep getting "Parameter set cannot be resolved using the specified named parameters. " just filling up the CSV output sheet.
I have looked at alot of examples and syntax but i cant figure out how to get this error fixed.
Im guessing it have something to do with do with the $Targets not being readable in this manner?
$Targets is just supposed to be the ID’s used already.

As far as i can read up on there is no available parallel function simply for “foreach” which is why i am including ForEach-Object and Posh, or atleast trying.

Here is the modified code:
https://gist.github.com/jtn-webkoncept/cbff3c178d37ca0fbc40a2b974c4961a

Take a look at examples like this:

https://docs.microsoft.com/en-us/powershell/scripting/learn/deep-dives/write-progress-across-multiple-threads?view=powershell-7.1

The loop is in the wrong place. You want to process each website in it’s own thread. To emulate the updates taking different time, the WebSite id is used as milliseconds, so 2000 would be 2 seconds.

#Emulate Get-Content
$webSiteIds = @"
1232
6543
4563
8567
9564
3542
1784
6743
3244
8567
9564
"@ -split [environment]::NewLine

$pluginpath = "forminator/forminator.php"
$cosandsec = "consumer_key=ck_5daadfa8&consumer_secret=cs_8adfa97b10d1b8056"

$origin = @{}
$webSiteIds | Foreach-Object {$origin.($_) = @{}}

# Create synced hashtable
$sync = [System.Collections.Hashtable]::Synchronized($origin)

$job = $webSiteIds | Foreach-Object -ThrottleLimit 3 -AsJob -Parallel {

    $syncCopy = $using:sync
    $process = $syncCopy.$($PSItem)

    $process.Id = $PSItem
    $process.Activity = "Update of WebSiteId $($PSItem) starting"
    $process.Status = "Updating"

    $Url = "https://test.dk/wp-json/mainwp/v1/site/site-update-wordpress?site_id=$($PSItem)&$($cosandsec)"

    try {        
        #$updateprocess = Invoke-RestMethod -Method 'Put' -Uri $url
        
        #Emulate long Invoke-RestMethod
        #Start-Sleep -Milliseconds ($PSItem * 2)
        Start-Sleep -Milliseconds $PSItem

        [PSCustomObject]@{
            url                    = $url
            websiteid              = $PSItem
            Exceptionmessage       = $updateProcess.success
            StatusdescriptionValue = '200'
            Statusdescription      = 'SUCCESS'
        }

    } 
    catch {
        [PSCustomObject]@{
            url                    = $url
            websiteid              = $PSItem
            Exceptionmessage       = $_.Exception.Message
            StatusdescriptionValue = $_.Exception.Response.StatusCode.value__ 
            Statusdescription      = $_.Exception.Response.StatusDescription
        }
    }

    $process.Completed = $true
}

while($job.State -eq 'Running')
{
    $sync.Keys | Foreach-Object {
        # If key is not defined, ignore
        if(![string]::IsNullOrEmpty($sync.$_.keys))
        {
            # Create parameter hashtable to splat
            $param = $sync.$_

            # Execute Write-Progress
            Write-Progress @param
        }
    }

    # Wait to refresh to not overload gui
    Start-Sleep -Seconds 0.1
}

This is executed as a job, so you need to understand how to work with jobs. For instance, testing this code a couple of times I have multiple jobs. The results can only be retrieved one time unless you use the -Keep switch.

PS C:\Users\rasim> Get-Job #old job from testing


Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
67     Job67           PSTaskJob       Completed     False           PowerShell           …

PS C:\Users\rasim> c:\Users\rasim\Desktop\temp.ps1 #rerun script
PS C:\Users\rasim> Get-Job #get the jobs again


Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
67     Job67           PSTaskJob       Completed     False           PowerShell           …
103    Job103          PSTaskJob       Completed     True            PowerShell           …

PS C:\Users\rasim> $results = Receive-Job -Id 103 -Keep

PS C:\Users\rasim> $results | Select -First 5


url                    : https://test.dk/wp-json/mainwp/v1/site/site-update-wordpress?site_id=1232&
websiteid              : 1232
Exceptionmessage       :
StatusdescriptionValue : 200
Statusdescription      : SUCCESS

url                    : https://test.dk/wp-json/mainwp/v1/site/site-update-wordpress?site_id=6543&
websiteid              : 6543
Exceptionmessage       :
StatusdescriptionValue : 200
Statusdescription      : SUCCESS

url                    : https://test.dk/wp-json/mainwp/v1/site/site-update-wordpress?site_id=4563&
websiteid              : 4563
Exceptionmessage       :
StatusdescriptionValue : 200
Statusdescription      : SUCCESS

url                    : https://test.dk/wp-json/mainwp/v1/site/site-update-wordpress?site_id=8567&
websiteid              : 8567
Exceptionmessage       :
StatusdescriptionValue : 200
Statusdescription      : SUCCESS

url                    : https://test.dk/wp-json/mainwp/v1/site/site-update-wordpress?site_id=9564&
websiteid              : 9564
Exceptionmessage       :
StatusdescriptionValue : 200
Statusdescription      : SUCCESS