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.

[Click on image for larger view.] Figure 1.

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.

[Click on image for larger view.] Figure 2.

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.


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
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;
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 />
<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!
<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  {
Retrieves the weather information using Yahoo weather.  

Retrieves the weather information using Yahoo weather.

City to query weather.

        .PARAMETER State
State to query weather.

Name: Get-YahooWeather
Author: Boe Prox
Created: 27JAN2012
Version History:
- Updated with new Yahoo weather API
- Parameter updates
- Initial creation

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

Gets the current weather for Omaha, NE
Param (
[string]$City = "Omaha",
[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
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.

comments powered by Disqus
Most   Popular