PowerShell Pipeline
Checking the Weather using PowerShell
Get accurate, no fluff weather reports through PowerShell with the use of Web APIs.
Working with PowerShell, we sometimes find ourselves wondering if we can do something that maybe others haven't thought of yet. Other times, we try to do something just because it sounds like fun. In today's article, I am looking at the latter. While I appreciate the great graphics that we see when looking at the weather report on some Web site, there are other times when I just want the information with as little fluff as possible.
Scraping the Web for information is nothing new and I will show you a couple of techniques that will provide a way to get the weather forecast (plus a little more) using PowerShell.
I am going to take advantage of the Yahoo weather APIs to make use of not only finding the weather forecast around my area, but also look at a couple of other items which happen to be available. You can look more at how this API works here.
Here you can see that Yahoo uses their own query language, called YQL (Yahoo Query Language) which is modeled after the SQL query language. Fortunately for us, most of the work has been taken care of. All we need to do is copy their initial code and make a couple of adjustments to allow us to determine the city and state that will be used in the query. I am also going to place this query in the middle of an URI that will be passed to the web site to begin the query. The full URI is shown below:
https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='{0}, {1}')&format=json&env=store://datatables.org/alltableswithkeys
You can see by the {0} and {1} in my bolded query that we will be providing the values later on which will represent the city and state. The text to the right of my query is the Yahoo API site that I will be sending the query to and the text at the end tells the service to send the data back as JSON that we can then use at the end.
With that, let's set up the URI that we will use to send the request to.
$URI = "https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='{0}, {1}')&format=json&env=store://datatables.org/alltableswithkeys" -f 'Omaha','NE'
Yea, that is a long string to throw up, but it is required for the query. If you notice, I added Omaha and NE which represent my city and state that will be included in the YQL query string. Now, next up we can supply this URI when we use the Invoke-RestMethod cmdlet and see what happens.
$Data = Invoke-RestMethod -Uri $URI
Looking at the results of $Data, we see that the JSON object was returned as a PSCustomobject.
This is an object with a lot of other nested objects. We will have to do some digging around in the object to find the data that we need. Fortunately, we are able to locate the weather forecast for Omaha under $Data.query.results.channel.item.forecast.
$Data.query.results.channel.item.forecast|Format-Table
code date day high low text
---- ---- --- ---- --- ----
11 20 Feb 2017 Mon 67 45 Showers
32 21 Feb 2017 Tue 70 34 Sunny
32 22 Feb 2017 Wed 72 41 Sunny
39 23 Feb 2017 Thu 52 37 Scattered Showers
5 24 Feb 2017 Fri 40 26 Rain And Snow
30 25 Feb 2017 Sat 32 19 Partly Cloudy
30 26 Feb 2017 Sun 42 20 Partly Cloudy
30 27 Feb 2017 Mon 47 26 Partly Cloudy
30 28 Feb 2017 Tue 51 30 Partly Cloudy
30 01 Mar 2017 Wed 51 30 Partly Cloudy
Pretty nice, right? That is not all that we have. If we move up a few levels to the channel property, we can see more of what is available within this object.
PS C:\> $Data.query.results.channel
units : @{distance=mi; pressure=in; speed=mph; temperature=F}
title : Yahoo! Weather - Bellevue, NE, US
link : http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather
.yahoo.com/country/state/city-2362026/
description : Yahoo! Weather for Bellevue, NE, US
language : en-us
lastBuildDate : Mon, 20 Feb 2017 07:09 PM CST
ttl : 60
location : @{city=Bellevue; country=United States; region= NE}
wind : @{chill=59; direction=210; speed=11}
atmosphere : @{humidity=71; pressure=971.0; rising=0; visibility=16.1}
astronomy : @{sunrise=7:12 am; sunset=6:4 pm}
image : @{title=Yahoo! Weather; width=142; height=18; link=http://weather.yahoo.com;
url=http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif}
item : @{title=Conditions for Bellevue, NE, US at 06:00 PM CST; lat=41.136471;
long=-95.893013; link=http://us.rd.yahoo.com/dailynews/rss/weather/Country__Co
untry/*https://weather.yahoo.com/country/state/city-2362026/; pubDate=Mon, 20
Feb 2017 06:00 PM CST; condition=; forecast=System.Object[];
description=<![CDATA[<img src="http://l.yimg.com/a/i/us/we/52/28.gif"/>
<BR />
<b>Current Conditions:</b>
<BR />Mostly Cloudy
<BR />
<BR />
<b>Forecast:</b>
<BR /> Mon - Showers. High: 67Low: 45
<BR /> Tue - Sunny. High: 70Low: 34
<BR /> Wed - Sunny. High: 72Low: 41
<BR /> Thu - Scattered Showers. High: 52Low: 37
<BR /> Fri - Rain And Snow. High: 40Low: 26
<BR />
<BR />
<a href="http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https:
//weather.yahoo.com/country/state/city-2362026/">Full Forecast at Yahoo!
Weather</a>
<BR />
<BR />
(provided by <a href="http://www.weather.com" >The Weather Channel</a>)
<BR />
]]>; guid=
Looking at the properties here, I can see a Wind, Atmosphere and Astronomy property which may yield some useful data to have available.
First, let's look at the atmosphere:
PS C:\> $Data.query.results.channel.atmosphere | Format-Table
humidity pressure rising visibility
-------- -------- ------ ----------
71 971.0 0 16.1
Then we can look at the wind readings:
PS C:\> $Data.query.results.channel.Wind | Format-Table
chill direction speed
----- --------- -----
59 210 11
And lastly we can figure out when the sun will rise and set for the day:
PS C:\> $Data.query.results.channel.astronomy | Format-Table
sunrise sunset
------- ------
7:12 am 6:4 pm
Of course, something as cool as this wouldn't be complete without its own function. I already had a function laying around that was no longer working due to an API change at Yahoo. So I made some updates to it and now here it is for everyone to use!
Function Get-YahooWeather {
<#
.SYNOPSIS
Retrieves the weather information using Yahoo weather.
.DESCRIPTION
Retrieves the weather information using Yahoo weather.
.PARAMETER City
City to query weather.
.PARAMETER State
State to query weather.
.NOTES
Name: Get-YahooWeather
Author: Boe Prox
Created: 27JAN2012
Version History:
1.5
- Updated with new Yahoo weather API
- Parameter updates
1.0
- Initial creation
.EXAMPLE
Get-YahooWeather -City Omaha -State NE
Sunrise : 6:58 am
Sunset : 5:50 pm
Temperature : 60°F
Conditions : Cloudy
City : Ottumwa
State : IA
Country : United States
WindChill : 59
WindSpeed : 14
LastUpdated : 2/20/2017 7:38:00 PM
HiTemp : 65°F
LowTemp : 56°F
Description
-----------
Gets the current weather for Omaha, NE
#>
[cmdletbinding()]
Param (
[parameter()]
[string]$City = "Omaha",
[parameter()]
[string]$State = 'NE'
)
$URI = "https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='{0}, {1}')&format=json&env=store://datatables.org/alltableswithkeys" -f $City, $State
Try {
$weather = (Invoke-RestMethod -Uri $URI).query.results.channel
$weatherobject = [pscustomobject]@{
Sunrise = $weather.astronomy.Sunrise
Sunset = $weather.astronomy.Sunset
Temperature = "{0}{1}F" -f $weather.Item.Condition.Temp,[char]176
Conditions = $weather.Item.Condition.Text
City = $City
State = $State
Country = $weather.Location.Country
WindChill = $weather.Wind.Chill
WindSpeed = $weather.Wind.Speed
LastUpdated = [datetime]"$(($weather.LastBuildDate | Select-String -pattern "\w+,\s\d{1,2}\s\w+\s\d{4}\s\d{1,2}:\d{1,2}\s\w{2}").matches[0].value)"
HiTemp = "{0}{1}F" -f $Weather.item.forecast[0].High,[char]176
LowTemp = "{0}{1}F" -f $Weather.item.forecast[0].Low,[char]176
}
$weatherobject.PSTypeNames.Insert(0,"Weather.Info")
Write-Output $weatherobject
}
Catch {
Write-Warning "$($Error[0])"
}
}
You can use it like in the below example to get the weather of the city/state of your choice.
PS C:\> Get-YahooWeather -City Seattle -State WA
Sunrise : 7:7 am
Sunset : 5:40 pm
Temperature : 46°F
Conditions : Showers
City : Seattle
State : WA
Country : United States
WindChill : 41
WindSpeed : 18
LastUpdated : 2/20/2017 5:41:00 PM
HiTemp : 48°F
LowTemp : 43°F
As you can see, there is definitely some fun with working with Web APIs to pull down data, such as weather that you can use for work or for fun!
About the Author
Boe Prox is a Microsoft MVP in Windows PowerShell and a Senior Windows System Administrator. He has worked in the IT field since 2003, and he supports a variety of different platforms. He is a contributing author in PowerShell Deep Dives with chapters about WSUS and TCP communication. He is a moderator on the Hey, Scripting Guy! forum, and he has been a judge for the Scripting Games. He has presented talks on the topics of WSUS and PowerShell as well as runspaces to PowerShell user groups. He is an Honorary Scripting Guy, and he has submitted a number of posts as a to Microsoft's Hey, Scripting Guy! He also has a number of open source projects available on Codeplex and GitHub. His personal blog is at http://learn-powershell.net.