Complex queries with Invoke-RestMethod in Powershell - powershell

I am trying to invoke an API in Powershell with GET requests. I am familiar with filtering the response by sending a Powershell hashtable in the "Body" parameter as"
Invoke-RestMethod -Uri $uri -Body $filters -Headers $headers
But the hashtables only allow me to filter with the equals operator. As the hashtable looks sort of like
$filter = #{id="fl201"; name="john"}
I need to use comparisons other than "equals", more importantly "-ne" and "-like" and so on. I can filter them after I get the response from Invoke-RestMethod but the response will be so huge that the request itself times out. The API is only a middleware between the client and the database and does nothing other than looking for rows that match the values of the fields in the body.
So, is there any way I can do complex filters along with the web request? Thanks in advance.

Related

powershell invoke-webrequest does not work but invoke-restmethod works

I want to get the content of a web page and when I use
$web = Invoke-RestMethod -Uri "https://inkscape.org/"
I will get the content but when I use
$web = Invoke-WebRequest -Uri "https://inkscape.org/"
I won't get anything why it happens?? and what is the difference exactly ??
Simply put, for plain-text or HTML response bodies, the relationship between the (older) Invoke-WebRequest cmdlet and the Invoke-RestMethod cmdlet is as follows with the respect to the default GET method:
# -UseBasicParsing is only needed in *Windows PowerShell*.
(Invoke-WebRequest -UseBasicParsing -Uri "https://inkscape.org/").Content
is the same as:
Invoke-RestMethod -Uri "https://inkscape.org/"
That is:
Invoke-WebRequest returns a response object whose .Content property contains the body of the response, always as text (except if you save the raw body to a file with -OutFile).
For HTML response bodies, Windows PowerShell attempts to also parse the HTML text into an HTML DOM, surfaced via the .ParsedHTML property, using the obsolete Internet Explorer. -UseBasicParsing suppresses this. This switch has no effect in PowerShell (Core) 7+, which fundamentally doesn't support parsing HTML, requiring third-party solutions (see this answer for an example) or - on Windows only - a COM-based solution (see this answer).
Invoke-RestMethod directly returns the response body (only).
Additionally, if the target site indicates that XML or JSON data is being returned, Invoke-RestMethod doesn't return the body as text, but automatically parses it into an [xml] instance / [System.Xml.XmlElement] instances (for RSS / Atom feeds) or a [pscustomobject] graph (ConvertFrom-Json is built in, so to speak).
Even in the absence of a known response data format, PowerShell tries to parse the response body, first as XML, then as JSON; if all attempts fail, plain text (a [string] instance) is returned.
Even for text/html responses an attempt is made to parse them as XML. That is, if a page happens to be valid XML (which is rare these days), you'll get an [xml] instance back; for instance, the very simple HTML5 page at https://httpbin.org/html happens to be valid XML (excluding the <!DOCTYPE html> declaration), whereas HTML5 pages in general are not. Thus, (Invoke-RestMethod https://httpbin.org/html).GetType().FullName returns System.Xml.XmlDocument, i.e. an [xml] instance.

How Do I GET a StreamResponseBody and save it as a ZIP file using Powershell

I am trying to extract a streaming response from a standard http GET call using PowerShell.
I tried to do something like using this Invoke-RestMethod method, such as:
$response = Invoke-RestMethod -Uri $uri -Method GET -Headers $headers -Body
and then tried doing various things like accessing the streaming response in this way:
$Stream.Write($response.Content)
or
$Stream.Write($response.RawContentStream)
but nothing works.
In the end, I found out the following command does both the call and the response along with allowing you to save the result to a file directly. This surprised me because the response is a multipart record that includes headers and other data, not just the chunked file in the stream. But the folks at MS apparently knew that 99% of the time with a chunked reply, the user only wants to save the streamed chunks of data into the file, without the other response header data.
$Response = Invoke-WebRequest #Params -Headers $headers -outfile $TempZipFileName
The key here is using the Invoke-WebRequest call with the -outfile option. This saved me a lot of headache and was super simple to use.

Powershell's Invoke-RestMethod doesn't wait for a response when called in a loop

There's been a few similar posts on this but none quite the same (or they don't describe the issue clearly, if they are the same).
I've got a script which makes one API call using Invoke-RestMethod and then iterates over the result of that call making other calls with values from it. The value substitution etc is fine, and I can see (both by dumping the Uri out with Write-Host, and also from the API logs itself) that the calls are being made successfully.
If I do this:
$team = #{ "id" = 5 }
$response = Invoke-RestMethod -Uri https://theUri/$($team.id) -Headers $header -Method Get
then $response is populated as you'd expect and contains the json response from the API endpoint. Response time is a few hundred milliseconds.
If, on the other hand, I have an array of team objects and do this:
foreach ($team in $teams)
{
$response = Invoke-RestMethod -Uri https://theUri/$($team.id) -Headers $header -Method Get
Write-Host $response
}
then it iterates over the whole of the $teams array and outputs empty values on each of the Write-Host lines (the same occurs no matter what you do with it, I'm just using Write-Host as an example here; sending it to Select-Object etc shows it's still blank).
Is this deliberate? I assume no, because it's mad. I've got a temporary workaround by (yes, it's this awful...) writing out the results of the first Api call to a file, then iterating over that list calling a script that does the subsequent calls without the foreach loop in the script for each row. Is there a better way?
I've tried -DisableKeepAlive - no difference. I've tried setting the -TimeoutSec value to a small number, a big number, etc - no difference. I've tried -OutFile and that writes out a bunch of empty files.
It feels - without any evidence for this - that when called inside the loop it's waiting for the HTTP response (which is a 200) and then not downloading any of the response body.
This is Powershell 7.1.3, btw.
Cheers in advance!

How to convert the code below to a powershell code

how to translate this code, this was taken from The DropBox API Explorer but a don't know how to translate it to a powershell code specifically using Invoke-RestMethod or another way, the thing is that i need list the content of a folder store in dropbox, all this using powershell and security token
POST /2/files/list_folder
Host: https://api.dropboxapi.com User-Agent: api-explorer-client Authorization: Bearer dropbox_token
Content-Type: application/json
{
"path": "/documentos"
}
Note to Asker: This question could be considered low quality as there appears to be little to no research effort. I'm going to leave an answer because it's a fairly simple question. However, questions should avoid asking "Convert this to that language," or "What's the code for a program that does such and such" (or really any other question) without showing a research effort or an attempt to answer your own question. See How to Ask a Good Question
REST API's are easy to work with in PowerShell. You just need to pass an ordered hash table containing the headers and a string containing the body. If the body is a json string, which appears to be the case, you can create an ordered hash table and pipe it to ConvertTo-Json to produce the string.
Use the following:
$BaseAPIPath = "https://replaceWithDropboxBaseApi.com/"
$headers = [ordered]#{
"Host" = "https://api.dropboxapi.com"
"User-Agent" = "api-explorer-client"
"Authorization" = "Bearer dropbox_token"
"Content-Type" = "application/json"
}
$body = [ordered]#{
"path" = "/documentos"
} | ConvertTo-Json
$result = Invoke-RestMethod -Method Post -Header $headers -Body $body -Uri "$BaseAPIPath/2/files/list_folder"
You will need to replace $BaseAPIPath with the path to the dropbox api (as it was not provided in your question).
See Invoke-RestMethod

Invoke-RestMethod: You must write ContentLength bytes to the request stream

I am trying to upload a file to a URL. I have tried both these approaches:
Invoke-RestMethod -Uri $uploadUrl -Method Put -Headers $uploadHdrs -InFile $uploadFilePath
Invoke-RestMethod -Uri $uploadUrl -Method Put -body $uploadFileBody -Headers $uploadHdrs
Error I am getting:
Invoke-RestMethod : You must write ContentLength bytes to the request stream
before calling [Begin]GetResponse.
If I add in the -TransferEncoding param, I get errors from the server saying unsupported.
What can I do to include the content length?
I think you'll need to use a different command, like Invoke-WebRequest or even better call the .NET WebClient.UploadFile() or .UploadData methods directly from PowerShell.
While REST methods might conceptually include uploading files, that doesn't mean that the Invoke-WebRequest command has been tested as supporting your scenario. I'd suggest going lower-level (like WebClient) because we know more scenarios have been tested (by the larger .NET team), and there are a wide variety of methods on WebClient for supporting specific scenarios.
One example you might find helpfull in how to invoke these methods from PowerShell is at https://social.technet.microsoft.com/Forums/windowsserver/en-US/0c268c7e-674c-49bc-9933-a87a95f8f44c/powershell-webclientuploadfile?forum=winserverpowershell
P.S. The message your are getting about the request stream is coming from an even lower level .NET API, but WebClient is simpler to use, should take care of setting ContentLength properly and hopefully is "just right" for your need.