RESTful Web Services with Powershell

Working with a client recently and needed to check connectivity to a web service.  I wanted to make a few HTTP requests. Normally I’d fire up curl and paste a URL with basic auth credentials:

curl -u $USERNAME:$PASSWORD -k https://api.example.com/some/endpoint

But… they were on Windows. No problem, fire up chocolately and install curl

choco install curl

Ah… this server is locked down and no way they’re going to fill out the paperwork (in triplicate) to install .  Someone said that PowerShell has curl installed.  But wait a minute…

Screen Shot 2017-08-18 at 3.21.40 PM

Someone has played a nasty trick on me.

I can’t use curl, but PowerShell has something not quite, but almost entirely unlike curl.  Let’s see what we can do with Invoke-WebRequest.

Ok, so you can call a URL with:

Invoke-WebRequest -Uri https://api.example.com/some/endpoint

It turns out that passing Basic Authentication credentials is trickier. But wait! stackoverflow comes to the rescue(-ish).

You have a -Credential flag, but all that does is open up a Windows dialog to enter them.  Not very automatable. (automatible? odd-tomato-bull?)

Basic authentication is really just an HTTP header:

GET /some/endpoint HTTP/1.1
Authorization: Basic SSBsb3ZlIEtlbHNleSBGb3g=

And the credentials are just a base64 encoded string containing text in the format

username:password

One last thing though, you need to escape the colon in your credentials.  Apparently backtick is the escape character in Powershell:

$credentials = "$username`:$password"

And you can pass an array of headers with Invoke-WebRequest.   (backtick also allows continuation on the next line)

Invoke-WebRequest `
-Uri https://api.example.com/some/endpoint `
-Headers @{ Authorization = "Basic $encodedCredentials" }

So now I’m getting somewhere.

The only step left is to figure out how to Base64Encode with PowerShell.  I’m not sure where I found it, but this will do the trick:

$encodedCredentials = `
[System.Convert]::ToBase64String( `
[System.Text.Encoding]::ASCII.GetBytes($credentials))

Remember folks, only you can prevent github from sharing your credentials.  Use an environment variable, and don’t put your password in powershell your script:

Here’s how you get an environment variable in Powershell

Get-ChildItem Env:USERNAME

Finally, here is my full script:

$username = $(Get-ChildItem Env:USERNAME).value
$password = $(Get-ChildItem Env:PASSWORD).value

$credentials = "$username`:$password"
$encodedCredentials = `
[System.Convert]::ToBase64String( `
[System.Text.Encoding]::ASCII.GetBytes($credentials))

Invoke-WebRequest `
-Uri https://api.example.com/some/endpoint `
-Headers @{ Authorization = "Basic $encodedCredentials" }

But wait, there’s more!

Now that I’ve got my response I can actually use Powershell to parse the JSON response and access it using ConvertFrom-Json.:

Given the following JSON

[{ "contact": { "name": "Aaron Evans", "website": { "url": "http://one-shore.com" }, "blog": { "url": "https://fijiaaron.wordpress.com" } }}]

I could parse it like this:

$response = $(Invoke-WebRequest -Uri "$endpoint" -Headers $headers)
$contacts = $(ConvertFrom-Json -InputObject $response.Content)

Invoke-WebRequest -Uri  $contacts[0].contact.blog.url

Please don’t flood my blog with hits.  I haven’t monetized it yet.

See the whole thing with this gist:

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s