Powershell shrink my URLs please!!!
Grumpy Admin was asked to tidy up a reference section in a document, basically the URL’s were too long and destroyed the table formatting and looked unsightly and unprofessional. The boss had a great Idea, for the 40 or so links to various white papers and best practice guides, that no doubt will be 404’ed by now. He wanted me to shorten the links using either tinyurl or some other url shorting tool to make things neat and tidy.
I am quite a fan of the https://goo.gl/ have been using it for years. Now, it quite easy to cut and paste and generate these short links, but me being me… doing the same operation 40 times, seemed like a job for a script or someone less important perhaps?
Now as with most things, in IT – it is actually quicker to do thing the slow way bone way not the smart way. The time it takes to write and debugging a script. You could do most jobs by hand! But Meh! This actually seemed like an interesting idea.
I liked the idea of solving this problem in PowerShell. I naturally Google to see if there were implementation of this already in PowerShell and yes of course there was. I had a quick look and decided. Yes that the method I would use, let’s see if I can “clean room” the code and produce a similar working example.
So the first thing for me was to find out about the API google has for the their shorten url stuff.
https://developers.google.com/url-shortener/v1/getting_started this URL reveals all the backend we need to know in order to get our script working
POST https://www.googleapis.com/urlshortener/v1/url
Content-Type: application/json
{“longUrl”: “http://www.google.com/”}
So from this we can get some key bits of information, first a POST method that is using JSON (JavaScript Object Notation) is being used and more importantly is An auth token is optional for shorten requests. – This means I don’t have to bother getting an API key or does it lets see as I actually found the answer to this after much grumpy admin cursing at Google!
Bottom line is I can just throw URLs at this web service and get a response – perfect
However, when I built my script I kept getting intermittent responses sometime it would work sometime it wouldn’t return a result I would keep getting this
After looking at it, I determined that the only way I can bypass and ensure results every time I request a short URL from Google. Is to go down the API key route. So I had to go to https://console.developers.google.com/ and create a project to get an API key bah! I create my project and then ensure that only the URL Shortener API is enabled. This will prevent someone using the projects API key elsewhere for other Google Services. So Signing up was easy and painless, I recommend you use your own key at this point but meh! Grumpy Admin doesn’t really care! What the worse you can do, max it the quota out!
Another thing I want to point out at this stage is it might be worth modifying the per user limit requests – I raised this up from 1 to 10 – this makes it more sensible and should mitigate any 403 forbidden errors you would get if you execution is faster.
So I we have done everything we need to do on the Google side of life, we have our API key AIzaSyAC0LjH3qcPbu910GbfBTRm2AhkxwBL85M and we know what we want to achieve, post a restful api command to a web service in JSON format and get the returned short URL and do something with it!
Now I rack my brain on a possible PowerShell command that allows me to send Post methods to the internet….. Ah there you are my friend
Invoke-RestMethod
So once again let’s do the tried and test Get-Help Invoke-RestMethod and we can see all the goodies and knowledge that we need so we can get this working. I construct a command like the following
$key=”AIzaSyAC0LjH3qcPbu910GbfBTRm2AhkxwBL85M”
Invoke-RestMethod -Uri https://www.googleapis.com/urlshortener/v1/url?key=$key –Body ‘{“longUrl”: “http://www.google.com/”}’ -ContentType application/json -Method Post
This was to prove that the syntax for the query works… so now we can use our PowerShell skills to make this in to a more reusable code, as my end goal is I want to pass a CSV file with URLs in it which will then be shortened and then written back to another CSV/txt file. Right let’s get to work!
So I draft my function – ignoring all the syntax of PowerShell commands, grumpy admin doesn’t worry about the Verbs conventions in PowerShell at the moment!
Function Shorten-URL {}
A good start, time for coffee…. next we need to be able to dynamically change the longURL in the JSON that we are going to be passing to Google in the –body portion of our Invoke-RestMethod cmdlet. I tried a few different methods, but the method which I found worked the best and made it easier in my mind to see what is going on was this.
Creating a new object using the New-Object cmdlet… Again do a quick Get-Help and have look and see how you can use it. There is a great property called –NoteProperty, which we will be taking advantage of. So if you Add-Member to this custom object and do a Get-Member you will see that -noteproperty with your custom name and whatever value you gave it!
$link=”http://hazzy.techanarchy.net/”
(New-Object PSObject | Add-Member -Passthru NoteProperty longUrl $link )
Now if you run that you will see your object 🙂 That is all well and good but I need to have that in JSON format in order to be able to send to Google. Again PowerShell comes to my aid with a nice function called – ConvertTo-JSON. So let do this command and see what happens!
$link=http://hazzy.techanarchy.net/
(New-Object PSObject | Add-Member -Passthru NoteProperty longUrl $link )|Convertto-JSON
Output:
{
“longUrl”: “http://hazzy.techanarchy.net/”,
}
Perfect, this is just what we need. So let add this to our little function and make it so that the $link is defined as parameter to our function. In order to get the JSON into the Invoke-RestMethod all I did was throw it in a variable called $toshorten.
function shorten-url {
Param([string]$link)
$key=”AIzaSyAC0LjH3qcPbu910GbfBTRm2AhkxwBL85M”
$toshorten=(new-object PSObject |
Add-Member -Passthru NoteProperty longUrl $link )|convertto-json
$goo=Invoke-RestMethod -Uri https://www.googleapis.com/urlshortener/v1/url?key=$key -Body $toshorten -ContentType application/json -Method Post
return $goo.id
}
As you can see, to help things out, I use the return keyword to pass back the short url as a result. This allows me to do the next things with easy. So I have a working function that shortens urls via Google. Now the original problem was to import a CSV file and then shorten the URLs and then write that back to the other CSV/txt file. This can be done using PowerShell’s very handy Import-CSV and Out-File functions and a simple For Each loop – so my end code and solution to this problem is:-
$urls=Import-Csv c:\test\urls.csv -header “url”
foreach($url in $urls) {
$link=$url.url
$result=”$link ,” + (shorten-url $url.url) |out-file c:\test\output.csv –append
}
This works like a charm, but as with quite a lot of thing I tend to do, I spent more time working out an automatic way of doing/solving the problem, than it would of taken to do the task manually. Meh! Grumpy Admin doesn’t care, the coffee here is free here at work and while I’m learning I’m working, that how it goes right? Better actually finish the job I was given, so I cut and paste my new tiny URLs into the reference document and it looks good… job done!
Hazzy