# HTTP requests with PowerShell’s Invoke-WebRequest – by Example

If you ever find yourself on a Windows system needing to make a HTTP request, the Invoke-WebRequest cmdlet will be your friend.

Let’s have a look on how to send various things with iwr (legit alias!) and how to get around common issues. We will be focussing on (manually) sending/requesting data, not so much on reading/parsing it.

In case it’s the first time you’re using Invoke-WebRequest or doing stuff with PowerShell in general, I recommend reading this post sequentially from top to bottom.

I will be using PowerShell 5.1 for this article. You can find your version with $PSVersionTable. As destination we will use several HTTP endpoints from httpbin.org. ## A simple first request Staying with the defaults, this command will translate to the following request: GET /json HTTP/1.1 User-Agent: Mozilla/5.0 (Windows NT; Windows NT 10.0; de-DE) WindowsPowerShell/5.1.17763.316 Host: httpbin.org  What we get back is a HtmlWebResponseObject in a nicely formatted way, displaying everything from (parts) of the body, response headers, length, etc. Let’s store the response in a variable to be able to access the individual parts: ## Accessing parts of the response The content can be accessed with $r.Content. If we want to see what actually came back and was being parsed, we can use $r.RawContent. And, as we can redirect outputs just like in any other shell, we could store the response like this: $r.RawContent > C:\My\Path\to\file.txt


Custom request headers can be set by passing a hash table to Invoke-WebRequest’s -Headers option. The syntax for creating a hash table is as follows:

Let’s make a new request and add some custom headers. We’ll also start using the alias iwr from now on to safe some typing.

Tip: A list of aliases for a cmdlet can be retrieved with Get-Alias -Definition <cmdlet>, in our case Get-Alias -Definition Invoke-WebRequest.

This will produce something like:

GET /headers HTTP/1.1
Accept: application/json
...


Note that if you want to set cookies, you should do so with Invoke-WebRequest’s -WebSession option (see below). Manually including a Cookie HTTP header will not work. The same applies, according to the docs, to the user agent, which should only be set via the -UserAgent option, not via -Headers (in practice, I had no issues setting it via -Headers, though).

Debugging the request headers can be done with a service like httpbin.org (httpbin.org/headers) or simply by sniffing the traffic (e.g. with Wireshark) while making the request. Unfortunately, I am not aware of any way inside PowerShell to retrieve the headers that were actually sent.

## Sending data and setting the content type

To give our request a body, we can either use the -Body option, the -InFile option or use a pipeline. For these examples we will do a POST request, so use -Method 'POST'.

Before actually sending data, let’s talk about the content type. If you do a POST request, but neither specify a Content-Type header nor use the -ContentType option, Invoke-WebRequest will automatically set the content type to application/x-www-form-urlencoded.

More gotchas: when you do set a Content-Type header via -Headers, say application/json; charset=utf8 and then pipe a utf8 file to iwr like so…

… you may not actually send what you expect, as iwr will not read the piped data as utf8.

Depending on the encoding, you may send something like this:

{ "umlauts": "äüö" }


As something like this (ISO-8859-1):

7b 20 22 75 6d 6c 61 75 74 73 22 3a 20 22 e4 fc f6 22 20 7d


7b 20 22 75 6d 6c 61 75 74 73 22 3a 20 22 c3 a4 c3 bc c3 b6 22 20 7d


To be on the safe side, make sure to either use the -InFile option (and specify the -Headers) and/or use a pipeline, but set the -ContentType option (instead of the Content-Type header in the -Headers) the Invoke-WebRequest cmdlet provides:

… will properly send the UTF-8 data.

### Using -Body

If you want to build your body manually in the command, you can use the -Body option:

For posting form data, you can use a hash table (going with the default application/x-www-form-urlencoded here):

When having multiple interactions with an endpoint, you might want to use a session object, for example to capture/send cookies. The Invoke-WebRequest cmdlet provides the option -SessionVariable, which you can give a target variable name to be used later for subsequent requests with the -WebSession option. Since we’re focussing on just manually sending data, let’s rather see, how we can manually create a .NET CookieContainer, add a cookie, and then pass the whole thing to iwr:

This basically just translates to a Cookie: Hello=World header.