Invoke-RestMethod -Method PUT

I have been working on querying a refrigeration controller API for the past week or so. They implement an “API Key” which I have tested and works. I can successfully pull data with the key. I’m having to construct the URI manually to use the key and I’m doing it like this:

$controller = "192.168.50.185"
$protocol = "http://"
$apicall = "/api/Settings/Location"
$apikey = "1234567890"
$key = "?key="+$apikey
$request = $protocol+$controller+$apicall+$key
$response = Invoke-RestMethod $request

I’m not sure if there is a more efficient way to do this, but this does work! >:}

Now here is where it get’s really muddy…

When I try to manipulate the data and use the PUT method, which is what the API is expecting and allowed, per their documentation, my PUTS fail! >:\

The PUT looks like this, which follows inline with the above code:

$response = Invoke-RestMethod $request 
$response.PhoneNumber.current
$response.PhoneNumber.current = "(555) 867 5309"
$json = $response | ConvertTo-Json
Invoke-RestMethod -Uri $request -Verbose -Method Put -Body $json

The big red error looks like this:
Invoke-RestMethod : The remote server returned an error: (403) Forbidden.
At C:\Scripts\Ke2APIQuery_base.ps1:12 char:1

  • Invoke-RestMethod -Uri $request -Verbose -Method Put -Body $json
  •   + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
      + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    
    

I’m trying to use the following “tested/verified” C# snippet, which I received from the API developer(s), and convert it to a PowerShell script:

using System;

//Tested with dotnet-sdk-2.1 on Ubuntu 18.04, should work equally as well on windows
namespace csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            using(var client = new System.Net.WebClient()) {
                //Replace 192.168.50.185 with IP address of your controller
                /////////////////////////////////////////////
                //Example GET request- all api data
                var getResult = client.DownloadString("http://192.168.50.185/api");
                //Print result to console
                Console.WriteLine(getResult);
                ///////////////////////////////
                //Example PUT request
                //Assemble payload. A string containing JSON encoded data is used in example, but any JSON data could be used
                //Multiple values can be changed in a single request, but only a single category can be changed at a time (refrigeration in example)
                //Note that all values are encoded as JSON strings- this means that numbers are surrounded by quotes (")
                //Replace 12345678 with value of key for your controller
                var PUTpayload = System.Text.Encoding.ASCII.GetBytes(@"{""RoomTemp"":""22.5"",""Refrigerant"":""R-22""}");
                var result = (client.UploadData("http://192.168.50.185/api/setpoints/refrigeration?key=12345678", "PUT", PUTpayload));
                Console.WriteLine(System.Text.Encoding.ASCII.GetString(result));
            }
        }
    }
}

I have gotten this far, but I’ve spent the last few hours “PUTTING” myself through hell with this “PUT” command…

My gut tells me it has something to do with the way the JSON is formatted, but I’m not 100% sure.

Here is a sample of the raw JSON output from the controller:

{
	"BusinessName":{
		"current":"KE2 Therm Solutions"
	},
	"PhoneNumber":{
		"current":"(888) 337 3358"
	},
	"Location":{
		"current":"Adams Freezer"
	}
}

This looks the same as the JSON as I’m posting in my PUT request, just with an updated phone number…

Any suggestions?

One of the first things to check is the JSON depth with ConvertTo-Json, if you look at the help:

    -Depth 
        Specifies how many levels of contained objects are included in the JSON representation. The default value is 2.

If your depth is more than 2, the JSON is truncated, so try this first:

$json = $response | ConvertTo-Json -Depth 30