March 9, 2015

Slow Traffic......

Nothing destroys Grumpy Admins happiness levels, than traffic on a Friday trip home! Set the scene, it’s POETs day, you finish work, you dance happily out of the office and get in to your car, leave the car park and bang! You are almost stationary in traffic! Grrrr

You curse your GPS and you scream at Google Now, for not reporting there traffic on your route home! Dam technology! Well Grumpy Admin is not having any of this! So I decided to spend a bit of time this morning dedicated to solving this problem in Powershell!

Seriously Grumpy Admin wants Powershell to provide him with traffic updates! OK… Grumpy Admin get your head out of the Azure Cloud and back to reality, Powershell doesn’t do that!

Yes your right, and there no good administrative reason, why you want Powershell to be able to report to your servers if a road is close or has traffic or there has been an accident. It not like your server farm, drives to the beach on a Friday afternoon!

Lets look at it a a capability demonstration of Powershell shall we? Instead of it being a lazy and easy way for Grumpy Admin to get traffic reports before he is due to go home!

First lets look at what we want to do at a high level- We want to get data from the internet and parse it depending on criteria and issue results. While I am putting this in to a traffic reporting script, it could actually be really useful.

Let break this simple problem down! Complex problems are far to “complex” for a Monday morning!

So basically the question is. How do we get information from the Internet/ or Webservice (Soap,RSS etc) from within Powershell? I have in previous blogs touched upon the Invoke-WebRequest cmdlet.  Right Lets do a Get-Help Invoke-WebRequest and see what it says!

SYNTAX
Invoke-WebRequest [-Uri] <Uri> [-Body <Object>] [-Certificate <X509Certificate>] [-
CertificateThumbprint <String>] [-ContentType <String>]
[-Credential <PSCredential>] [-DisableKeepAlive] [-Headers <IDictionary>] [-InFile <String>] [-
MaximumRedirection <Int32>] [-Method
<WebRequestMethod>] [-OutFile <String>] [-PassThru] [-Proxy <Uri>] [-ProxyCredential <PSCredential>]
[-ProxyUseDefaultCredentials]
[-SessionVariable <String>] [-TimeoutSec <Int32>] [-TransferEncoding <String>] [-UseBasicParsing]
[-UseDefaultCredentials] [-UserAgent
<String>] [-WebSession <WebRequestSession>] [<CommonParameters>]

DESCRIPTION
The Invoke-WebRequest cmdlet sends HTTP, HTTPS, FTP, and FILE requests to a web page or web service.
It parses the response and returns
collections of forms, links, images, and other significant HTML elements.

This cmdlet was introduced in Windows PowerShell 3.0.

Right so we know quite a few things now about this cmdlet now! – We know that it only runs in Powershell 3.0 and above! And we know there quite a rich syntax for this cmdlet, we can pass PSCredentials and other stuff! Wow very powerful and thought out command!

So we now we can pull data from the internet and get that into Powershell, we just need the data source… but where can we get UK traffic information data for free!! (or not if we are naughty…ssssh) and in more importantly in a format that we can use and take advantage of without much effort.

A quick google and I stumble upon http://www.highways.gov.uk/news/connect/rss-feeds/traffic-
information-rss-feeds/ which seems to answer all my traffic data source issues.

The very friendly Road Cone loving UK Highways Agency provides all this information in an nice RSS feed, even broken down in to regions.

What is an RSS feed at it’s most basic level? It is XML formatted information. That is the data type! XML – So how does powershell handle that – will i have to put in a string and parse it? As writing all that string handling code
would make me very grumpy and be very error prone and be far more effort than it is worth!

No lucky for us, Powershell supports XML as an actual Powershell data type. There are other major data types as well so a quick recap for you is :-

[string]
[char]
[byte]
[int]
[long]
[bool]
[decimal]
[single]
[double]
[DateTime]
[xml]
[array]
[hashtable]

Powershell allows us like in other languages declare what type of data a variable will be holding – So [bool]$result would result in a variable called result which would hold a true or false value. If I then tried to store other data in to that variable it would error like this

bool

As you can see from the table above XML is an valid datatype in Powershell. So we can very simply get the XML from this RSS feed in to a Powershell variable with the following line:-

[xml]$trafficincidents =invoke-webrequest http://hatrafficinfo.dft.gov.uk/feeds/rss/AllEvents/South%20West.xml

So from this we can determine quite a few things :-

1) Grumpy Admin travels along the M5!!! This could be a factor in why he is a Grumpy!
2) We now have a variable call $trafficincidents which is populated with the UK Highway Agencies South West Traffic reporting RSS feed.

Next thing we need to be able to do is to be able extract out of this variable ($trafficincidents) the information that will be useful to us! IE The traffic Reports. The best way to do this is to do a | Get-Member on the $trafficincidents. This will give us all the methods and all the properties of the variable that we can work with!

If you do that – $trafficincidents|get-member – you will see there are a lot of methods of modifying and creating and maniplulating the nodes and items in the XML but only a couple properties. One of these properties is named RSS! Bing – perfect – Now all we need is the structure of the XML, so we can reference it and extract the information . The way I did this was to open the URL and study the structure of the XML, I expect there are other methods but this was quick and dirty and worked for me! After all, I should be doing actual work right?

So I worked out the base structure was :-

$trafficincidents.RSS.channel.item

So then to see the item – all did was type that in and Powershell printed the value out to the console screen! With the screen full of the values of the XML items all in a nice tidy list format. I could see each field had it’s name, so I could further break it down.

$trafficincidents.RSS.channel.item.road

With this technically being objects, we can then send them down pipe line to produce some basic parsing. I wanted to find out about the M5 motorway. And to make me less grumpy the good old UK goverment handily provides a field in the XML called road. This then allows me to construct a statement like this

Where-Object {$_.road -eq “M5”}

So my full script to get current traffic reports on the M5 motorway directly from the Highways Agency currently looks like this

[xml]$trafficincidents =invoke-webrequest http://hatrafficinfo.dft.gov.uk/feeds/rss/AllEvents/South%20West.xml
$trafficincidents.rss.channel.item | Where-Object {$_.road -eq “M5”}

Which will return the full item, if the road is equal to “M5” – which is great but there information in the ITEM that is returned that makes it hard to read, and Grumpy Admin likes his information presented in a useful manner!

So we can once again, use the pipeline and do a | Select on the fields that we want

For me this will be, the title, county, road, pubDate – Excellent we then pipe this to the FL (Format-
List) cmdlet so that it is presented in a nice manner and then the job is done!

[xml]$trafficincidents =invoke-webrequest http://hatrafficinfo.dft.gov.uk/feeds/rss/AllEvents/South%20West.xml
$trafficincidents.rss.channel.item | Where-Object {$_.road -eq “M5”} |select title,county,road,pubDate |FL

As you can see, it is really easy to work with Powershell and XML. This is just 2 lines of code, and
could be made in to a simple function, that allows you to specify the road or any other of the returned
information. I don’t joke, it took longer to find the HA’s RSS feed on the Internet than it did to write the script!

I used traffic incidents as the base here for this example, but there are a million more uses out there – The Invoke-
WebRequest is a very powerfull command and with alot of products in the enterprise having REST api’s for
administration of their products these days, using this command to send commands to things like Backup products means you can have a very rich scripting language like Powershell controlling very many things.

Hazzy