Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Getting the Weather Where On Earth

Posted on February 17, 2015February 17, 2015

Yesterday I posted a popular article about using Invoke-WebRequest to get weather conditions. That function used the Yahoo web site but really only worked for US cities. So I also cleaned up and revised another set of advanced PowerShell functions (required PowerShell 3) that can retrieve weather information for probably any location on Earth. The first piece of information you need is your WOEID, or "Where On Earth ID". Here is a function to do just that.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Function Get-Woeid {

<#
.Synopsis
   Retrieve WOEID information
.Description
    Search Yahoo's Geo Places for a WOEID (Where On Earth ID). You can search based on a postal code, or place name. Optionally, you can save the XML results to the pipeline.
.Parameter Search
    A search parameter such as a postal or zip code. You can also use a place name.
.Parameter AsXML
    Write the XML document to the pipeline.
.Example
PS C:\> get-woeid 89101

Country : US
Region  : Nevada
Postal  : 89101
Locale  : Las Vegas
WOEID   : 12795439

.Example
PS C:\> get-woeid -search "H1A0A1"

Region  : Quebec
Postal  : H1A 0A1
WOEID   : 55963829
Locale  : Montreal
Country : CA

.Example
PS C:\> get-woeid "Helsinki, Finland"

Country : FI
Region  : Uudenmaan maakunta
Postal  :
Locale  : Helsinki
WOEID   : 565346
.Example
PS C:\> get-woeid "Helsinki, Finland" | get-weather -unit C


Date              : Mon, 16 Feb 2015 4:49 pm EET
Location          : Helsinki, Finland
Temperature       : -2 C
Condition         : Fair
ForecastCondition : Clear
ForecastLow       : -6 C
ForecastHigh      : -2 C
.Example
PS C:\> [xml]$doc = get-woeid "omaha, ne" -AsXML
PS C:\> $doc.Save("c:\work\omahaid.xml")

The first command gets the raw XML document and the second command writes it to disk. Or you can explore the document interactively.

PS C:\> $doc.query.results.place.timezone

type                          woeid                         #text                       
----                          -----                         -----                       
Time Zone                     56043661                      America/Chicago  
.Inputs
    strings
.Outputs
    custom object
.Link
Invoke-RestMethod
    
.Notes
 NAME:      Get-Woeid
 VERSION:   3.0
 AUTHOR:    Jeffery Hicks
 LASTEDIT:  February 16, 2015
 
 Learn more about PowerShell:
 
Essential PowerShell Learning Resources
#> Param( [parameter(Position=0,Mandatory,ValueFromPipeline, HelpMessage="Enter a place name or postal (zip) code.")] [string[]]$Search, [switch]$AsXML ) Begin { Write-Verbose "Starting $($myinvocation.mycommand)" } Process { foreach ($item in $search) { Write-Verbose "Querying for $search" $uri = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.places%20where%20text%3D'$ITEM'%20limit%201" Write-Verbose $uri [xml]$xml= Invoke-RestMethod -Uri $uri if ($AsXML) { Write-Verbose "Writing XML document" $xml Write-Verbose "Ending function" #bail out since we're done Return } if ($xml.query.results.place.woeid) { Write-Verbose "Parsing XML into an ordered hashtable" $hash = [ordered]@{ WOEID = $xml.query.results.place.woeid Locale = $xml.query.results.place.locality1.'#text' Region = $xml.query.results.place.admin1.'#text' Postal = $xml.query.results.place.postal.'#text' Country = $xml.query.results.place.country.code } Write-Verbose "Writing custom object" New-Object -TypeName PSObject -Property $hash } #if $xml else { Write-Warning "Failed to find anything for $item" } } #foreach } #process End { Write-Verbose "Ending $($myinvocation.mycommand)" } } #end function

To use the function you specify some sort of search criteria such as a postal code or city name.

I saved my WOEID as a variable in my PowerShell profile. This function also uses Invoke-RestMethod. I included a parameter to write an XML document to the pipeline instead in case you want to modify the function and need some help discovering the data. The second function, Get-Weather, uses the WOIED to get the current weather conditions. It too uses Invoke-RestMethod to retrieve the data. The resulting XML document is then parsed out using Select-XML to build an output object.

Function Get-Weather {

<#
.Synopsis
Retrieve weather information from Yahoo.com.
.Description
Using the Yahoo weather APIs, this function will retrieve weather information for the specified WOEID or "Where on Earth ID". If you don't know your WOED, open a web browser and go to http://weather.yahoo.com/. Enter in your zip or postal code. Your WOEID will be the number at the end of the url. 
Or you can use the Get-Woeid function.
    
A custom object is written to the pipeline and you can control how much information is displayed by specifying Basic, Extended or All for the Detail parameter.
    
Basic properties:
    Date,Location,Temperature,Condition,ForecastCondition,ForecastLow, and ForecastHigh. This is the default.
Extended properties:
	Basic properties plus WindChill,WindSpeed,Humidity,Barometer,Visibility,and Tomorrow.
All properties:
	Extended properties plus Sunrise,Sunset,City,Region,Zip,Latitude,Longitude,URL
 
.Parameter Woeid
Your WOEID, or "Where on Earth ID".
.Parameter Unit
Show temperature in Farenheit or Celsius
.Parameter Online
Open the web page in your default browser.
.Parameter AsXML
Write an XML document to the pipeline.
.Example
PS C:> get-weather 12795711

Date              : Mon, 16 Feb 2015 3:51 am PST
Location          : Beverly Hills, CA
Temperature       : 56 F
Condition         : Fair
ForecastCondition : Sunny
ForecastLow       : 55 F
ForecastHigh      : 72 F
.Example
PS C:\> get-weather 12795446 extended

Date              : Mon, 16 Feb 2015 6:56 am PST
Location          : Las Vegas, NV
Temperature       : 52 F
Condition         : Mostly Cloudy
ForecastCondition : Sunny
ForecastLow       : 49 F
ForecastHigh      : 77 F
WindChill         : 52 F
WindSpeed         : 9 mph
Humidity          : 35%
Barometer         : 29.95 in and steady
Visibility        : 10  mi
Tomorrow          : Tue 17 Feb 2015 Sunny Low 49F: High: 70F
.Example
PS C:\> 12795711,12795446,12762736 | Get-Weather -detail all | Format-Table City,Temperature,Condition,Sunrise,Sunset
City          Temperature Condition     Sunrise Sunset 
----          ----------- ---------     ------- ------ 
Beverly Hills 56 F        Fair          6:37 am 5:38 pm
Las Vegas     52 F        Mostly Cloudy 6:26 am 5:21 pm
Syracuse      -3 F        Partly Cloudy 7:01 am 5:34 pm
.Example
PS C:\> get-woeid "Bangor,ME" | get-weather 


Date              : Mon, 16 Feb 2015 9:51 am EST
Location          : Bangor, ME
Temperature       : 5 F
Condition         : Partly Cloudy
ForecastCondition : Partly Cloudy/Wind
ForecastLow       : -6 F
ForecastHigh      : 12 F
.Example
PS C:\> get-woeid "Juneau, AK","Miami,FL" | get-weather | Select Date,Location,Temperature


Date                                 Location                             Temperature
----                                 --------                             -----------
Mon, 16 Feb 2015 8:54 am AKST        Juneau, AK                           35 F
Mon, 16 Feb 2015 12:53 pm EST        Miami, FL                            75 F
.Inputs
Strings
.Outputs
Custom object
.Link
Invoke-RestMethod

.Link
Get-Woeid
Select-XML
    
.Notes
 NAME:      Get-Weather
 VERSION:   3.0
 AUTHOR:    Jeffery Hicks
 LASTEDIT:  February 16, 2015

 Learn more about PowerShell:
 
Essential PowerShell Learning Resources
**************************************************************** * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED * * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF * * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, * * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. * **************************************************************** #> [cmdletbinding(DefaultParameterSetName="detail")] Param( [Parameter(Position=0,Mandatory,HelpMessage="Enter a WOEID value", ValueFromPipeline, ValueFromPipelineByPropertyName )] [ValidateNotNullorEmpty()] [string[]]$woeid, [Parameter(Position=1,ParameterSetName="detail")] [ValidateSet("Basic","Extended","All")] [String]$Detail="Basic", [ValidateSet("f","c")] [String]$Unit="f", [Parameter(ParameterSetName="online")] [Switch]$Online, [Parameter(ParameterSetName="xml")] [Switch]$AsXML ) Begin { Write-Verbose "Starting $($myinvocation.mycommand)" #define property sets $BasicProp=@("Date","Location","Temperature","Condition","ForecastCondition", "ForecastLow","ForecastHigh") $ExtendedProp=$BasicProp $ExtendedProp+=@("WindChill","WindSpeed","Humidity","Barometer", "Visibility","Tomorrow") $AllProp=$ExtendedProp $AllProp+=@("Sunrise","Sunset","City","Region","Latitude", "Longitude","ID","URL") #unit must be lower case $Unit=$Unit.ToLower() Write-Verbose "Using unit $($unit.toLower())" #define base url string [string]$uribase = "http://weather.yahooapis.com/forecastrss" Write-Verbose "Base = $uribase" } #begin Process { Write-Verbose "Processing" foreach ($id in $woeid) { Write-Verbose "Getting weather info for woeid: $id" #define a uri for the given WOEID [string]$uri = "{0}?w={1}&u={2}" -f $uribase,$id,$unit if ($online) { Write-Verbose "Opening $uri in web browser" Start-Process -FilePath $uri #bail out since there's nothing else to do. Return } Write-Verbose "Downloading $uri" [xml]$xml= Invoke-WebRequest -uri $uri if ($AsXML) { Write-Verbose "Writing XML document" $xml Write-Verbose "Ending function" #bail out since we're done Return } if ($xml.rss.channel.item.Title -eq "City not found") { Write-Warning "Could not find a location for $id"} else { Write-Verbose "Processing xml" #initialize a new hash table $properties=@{} <# get the yweather nodes yweather information comes from a different namespace so we'll use Select-XML to extract the data. Parsing out all data regardless of requested detail since it doesn't take much effort. Later, only the requested detail will be written to the pipeline. #> #define the namespace hash $namespace=@{yweather=$xml.rss.yweather} $units=(Select-Xml -xml $xml -XPath "//yweather:units" -Namespace $namespace ).node $properties.Add("Condition",$xml.rss.channel.item.condition.text) $properties.Add("Temperature","$($xml.rss.channel.item.condition.temp) $($units.temperature)") #convert Date to a [datetime] object $dt = $xml.rss.channel.item.condition.date.Substring(0,$xml.rss.channel.item.condition.Date.LastIndexOf("m")+1) -as [datetime] $properties.Add("Date",$dt) #get forecast $properties.add("ForecastDate",$xml.rss.channel.item.forecast[0].date) $properties.add("ForecastCondition",$xml.rss.channel.item.forecast[0].text ) $properties.Add("ForecastLow","$($xml.rss.channel.item.forecast[0].low) $($units.temperature)" ) $properties.Add("ForecastHigh","$($xml.rss.channel.item.forecast[0].high) $($units.temperature)" ) #build tomorrow's foreacst $t=$xml.rss.channel.item.forecast[1] $tomorrow="{0} {1} {2} Low {3}{4}: High: {5}{6}" -f $t.day,$t.Date,$t.Text,$t.low, $($units.temperature),$t.high, $($units.temperature) $properties.add("Tomorrow",$tomorrow) #get optional information $properties.Add("Latitude",$xml.rss.channel.item.lat) $properties.Add("Longitude",$xml.rss.channel.item.long) $city=$xml.rss.channel.location.city $properties.Add("City",$city) $region=$xml.rss.channel.location.region $country=$xml.rss.channel.location.country if (-not ($region)) { #if no region found then use country Write-Verbose "No region found. Using Country" $region=$country } $properties.Add("Region",$region) $location="{0}, {1}" -f $city,$region $properties.Add("Location",$location) $properties.Add("ID",$id) #get additional yweather information $wind=(Select-Xml -xml $xml -XPath "//yweather:wind" -Namespace $namespace ).node $astronomy=(Select-Xml -xml $xml -XPath "//yweather:astronomy" -Namespace $namespace ).node $atmosphere=(Select-Xml -xml $xml -XPath "//yweather:atmosphere" -Namespace $namespace ).node $properties.Add("WindChill","$($wind.chill) $($units.temperature)") $properties.Add("WindSpeed","$($wind.speed) $($units.speed)") $properties.Add("Humidity","$($atmosphere.humidity)%") $properties.Add("Visibility","$($atmosphere.visibility) $($units.distance)") #decode rising switch ($atmosphere.rising) { 0 {$state="steady"} 1 {$state="rising"} 2 {$state="falling"} } $properties.Add("Barometer","$($atmosphere.pressure) $($units.pressure) and $state") $properties.Add("Sunrise",$astronomy.sunrise) $properties.Add("Sunset",$astronomy.sunset) $properties.Add("url",$uri) #create new object to hold values $obj= New-Object -TypeName PSObject -Property $properties #write object and properties. Default is Basic Switch ($detail) { "All" { Write-Verbose "Using All properties" $obj | Select-Object -Property $AllProp } #all "Extended" { Write-Verbose "Using Extended properties" $obj | Select-Object -Property $ExtendedProp } #extended Default { Write-Verbose "Using Basic properties" $obj | Select-Object -Property $BasicProp } #default } #Switch } #processing XML } #foreach $id } #process End { Write-Verbose "Ending $($myinvocation.mycommand)" } #end } #end function

You can also change the temperature units.

I wrote these as two separate functions, I suppose I could have nested Get-Woeid inside Get-Weather, although the better option is probably to build a module. I'll leave that for you. The functions are designed to take advantage of pipeline binding so that you can pipe Get-Woeid to Get-Weather.

You can even get weather for multiple locations.

This weather source includes a lot of information so I created a parameter to control how much detail to display. What you see above is basic information. But there is 'extended'.

Or you can see everything with a detail setting of 'all'.

Notice that url at the end? As the cherry on top, you can open the weather forecast in a browser using the Online parameter.

get-woeid 13244 | get-weather -Online

There you have it. No matter where you are you can check the weather. Or look out a window.

Enjoy.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

4 thoughts on “Getting the Weather Where On Earth”

  1. Irwin Strachan says:
    February 17, 2015 at 10:55 am

    What a work of art!!! It has a bit of everything… ValidationSet,ParameterSetName. I love the way you append the properties from Basis to Extended to All. Formating is there also. Last but not least XML and XPath!!! PowerShell at its finest!!! Thanks again!!!

    1. Jeffery Hicks says:
      February 17, 2015 at 11:58 am

      Thanks for the kind words.

  2. DanP. says:
    March 10, 2015 at 12:41 pm

    Seems a bit complex when you have to know the zip or postal code.

    function weather{

    $zip = $args

    $url = “http://www.weather.com/weather/today/l/” + $zip

    start $url

    }

    1. Jeffery Hicks says:
      March 10, 2015 at 4:02 pm

      Sure, but the point was to display the results in PowerShell.

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d