Looping an invoke-RestMethod? - powershell

So I'm trying to automate a process at work which involves hitting SendGrid's API. For a short explanation.. with SendGrid you have Subusers and underneath those Teammates. There is no ready option to search all teammates, so you have to supply a subuser then display all teammates underneath. Rinse, repeat down the line. Well I'd like to automated as best as I can.
So the idea is to collect a teammate email address from then user then dump into a variable all the subusers then loop through those subusers looking for the $email variable.
I've never actually used loops in my scripts over the years so it's new territory for me and combining it with an invoke-restmethod just boggles me. heres what Ive got so far:
$token = 'xxxxxxxxxxxxxxxxxxx'
#First uri is to pull a list of subusers
$uri = "https://api.sendgrid.com/v3/subusers"
#Prompts for target email address
$email = Read-Host "Enter the users email"
$headers1 = #{"Authorization" = "Bearer $token"}
$headers2 = #{"Authorization" = "Bearer $token"
"on-behalf-of" = "$subuser"
}
$subs = Invoke-RestMethod -Method get -uri $uri -headers $headers1
$subarray = $subs | select-object username
foreach ($su in $subarray){
$teamarray = invoke-restmethod -method get -uri "https://api.sendgrid.com/v3/teammates?limit=500&offset=0" -headers $headers2
#$teamarray.gettype()
}
The last line is commented out.. i was trying to find teh type of the $teamarray data but it's giving this error for each loop through the subusers:
invoke-restmethod : {"errors":[{"field":null,"message":"authorization required"}]}
At line:18 char:18
+ ... teamarray = invoke-restmethod -method get -uri "https://api.sendgrid. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod],
WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodComma
nd
This should mean the invoke-restmethod is malformed somehow. Any pointers would be appreciated!

Related

Invoke-RestMethod The underlying connection was closed: An unexpected error occurred on a receive

To Introduce myself : Working as a Power BI Developer with PBI Admin access.
My Powershell script stoped working suddenly and prompting me an error saying the underlying connection was closed. This was all working fine few days back.
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a receive.
At line:25 char:7
Invoke-RestMethod -Method Post -uri $url1 -Headers $authHeader ...
CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExcepti on
FullyQualifiedErrorId:WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Login-PowerBI
$groupid = "Hidden"
$Reportid = "Hidden"
$Folder = "c:\temp\"
$Body = "{`”format`”:`”pdf`”}"
$filename = $Folder + "PowerBIMetrics.pdf"
$StatusCheck=0
$token = Get-PowerBIAccessToken -AsString
$authHeader = #{
"Authorization"= $token
"Content-Type" = "application/json"
}
$url1 = "https://api.powerbi.com/v1.0/myorg/groups/$groupid/reports/$Reportid/ExportTo"
Invoke-RestMethod -Method Post -uri $url1 -Headers $authHeader -body $Body'
I have also tried to look for solution and many of them (Power BI community/ DBA) is saying I need to add extra line of code below before I execute the Invoke-ResMethod command line,
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Unfortunately, I'm getting same error message if i add above line.
I passed in parameters groupId/reportid/body and click "run" but nothing happens, it doesn't give me any result, this was working fine before.
https://learn.microsoft.com/en-us/rest/api/power-bi/reports/export-to-file#code-try-0

Updating text file inside of Google Team Drive using Google Docs API- PowerShell

I have a powershell script currently that pulls in data from a Google Sheet on a team drive and then creates Active Directory users in our environment based on that data. I haven't gotten to fully test this part yet, but don't believe it will cause me any problems.
Where I am having issues is I would like to use a Team-Shared Google Drive Document to contain all of my logging for this automation.
I have had no issues authenticating but cannot seem to get the POST request correct for batchUpdating the document itself. I am able to obtain the revision Id without any problem. I cannot seem to find out where to pass the "batchUpdate" object in my request. I am not worried about where the text is stored on the page once it is added, just looking to add the text to the file.
Documentation:
https://developers.google.com/docs/api/reference/rest/v1/documents/batchUpdate#http-request
Here is how I am obtaining my access token
function Get-Auth{
#Obtains access token for the Google API's
#Runs everytime to ensure there is a fresh access token available to the service account
$refresh_body = #{
client_id='338139966542-qaa4me7l4fs0l1ltl2e6kjidjr9tf3up.apps.googleusercontent.com';
client_secret='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';
refresh_token='1//04GjkX_q30ioyCgYIARAAGAQSNwF-L9IrKggdZo-Pq9E_t3qEbmhHmQe8JVVDW4vaXGoeFiRxxJ5KRu7f7TpQVDsHrwMdmc7Xqn4';
grant_type="refresh_token";
}
#Makes a request to obtain the access token
$refresh_token = Invoke-RestMethod -Uri "https://www.googleapis.com/oauth2/v4/token" -Method POST -Body $refresh_body
$access_token = $refresh_token.access_token
}
Here is where I am attempting to update the document
$document = Invoke-RestMethod -Headers #{Authorization = "Bearer $access_token"} -ContentType "application/json" -Method GET -Uri "https://docs.googleapis.com/v1/documents/1K8_q_VCTWin_s8aVb0D16DNujqA72eravHojMfM9cyo"
$revId = $document.revisionId
$updateObject = {
requests = [
{
insertText= {
text= "The Red Dog Crosses the Road";
endOfSegmentLocation= {
segmentId= ""
}
}
}
]
writeControl= {
requiredRevisionId= $revId;
}
}
Invoke-RestMethod -Headers #{Authorization = "Bearer $access_token"} -ContentType "application/json" -Method POST -Uri "https://docs.googleapis.com/v1/documents/1K8_q_VCTWin_s8aVb0D16DNujqA72eravHojMfM9cyo:batchUpdate" -Body $updateObject
Here is the error I receive when trying to make this request.
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:39 char:1
+ Invoke-RestMethod -Headers #{Authorization = "Bearer $access_token"} ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExceptio
n
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I think I just need to find the correct place to put my batchUpdate object in the request, but I could be completely off. Any help would be much appreciated.
In your script, how about the following modification? I thought that the reason of your issue is due to the value of $updateObject and the request body of -Body $updateObject. In this case, the request body is required to be the string value. I thought that this might be the reason of your issue.
Modified script:
$document = Invoke-RestMethod -Headers #{Authorization = "Bearer $access_token"} -Method GET -Uri "https://docs.googleapis.com/v1/documents/1K8_q_VCTWin_s8aVb0D16DNujqA72eravHojMfM9cyo"
$revId = $document.revisionId
$updateObject = #{
requests = #(
#{
insertText = #{
text = "The Red Dog Crosses the Road";
endOfSegmentLocation = #{
segmentId = "";
}
}
}
)
writeControl = #{
requiredRevisionId = $revId;
}
}
Invoke-RestMethod -Headers #{Authorization = "Bearer $access_token"} -ContentType "application/json" -Method POST -Uri "https://docs.googleapis.com/v1/documents/1K8_q_VCTWin_s8aVb0D16DNujqA72eravHojMfM9cyo:batchUpdate" -Body (ConvertTo-Json -Depth 4 $updateObject)
Note:
When this script is run, I confirmed that the text of "The Red Dog Crosses the Road" is appended to the Google Document.
Reference:
Method: documents.batchUpdate

Powershell v5.1 Invoke-RestMethod Error Parsing Body

I'm a beginner with Powershell who's trying to send a PUT request to Microsoft Azure to create an Application Insights log query. I'm able to get this working in Postman, but not in a powershell script. This is the error that I'm getting when running the script:
Invoke-RestMethod : {"code":"Unexpected character encountered while parsing value: S. Path '', line 0, position 0.","message":"Unexpected character encountered while parsing value: S. Path '', line 0, position 0.","innererror":{"diagnosticcontext":"f2843c54-dad7-49b5-92ab-e1dadd40e145","time":"2020-07-24T19:59:45.7979293Z"}}
At C:\Users\thophan\source\Update-AiLogQueries.ps1:58 char:9
+ Invoke-RestMethod -Method Put -Uri $uri -Header $header -Body ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
From looking at the Microsoft documentation, it looks like it's supposed to be able to take in a hashtable for the body, and I'm quite certain my syntax looks exactly the same as the one from the exameple, so I'm not sure what's going on. Below is an excerpt from my script:
$scope = "shared"
$header = #{
"Authorization" = "Bearer $token"
}
$uri = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$rgName/providers/microsoft.insights/components/$aiName/analyticsItems/item?api-version=2020-02-02-preview"
$difference = Compare-Object -ReferenceObject $localQueryList.value -DifferenceObject $response
if ($difference -ne $null)
{
$difference.ForEach(
{
$body = #{
Scope = $scope
Type = "query"
Name = $_.InputObject.Name
Content = $_.InputObject.Content
}
Invoke-RestMethod -Method Put -Uri $uri -Header $header -Body $body
})
}
UPDATE: Here is the documentation that I was looking at, as requested.
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-5.1
The API requires that the body be a JSON string. You can do a simple conversion (using ConvertTo-Json) in your Invoke-RestMethod command and set the content type accordingly.
Invoke-RestMethod -Method Put -Uri $uri -Header $header -Body ($body | ConvertTo-Json) -ContentType 'application/json'

Missing API key when making API RestMethod Call After HTTP Basic authentication in Mailchimp

In PowerShell, I was able to log in using HTTP Basic authentication For Mail Chimp.
$acctname = 'thisismyusername'
$password = 'thisismyapikey'
$params = #{
Uri = 'https://us14.api.mailchimp.com/3.0/';
Method = 'Get'; #(or POST, or whatever)
Headers = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($acctname):$($password)"));} #end headers hash table
} #end $params hash table
$var = Invoke-RestMethod #params
$var
When I try to get basic info on list thats id is "d3a7a4432d".
$URL = "https://us14.api.mailchimp.com/3.0/"
$Endpoint = "/lists/d3a7a4432d"
$URLMailChimp = "$URL$Endpoint"
$gist = Invoke-RestMethod -Method Get -Uri $URLMailChimp
I get this error message:
Invoke-RestMethod : {
"type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/",
"title":"API Key Missing",
"status":401,
"detail":"Your request did not include an API key.",
"instance":""
}
At line:7 char:9
+ $gist = Invoke-RestMethod -Method Get -Uri $URLMailChimp
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I don't understand how to pass it my API key again. I thought by logging it it solved the issue.
I don't use MailChimp, but unless the first invocation provides you with an access token (and the documentation as well as your error message don't look like it would) you need to provide the authentication header with every request.
$acctname = 'thisismyusername'
$password = 'thisismyapikey'
$URL = 'https://us14.api.mailchimp.com/3.0/'
$listID = 'd3a7a4432d'
$auth = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${acctname}:${password}"))}
$gist = Invoke-RestMethod -Method Get -Uri "$URL/lists/$listID" -Headers $auth

Running PowerShell code in powershell works, executing as .ps1 doesn't

I wrote some code which tries to Get a value from one Rest API and post it to another.
I have the code saves in a .ps1 file. If I edit it and run it (or just copy and paste it into an empty PowerShell terminal) it does what I expect. However when I try to run the same .ps1 file directly I get an error on the 2nd Invoke-RestMethod.
Don't understand why I'm getting a different result and the error message not giving me many clues.
What am I doing wrong?
The code I am using is (with modified API key):
$encoded = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($APIkey+":"))
$headers = #{"Content-Type" = "application/json"; "AUTHORIZATION" = "Basic $encoded"}
$APIkey = "123456789"
$metricId = "123"
$r = Invoke-RestMethod -Uri https://coinbase.com/api/v1/currencies/exchange_rates
$metric = [PSCustomObject]#{
value = [Math]::Round($r.btc_to_eur, 2)
}
$baseuri = "https://api.numerousapp.com/v1/metrics/$metricId/events"
$data = ConvertTo-Json $metric
Invoke-RestMethod -Uri $baseuri -Body $data -Headers $headers -Method Post
And the error message I get when running the .ps1 file is:
Invoke-RestMethod : :
At C:\NumerousBitcoinEur.ps1:13 char:1
+ Invoke-RestMethod -Uri $baseuri -Body $data -Headers $headers -Method Post
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I'm using PowerShell 4.0
$APIkey is being set after it is being used, which must be wrong. It probably works in the console because $APIkey happens to already be set.
If you like (I think it's a good idea), you can add the following to the top of your scripts to catch errors like this one.
Set-StrictMode -Version Latest