Powershell Invoke-Webrequest w/ JSON Body - Can not deserialize...? - json

I need to perform an Invoke-Webrequest with a specifically formatted body to add devices to a product. Here is what it looks like in json (example straight from the vendor's documentation):
$body_json = '{"datasource": [{
"parentId": "123456789000",
"name": "(name)",
"id": "(value)",
"typeId": 0,
"childEnabled": false,
"childCount": 0,
"childType": 0,
"ipAddress": "(ipAddress)",
"zoneId": 0,
"url": "(url)",
"enabled": false,
"idmId": 123456789000,
"parameters": [{
"key": "(key)",
"value": "(value)"
}]
}]}'
When I try to submit this in its json representation though, I get the following error:
Invoke-WebRequest : Can not deserialize instance of
com.vendor.etc.DataSourceDetail out of START_ARRAY token at [Source:
java.io.StringReader#22c614; line: 1, column: 1] At
C:\powershell_script_location\ps.ps1:114 char 9
+ $request = Invoke-WebRequest $url -Method Post -Headers $headers -Body $body_json - ...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation:
(System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest],
WebException + FullyQualifiedErrorId :
WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
The issue is with the format of the "parameters", parameter because the request submits fine when omitting the "parameters", but then the
devices that I'm adding are missing important parameter details.
Is there something wrong with Invoke-WebRequest, JavaScriptSerializer,
the vendor's code, or is this a user error? Let me know if any clarification is needed.
Unfortunately I don't know what a com.vendor.etc.DataSourceDetail instance looks like, as I am using an API and I don't have access to it directly.

Use Invoke-RestMethod instead of Invoke-WebRequest.
If you have the body as a string use:
Invoke-RestMethod -Uri http://your-url.com -Method POST -Body $body_json -ContentType "application/json"
If the body must be constructed from data/parameters, it might be easier to build a hashtable and convert it to json via ConvertTo-Json:
$body_json = #{
datasource = #(
#{
parentId = 123456789000
name = "name"
id = "value"
typeId = 0
childEnabled = $false
childCount = 0
childType = 0
ipAddress = "ipAddress"
zoneId = 0
url = "url"
enabled = $false
idmId = 123456789000
parameters = #( #{
key = "key"
value = "value"
})
})} | ConvertTo-Json -Depth 4
Invoke-RestMethod -Method 'Post' -Uri http://your-url.com -Body $body_json -ContentType "application/json"

Body Undefined
I couldn't understand why the req.body on the server was undefined (NodeJS Azure Function). It turns out I had a header that was an empty string.
It's not clear whether is was invoke-restmethod or azure-functions-core-tools that has a bug.
FWIW.

Related

Azure Management Service - Type conversion error ( NSG Security rule )

I am using the Azure Management Rest API in Powershell , to create an NSG with some rule properties at the creation time. (yes I am aware that there is a PS module that can do that as well)
I have constructed the body of my PUT request as per the Microsoft documentation.
$url = "https://management.azure.com/subscriptions/$subid/resourceGroups/$rg/providers/Microsoft.Network/networkSecurityGroups/$nsg2" +"?api-version=2022-05-01"
$body = #{
"name" = "NSG-Test";
"location" = "useast";
"properties"= #{
"securityRules" = #(
#{
"name" = "rule1"
"properties"= #{
"protocol" = "*"
"sourcePortRange"= "*"
"destinationPortRange" = "80"
"sourceAddressPrefix"= "*"
"destinationAddressPrefix"= "*"
"access" = "Allow"
"priority" = 130
"direction"="Inbound"
}
}
)
}
} | ConvertTo-Json
try{
$Result = (Invoke-RestMethod -Uri $url -Headers $Headers -Method PUT -Body $body -Verbose -ContentType "application/json")
Write-Host $Result
}
Unfortunately I am greeted with the following error when executing this code :
{
"error": {
"code": "InvalidRequestFormat",
"message": "Cannot parse the request.",
"details": [
{
"code": "InvalidJson",
"message": "Error converting value \"System.Collections.Hashtable\" to type 'Microsoft.WindowsAzure.Networking.Nrp.Frontend.Contract.Csm.Public.Se
curityRule'. Path 'properties.securityRules[0]', line 4, position 75."
}
]
}
}
So the reason behind this is the nested dictionary #{"name"="rule1"..} inside the securityRules attribute value.
When removing this hashtable, the request executes and the NSG gets created, however without any properties of course.
Is there any way to circumvent this issue and have the REST API accept my JSON body with it's properties?
I tried to reproduce the same in my environment I got the same error as below:
To resolve this issue, Make sure to add -Depth 4 in the ConvertTo-Json .
When I added ConvertTo-Json -Depth 4 the error was resolved.
Code:
$AppId="<clientID>"
$AppSecret="75X8Q~2RXXXXXX"
$TokenURI="https://login.microsoftonline.com/2f2ebbbc-e970-XXXXXXXX/oauth2/token"
$Resource="https://management.core.windows.net"
#OAUTH
$BodyRequest="grant_type=client_credentials&client_id=$AppId&client_secret=$AppSecret&resource=$Resource"
$AccessToken=Invoke-RestMethod -Method Post -Uri $TokenURI `
-Body $BodyRequest -ContentType 'application/x-www-form-urlencoded'
$subid ="<SubscriptionID>"
$rg="imran"
$nsg2="nsg2"
#$Headers=#{}
#$Headers.Add("Authorization ","Bearer " + $AccessToken.access_token)
$RequestURI = "https://management.azure.com/subscriptions/$subid/resourceGroups/$rg/providers/Microsoft.Network/networkSecurityGroups/$nsg2" + "?api-version=2022-07-01"
$body=#{
"name" = "nsg2";
"location" = "East us";
"properties"= #{
"securityRules" = #(
#{
"name" = "rule1"
"properties"= #{
"protocol" = "*"
"sourcePortRange"= "*"
"destinationPortRange" = "80"
"sourceAddressPrefix"= "*"
"destinationAddressPrefix"= "*"
"access" = "Allow"
"priority" = 130
"direction"="Inbound"
}
}
)
}
} | ConvertTo-Json -Depth 4
$Headers=#{}
$Headers.Add("Authorization","Bearer " + $AccessToken.access_token)
$Result = (Invoke-RestMethod -Uri $RequestURI -Headers $Headers -Method PUT -Body $body -Verbose -ContentType 'application/json' )
Write-Host $Result
Result:
To confirm in portal rule1 is added successfully like below:

Invoke RestMethod issues parsing JSON: Value not convertible to Int

I have to use PowerShell to manage a Websense server via API. I am using Invoke-RestMethod and I am using a json format to make the changes. The comand to the server is as follows:
Invoke-RestMethod -Uri $uriCreate -Method Post -Headers $headers -Body ($jsonCat | ConvertTo-Json) -ContentType "application/json"
My variables are as follows:
$uriCreate = https://<ipaddress>:<port>/api/web/v1/categories
$headers = #{ Authorization = <credentials> }
$jsonCat = [ordered]#{
"Transaction ID" = $transID
Categories = #(
[ordered]#{
"Category Name" = $catName
"Category Description" = $catDesc
"Parent" = $catID
}
)
}
When I attempt to create the category via Powershell I get the following error returned:
Invoke-RestMethod : {
"Error" : [ "Could not parse JSON: Value is not convertible to Int." ]
}
Any idea what I am doing wrong?

PowerShell Invoke-WebRequest | API Call

I'm using Gitea and I try to create a user using an API call in PowerShell:
Testing Plateforme : https://try.gitea.io/
API URL : https://try.gitea.io/api/swagger
API Token : 3bb81a498393f4af3d278164b5755fc23b74b785
Username : Will-stackoverflow
Password : willwill
Here it's what I have tried so far :
# Filling my var with some data
$username="myuser"
$email="myuser#mydomain.com"
$full_name="My User"
$password="P#$$w0rd"
# Building a hash with my data
$hash = #{
Email = $($email);
full_name = $($full_name);
login_name = $($username);
Password = $($password);
send_notify = "false";
source_id = 0;
Username = $($username)
}
# Converting my hash to json format
$JSON = $hash | convertto-json
# Displaying my JSON var
$JSON
Invoke-WebRequest -uri "http://try.gitea.io/api/v1/admin/users?access_token=3bb81a498393f4af3d278164b5755fc23b74b785" -Method POST -Body $JSON
My $JSON var is fed properly :
{
"Password": "P#w0rd",
"full_name": "My User",
"Username": "myuser",
"Email": "myuser#mydomain.com",
"source_id": 0,
"login_name": "myuser",
"send_notify": "false"
}
But there is the result (from my prod environement as I can't get it to work at all using the online plateforme) :
To me it sounds like the fields "Username", "Email" and "Password" are required, but they are filled in my displayed JSON. What am I missing or doing wrong ?
EDIT :
Adding the -ContentType 'application/json' parameter to the Invoke-WebRequest command as suggested by Theo :
Looking at the Swagger UI site, it seems to me the json must contain properties in lower-caps only
{
"email": "myuser#mydomain.com",
"full_name": "My User",
"login_name": "myuser",
"password": "P#w0rd",
"send_notify": $true,
"source_id": 0,
"username": "myuser"
}
Also, according to the Swagger site, you need to state the -ContentType.
Your code would look like this:
# Filling my var with some data
$username="myuser"
$email="myuser#mydomain.com"
$full_name="My User"
$password="P#$$w0rd"
# Building a hash with my data
$hash = #{
email = $($email); # string
full_name = $($full_name); # string
login_name = $($username); # string
password = $($password); # string
send_notify = $false; # boolean
source_id = 0; # int
username = $($username) # string
}
# Converting my hash to json format
$JSON = $hash | ConvertTo-Json
# Displaying my JSON var
$JSON
# just to make it somewhat easier on the eyes
$token = "3bb81a498393f4af3d278164b5755fc23b74b785"
$url = "http://try.gitea.io/api/v1/admin/users?access_token=$token"
Invoke-WebRequest -uri $url -Method POST -Body $JSON -ContentType 'application/json'

Powershell ConvertTo-JSON returning "nested" object

I'm trying to make a POST request to my server. Everything was fine until I decided to convert my object to JSON. Here's my code:
$postParams = #{
Login = "JonSnow66";
Password = "LetItSnow";
Email = "Jon.Snow#wall.com";
Name = "Jon Snow";
Desc = "I know nothing";
BirthDate = "1572 2 16";
Img = Get-Content -Path ./PH_img.txt | Out-String;
Type = "Admin";
}
Invoke-WebRequest -Uri http://localhost:3000/api/add/user -Method POST -Body (ConvertTo-Json $postParams -Compress)
Instead of returning regular JSON object like:
{
"Login": "JonSnow66"
...
}
It returns:
{{
"Login": "JonSnow66",
"BirthDate": "1572 2 16",
"Desc": "I know nothing",
"Name": "Jon Snow",
"Type": "Admin",
"Password": "LetItSnow",
"Img": "/9j/4<BASE64>/Z\r\n",
"Email": "Jon.Snow#wall.com"
}: ""}
I'm just a powershell beginner.
I think you need to specify ContentType on Invoke-WebRequest to be 'application/json'. If you don't specify a content type and are performing a Post then I think the cmdlet assumes you are submitting a form by default, and that might explain the extra { } characters you are seeing in the result.
Here's the modified code:
Invoke-WebRequest -Uri 'http://localhost:3000/api/add/user' -Method POST -ContentType 'application/json' -Body (ConvertTo-Json $postParams -Compress)

Dynamic Json variable to feed Invoke-Restmethod

I was able to pass the dynamic json object if the object creation code is in single line.
Invoke-RestMethod -ContentType "application/json" -Method Post -Body '{ "name" : "azurefunctionapp2email", "appname": "Applicationnamehere", "requestedBy" : "requestedby", "reqdate" : "requestdate", "status" : "Successfully Deployed", "AppsCount" : "2" }' `
-Uri “https://implementurihere"
Since the dynamic JSON object in real world need be longer, I seperated created with new line and referenced in the above as below. But new line shift causes the json to break. I tried to pipe to ConvertTo-Json function and then found the output to hold '`\r\n' getting introduced:
$body = '{ "name" : "azurefunctionapp2email", `
"appname": "Applicationnamehere", `
"requestedBy" : "requestedby", `
"reqdate" : "requestdate",
"status" : "Successfully Deployed",
"AppsCount" : "2" }' `
Invoke-RestMethod -ContentType "application/json" -Method Post -Body $body `
-Uri “https://implementurihere"
Note: The above works if the $body is single line.
How to approach in such scenarios where we create a dynamic json , long file and feed?
Your example doesn't work because the last line containing a backtick which you have to omit.
You could use a here string to define your JSON so you don't need to seperate each line by a backtick:
$body =
#'
{ "name" : "azurefunctionapp2email",
"appname": "Applicationnamehere",
"requestedBy" : "requestedby",
"reqdate" : "requestdate",
"status" : "Successfully Deployed",
"AppsCount" : "2" }
'#
You could also consider to use a PowerShell hashtable to define your object which will allows you to use variables without the need of a format string:
$bodyObject = #{
name = 'azurefunctionapp2email'
appname = 'Applicationnamehere'
requestedBy = 'requestedby'
reqdate = 'requestdate'
status = 'Successfully Deployed'
AppsCount = '2'
}
$bodyObject | ConvertTo-Json