CURL example to Invoke-RestMethod - powershell

I am trying to convert curl command to powershell Invoke-RestMethod
Command from MobileIron (in case someone will google that topic)
curl --user <username>:<password> --header 'Content-Type: application/json' --request PUT 'https://
<mobileiron_core>/api/v2/devices/wakeup?adminDeviceSpaceId=1' --data '{"deviceUuids": ["af0cea8bf56c-
49f5-b615-76cc34936b2f"], "note": "something"}'
Ok, my code (based on https://gist.github.com/rayterrill/e83a1bd877547eccfd59b656e7f91b48#file-mobileiron-addremovelabels-ps1 )
$url = $mi_server + "/api/v2/devices/wakeup?adminDeviceSpaceId=1"
$contentType = "application/json"
$headers = #{
Authorization=("Basic {0}" -f $regase64AuthInfo)
}
$data = #{
note = "test";
deviceUuids = $guid
};
$json = $data | ConvertTo-Json;
Invoke-RestMethod -Method PUT -Uri $url -ContentType $contentType -Headers $headers -Body $data;
But i am getting 400 error - so,as i understand - something wrong with --data , but what ?

MobileIron 400 is a general error: 400 Bad request, Meaning the request was invalid.
The accompanying error message (That follows the the error code) explains the reason.
Can you post the rest of the error message?
You cannot use --data or -Body with a PUT request.
You must make a query string for the data.
The query string must be url encoded.
Because it is HTTPS transfer you may need -k (--insecure)
The PUT request may work, I believe MobileIron prefers GET, There is no real difference between the two. I tested both.
I tried (I did my testing with PHP)
A PUT Request
Request Headers
Content-Type: application/json
Accept: application/json
POST DATA was the same as the Query String
I checked with and without the POST DATA and no change.
I also sent the POST DATA with no query string and it was if not data was sent.
URL and Query
$query = urlencode('{"deviceUuids": ["af0cea8bf56c-49f5-b615-76cc34936b2f"], "note": "something"}');
$url = https://<domain>/api/v2/devices/wakeup? . $query
URL was changed to my server to an app that returns the request header, and parameters.
Which returned this on the server:
Request Headers:
Content-Type: application/json
Accept: application/json
Accept-Encoding: deflate, gzip, br
Expect: 100-continue
Host: mydomain.com
Transfer-Encoding: chunked
The server GET and server REQUEST values
$_GET
array (
'{"deviceUuids":_' =>
array (
'"af0cea8bf56c-49f5-b615-76cc34936b2f"' => '',
),
)
$_REQUEST
array (
'{"deviceUuids":_' =>
array (
'"af0cea8bf56c-49f5-b615-76cc34936b2f"' => '',
),
)
The Request Query
$_SERVER['QUERY_STRING']) (url decoded)
{"deviceUuids": ["af0cea8bf56c-49f5-b615-76cc34936b2f"], "note": "something"}
Notice above the JSON query string was cut off.
But was in the arguments
argv array (url decoded)
0 = {"deviceUuids":
1 = ["af0cea8bf56c-49f5-b615-76cc34936b2f"],
2 = "note":
3 = "something"}
I removed the Content-Type: application/json from the request header and there was no change.
I changed the PUT to GET, no change
When a I started sending the Content=Type: application/json
With a POST request, and no Query String, the POS Data was ONLY in the BODY of the request.
And here are some example requesst from some MobileIron documentation:
The first request was a default GET not a PUT.
curl -u admin_username:admin_password -kv "https://URL_to_your_mobileiron_cloud_environment/api/v1/account?emailAddress=johnnydoe#acme.com&uid=johnnydoe#acme.com&accountSource=Local" -d ''
curl GET -kv -u user:password "https://[mobileiron_cloud]/api/v1/device/57d9903c-aadf-4b40-aef3-e1f24302f180/customattributes”
curl -X POST -kv -u user:password -H 'Content-Type: application/json' -d '{ "attrs" : { "tlark" : [ "1" ] } } ' "https://[mobileiron_cloud]/api/v1/device/22000/customattributes"
curl -X POST -kv -u user:password -H 'Content-Type: application/json' -d '{ "attrs" : { "tlark" : [ "1" ] } } ' "https://[mobileiron_cloud]/api/v1/device/8bcc4cee-dca9-476d-8710-9bb1e738ade9/customattributes"

$param_pam_pam = #{
Method = 'PUT'
Uri = "$url"
ContentType = "application/json"
Headers = #{authorization = ("Basic {0}" -f $regase64AuthInfo) }
Body = #{
deviceUuids = #($guid)
note = "force check-in from $ma"
} | ConvertTo-Json
}
$reg = Invoke-RestMethod #param_pam_pam

Related

Append data to Google Spreadsheet using API and Invoke-RestMethod

I'm doing my first steps with Google API. Currently I have a need to add some data to existing spreadsheet. For some purposes I need to use Invoke-RestMethod instead of any already created modules.
For a test purpose I wanted to add single entry for now. I'm using this code:
$requestUri = "https://sheets.googleapis.com/v4/spreadsheets/$($SpreadsheetID)/values/$("SheetName!A1:F195"):append
$body = #{
range = 'SheetName!A1:F195';
values = #{
'Field1' = 'Test';
'Field2' = 'Test';
'Field3' = 'Test';
'Field4' = 'Test';
'Field5' = 'Test';
'Link' = 'https://test.com'
};
};
$test = ConvertTo-Json -InputObject $body
$response = Invoke-RestMethod -Headers #{Authorization = "Bearer $accessToken"} -Uri $requestUri -Method POST -ContentType 'application/json' -Body $test
As a response, I'm receiving this error 400 - Bad request.
Sheet already containing some data. Field names in my $body variable are exactly same like in spreadsheet. A196 is first empty cell in my spreadsheet. I was kind of expecting that it will just enter those values into that row basically.
I still didn't know what is wrong, so I decided to use Google API Playground. When I filled everything, request looks like this:
POST /v4/spreadsheets/<SpreadsheetID>/values/SheetName!A1:F195:append HTTP/1.1
Host: sheets.googleapis.com
Content-length: 385
Content-type: application/json
Authorization: Bearer <code>
{
'range': 'SheetName!A1:F195',
'values': {
'Field1':'Test',
'Field2':'Test',
'Field3':'Test',
'Field4':'Test',
'Field5':'Test',
'Link':'https://test.com'
}
}
As a response I'm getting this:
"code": 400,
"details": [
{
"fieldViolations": [
{
"field": "data.values",
"description": "Invalid JSON payload received. Unknown name \"Field1\" at 'data.values': Cannot find field."
},
{
"field": "data.values",
"description": "Invalid JSON payload received. Unknown name \"Field1\" at 'data.values': Cannot find field."
},
{
"field": "data.values",
"description": "Invalid JSON payload received. Unknown name \"Field1\" at 'data.values': Cannot find field."
},
{
"field": "data.values",
"description": "Invalid JSON payload received. Unknown name \"Field1\" at 'data.values': Cannot find field."
},
{
"field": "data.values",
"description": "Invalid JSON payload received. Unknown name \"Field1\" at 'data.values': Cannot find field."
},
{
"field": "data.values",
"description": "Invalid JSON payload received. Unknown name \"Link\" at 'data.values': Cannot find field."
}
],
"#type": "type.googleapis.com/google.rpc.BadRequest"
}
]
But I really have not clue what is wrong here. I'm fighting with this some time already, but I'm out of ideas ATM. Appreciate if somebody could point me to correct route.
#EDIT
I find information that while appending, range should cover existing table. However chaning range to A1:F195 gives exactly same error.
Finally! I found some solution by trying different things. Maybe it's not best one, but definitelly one that actually works. The case was that actually $body in specific form. One that worked (at least not displaying same error) was this:
{
'range': 'SheetName!A1:F195',
'values': [
[
'Test',
'Test',
'Test',
'Test',
'Test',
'https://test.com'
]
]
}
So putting values in double square brackets and just values. Using this I was able to get another error in API Playground:
{
"error": {
"status": "INVALID_ARGUMENT",
"message": "'valueInputOption' is required but not specified",
"code": 400
}
}
So after adding ?valueInputOption=USER_ENTERED to $requestUri I was at last able to have row added.
Working code in Powershell looks like this:
$requestUri = "https://sheets.googleapis.com/v4/spreadsheets/$($SpreadsheetID)/values/$("SheetName!A:F"):append?valueInputOption=USER_ENTERED"
$body = #"
{
'range': 'SheetName!A:F',
'values': [
[
'Test',
'Test',
'Test',
'Test',
'Test',
'https://test.com'
]
]
}
"#
$response = Invoke-RestMethod -Headers #{Authorization = "Bearer $accessToken"} -Uri $requestUri -Method POST -ContentType 'application/json' -Body $body
If somebody know other way how $body could be defined to be acceptable by API - I would gladly see this!
#EDIT
Also I have found reason why it wasn't work in first approach. Thanks to more web searching I realized that values in JSON according to documentation is actually array of arrays (which is basically what I "hardcoded" in above example!).
"Correct way" of doing it looks like this:
$requestUri = "https://sheets.googleapis.com/v4/spreadsheets/$($SpreadsheetID)/values/$("SheetName!A:F"):append?valueInputOption=USER_ENTERED"
$body = #{
range = 'SheetName!A:F';
values = #(
,#(
'Test',
'Test',
'Test',
'Test',
'Test',
'https://test.com'
);
);
};
$test = ConvertTo-Json -InputObject $body
$response = Invoke-RestMethod -Headers #{Authorization = "Bearer $accessToken"} -Uri $requestUri -Method POST -ContentType 'application/json' -Body $test

cURL to PowerShell - Value in Square Bracket

I've been struggling with another cURL to PowerShell conversion, specifically with a value in a square bracket.
Background: I am about 1,500 lines into a script that takes CSV import files, consumes it, validates it then converts it into a series of API calls, to automate a process which is done manually. I am doing this as a learning opportunity for myself, as I have never done API work before.
I have this cURL command (from Postman):
curl -X PATCH \
https://example.com \
-H 'Authorization: Bearer 1234567890' \
-H 'Content-Type: application/json' \
-d '{
"data": {
"CID": 1234,
"GroupId": [
31
]
}
}'
My struggle is with the square brackets round the "GroupId".
To convert it to PowerShell, I have done the following:
$URL = "https://example.com"
$Body = #{
'data' = #{
'CID' = $CustomerID;
'GroupId' = $GetGroupID2
}
}
$CurlArgument = '-X', 'PATCH',
'-H', 'Content-Type: application/json',
$URL1,
'-H',
$AuthBearer,
'--retry', '2',
'--retry-delay', '3',
'--retry-connrefused',
'-d',
(($Body | ConvertTo-Json) -replace '"', '\"')
Write-Host "$Section cURL command took" ("{0:n1}" -f (Measure-Command {$PatchGroupResponse = & $CURLEXE #CurlArgument}).TotalSeconds) "Seconds" -ErrorAction SilentlyContinue
Now, PowerShell "hates" the square brackets enclosing "GroupID", so I did the following (Let say $GetGroupID contains 31 (with no quotes. I get this earlier in my script and save it to the variable):
$GetGroupID2 = '['+$GetGroupID+']'
$GetGroupID2 now contains: [31], however when I ConvertTo-Json, I get the extra quotes round my $GetGroupID2, [31] becomes "[31]", I assume from the -replace command but I don't know why/how or how to stop it.
My #CurlArgument looks like this:
-X
PATCH
-H
Content-Type: application/json
https://example.com
-H
Authorization: Bearer 1234567890
--retry
2
--retry-delay
3
--retry-connrefused
-d
{
\"data\": {
\"CID\": 1234,
\"GroupId\": \"[31]\"
}
My call to the server is failing with:
{"Missing Argument, Argument Name = CID"}.
From what I can see, everything looks the same as my cURL command, except the extra quotes round my GroupID of "[31]" (should be [31]).
Can anyone give me any pointers as to why the extra quotes appear round the [31]?
By doing this: $GetGroupID2 = '['+$GetGroupID+']' you are creating a string [31] and therefore the value gets quoted by the ConvertTo-Json cmdlet.
In fact, it should be output as the single element of an array, so if you do this instead:
'GroupId' = #($GetGroupID2)
you are forcing the GroupId value to be an array, so the output will be like this:
"data": {
"CID": 1234,
"GroupId": [
31
]
}

Syntax for groovy to duplicate PowerShell Invoke-RestMethod

I'm trying to duplicate the PowerShell Invoke-RestMethod to something similar in Groovy (groovy is standard we use in our coded pipeline).
I've done a lot of searching without success. I was wondering if I can get some help or suggestions on a possible alternative if there isn't a similar call?
The 3 three lines of PowerShell I'm trying to duplicate in Groovy are:
$tokenrequest = #{ "grant_type" = "password"; "username" = "adminuser"; "password" = "adminpassword" }
$token = Invoke-RestMethod -Uri "http://abcd.com/executionmanager/api/Token" -ContentType application/x-www-form-urlencoded -Headers #{ Authorization = ("OAuth2")} -Method POST -Body $tokenrequest
$token = $token.access_token
there are a lot of libraries to do that
the following one quite unknown
//download dependency from maven repository
#Grab(group='acme.groovy', module='acmehttp', version='20180403')
import groovyx.acme.net.AcmeHTTP
def ctx = AcmeHTTP.post(
url: "https://httpbin.org/post", //the url could be used for tests
//define body as map as soon as we are sending it as www-form
body: [ "grant_type": "password", "username": "adminuser", "password": "adminpassword" ],
headers:[
"content-type":"application/x-www-form-urlencoded",
"Authorization": "OAuth2"
],
)
assert ctx.response.code==200
//the url https://httpbin.org/post always returns json
assert ctx.response.contentType =~ "/json"
assert ctx.response.body instanceof Map
println ctx.response.body
//i guess your token should be accessible like this:
//println ctx.response.body.access_token

Corrupt Documents in new DocuSign envelope

I'm doing a POC to demonstrate DocuSign programmatically creating and routing an envelope containing a simple document. I'm using PowerShell and the JSON API. Login and the Create Envelope work without complaint, but the resulting Word doc routed to me for signature contains gibberish. I believe I have the base64 encoding and headers right. Any thoughts about what I'm doing wrong?
The entire POC is pasted below. I've just removed the ID, Password, Integrator Key, etc. Thanks!
function boundry {
[System.Guid]::NewGuid().ToString()
}
###this is the corrected code###
function encodeFile {
param ([string]$fileName)
[System.Convert]::ToBase64String([IO.File]::ReadAllBytes((Resolve-Path $fileName).ProviderPath))
}
function logonParams {
[string] $userName = 'DocuSign user name'
[string] $password = 'DocuSign password'
[string] $integratorKey = 'DocuSign Integrator Key'
#"
{
"Username" : "$userName",
"Password" : "$password",
"IntegratorKey" : "$integratorKey"
}
"#
}
function logon {
[string] $loginURL = 'https://demo.docusign.net/restapi/v2/login_information'
$headers =
#{
"X-DocuSign-Authentication"=$(logonParams);
"accept"="application/json";
"content-type"="application/json";
}
$r = Invoke-WebRequest -uri $loginURL -headers $headers -method GET
$responseInfo = $r.content | ConvertFrom-Json
$baseURL = $responseInfo.loginAccounts.baseURL
#return the base URL for the next call
$baseURL
}
function createEnvelope {
param ([string]$file1,
[string]$baseURL
)
[string]$boundry = boundry
$headers =
#{
"X-DocuSign-Authentication"=$(logonParams);
"accept"="application/json";
"content-type"="multipart/form-data; boundary=$boundry";
}
[string]$formData = #"
--$boundry
Content-Type: application/json
{
"status":"sent",
"emailBlurb":"Please sign.",
"emailSubject": "Contract $(date)",
"documents": [{
"name": "$file1",
"documentId":"1",
"order":"1"
}],
"recipients": {
"signers" : [{
"email": "recipient#somecompany.com",
"name": "Recipient Name",
"recipientId":"1",
}]
}
}
--$boundry
Content-Type: application/msword
Content-Transfer-Encoding: base64
Content-Disposition: file; filename="$file1";documentid=1
$(encodeFile $file1)
--$boundry--
"#
$envelopeURL = "$baseURL/envelopes"
Invoke-WebRequest -uri $envelopeURL -headers $headers -body $formData -method POST
}
$baseURL = logon
createEnvelope "test.doc" $baseURL
Try changing your Content-Type header value. I'm not sure if application/msword works here, I think the proper mime-type for .docx is
application/vnd.openxmlformats-officedocument.wordprocessingml.document
See this previous SO post for a more complete list of mime-types:
What is a correct mime type for docx, pptx etc?
I solved it with assistance from the DocuSign support team. You can enable server side logging in DocuSign which is very helpful. From the old UI (not available in new UI as of June '15) choose Preferences from the dropdown next to your ID/photo. Then select Permissions under Member Options on the left. Check "Enable API Request Logging." After you run your test, the Download API Request Logs button becomes active.
It was pretty clear from the logs that my encoding was wrong. Here's the correct version:
function encodeFile {
param ([string]$fileName)
[System.Convert]::ToBase64String([IO.File]::ReadAllBytes((Resolve-Path $fileName).ProviderPath))
}
I've updated this in the original code with the question so feel free to use it.

LWP::UserAgent SendHub API Issue

SendHub's documentation state to send a post with data and json data.
This is the curl example they gave
Trying to do this with perl and LWP::User Agent but getting either bad request or unauthorized
Do I have the request coded properly?
curl -H "Content-Type: application/json" -X POST --data '{"contacts" : [1111],"text" : "Testing"}' https://api.sendhub.com/v1/messages/?username
require LWP::UserAgent;
my $uri = 'https://api.sendhub.com/v1/messages/?username=MY_USERNAME\&api_key=MY_KEY_NUMBER';
my $json = '{"contacts":[18005551212],"text":"testing"}';
my $req = HTTP::Request->new('POST',$uri);
$req->header('Content-Type' => 'application/json');
$req->content($json);
my $lwp = LWP::UserAgent->new;
my $response=$lwp->request($req);
if ($response->is_success) {
print $response->decoded_content;
}
else {
die $response->status_line;
}
It looks basically OK.
What is the backslash before the ampersand in the URL?
'https://api.sendhub.com/v1/messages/?username=MY_USERNAME\&api_key=MY_KEY_NUMBER'
I think it should be
'https://api.sendhub.com/v1/messages/?username=MY_USERNAME&api_key=MY_KEY_NUMBER'
but if you're getting 401 Unauthorized then it's most likely the request is correct but the user name and key are wrong.