Created
February 18, 2021 14:38
-
-
Save jdhitsolutions/f2fb0184c2dbab107f2416fb775d462b to your computer and use it in GitHub Desktop.
A PowerShell function that displays weather information using the wttr.in REST API.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#requires -version 5.1 | |
<# | |
this must be run in a Windows Terminal or console session that supports the | |
emoji icons or use -Force if you know you are. | |
see https://github.com/chubin/wttr.in for API information | |
This command writes to the host not the PowerShell pipeline. | |
#> | |
Function Show-WeatherSummary { | |
[cmdletbinding()] | |
[alias("shws")] | |
[Outputtype("None")] | |
Param( | |
[Parameter(Position = 0, Mandatory, HelpMessage = "Specify the city or zip code.", ValueFromPipeline)] | |
[ValidateNotNullOrEmpty()] | |
[string]$Location, | |
[Parameter(HelpMessage = "Run the command even if not in the Windows Terminal.")] | |
[switch]$Force | |
) | |
Begin { | |
#region helper functions | |
Function TestWT { | |
# a private helper function to test if running in Windows Terminal | |
$parent = Get-CimInstance -ClassName win32_process -Filter "processid=$pid"-Property ParentProcessID | |
(Get-Process -Id $parent.ParentProcessId).ProcessName -eq "WindowsTerminal" | |
} #close TestWT | |
Function GetTZ { | |
# a private helper function to get the location's time zone | |
Param([string]$location) | |
Write-Verbose "Getting v2 data from wttr.in for $location" | |
$tmp = Invoke-RestMethod -Uri "http://v2.wttr.in/$location"-DisableKeepAlive -UseBasicParsing | |
$rx = [System.Text.RegularExpressions.Regex]::new("\b([a-z_]+\/[a-z_]+)\b", "IgnoreCase,Multiline") | |
$timezone = $rx.match($tmp).Value | |
Write-Verbose "Detected timezone $timezone" | |
$timezone | |
} #close GetTZ | |
Function GetTZData { | |
<# a private helper function to get time zone data | |
Timezone Label Offset DST Time | |
-------- ----- ------ --- ---- | |
America/Chicago CST -06:00:00 False 2/18/2021 8:22:13 AM | |
#> | |
[cmdletbinding()] | |
[OutputType("TimeZoneData")] | |
Param( | |
[Parameter(Position = 0, Mandatory, ValueFromPipeline, | |
HelpMessage = "Enter a timezone location like Pacific/Auckland. It is case sensitive.")] | |
[string]$TimeZoneArea, | |
[parameter(HelpMessage = "Return raw, unformatted data.")] | |
[switch]$Raw | |
) | |
Begin { | |
Write-Verbose "Starting $($myinvocation.mycommand)" | |
$base = "http://worldtimeapi.org/api/timezone" | |
} #begin | |
Process { | |
Write-Verbose "Getting time zone information for $TimeZoneArea" | |
$target = "$base/$TimeZoneArea" | |
Try { | |
$data = Invoke-RestMethod -Uri $target -DisableKeepAlive -UseBasicParsing -ErrorAction Stop -ErrorVariable e | |
} | |
Catch { | |
Throw $e.innerexception | |
} | |
if ($data -AND $Raw) { | |
$data | |
} | |
elseif ($data) { | |
if ($data.utc_offset -match "\+") { | |
$offset = ($data.utc_offset.substring(1) -as [timespan]) | |
} | |
else { | |
$offset = ($data.utc_offset -as [timespan]) | |
} | |
[datetime]$dt = $data.DateTime | |
[pscustomobject]@{ | |
PSTypename = "TimeZoneData" | |
Timezone = $data.timezone | |
Abbreviation = $data.abbreviation | |
Offset = $offset | |
DaylightSavingTime = $data.dst | |
Time = $dt.ToUniversalTime().Addseconds($data.raw_offset) | |
} | |
} | |
} #process | |
End { | |
Write-Verbose "Ending $($myinvocation.mycommand)" | |
} #end | |
} #close GetTZData | |
#endregion | |
#characters for building a line box | |
$charHash = @{ | |
upperLeft = [char]0x250c | |
upperRight = [char]0x2510 | |
lowerRight = [char]0x2518 | |
lowerLeft = [char]0x2514 | |
horizontal = [char]0x2500 | |
vertical = [char]0x2502 | |
} | |
#ANSI sequences | |
#If you change these values you might need to adjust line lengths below | |
$boxAnsi = "$([char]0x1b)[38;5;11m" | |
$closeAnsi = "$([char]0x1b)[0m" | |
$textAnsi = "$([char]0x1b)[38;5;191m" | |
Write-Verbose "Starting $($MyInvocation.MyCommand)" | |
} | |
Process { | |
Write-Verbose "Getting weather summary for $location" | |
#convert location to title case if it is words | |
if ($Location -match '^([a-zA-Z\s\.\,])+$') { | |
if ($location -match "\,") { | |
#split the location assuming anything after the comma is a US State | |
$splitLoc = $location -split "\," | |
$location = "{0},{1}" -f [System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ToTitleCase($splitLoc[0].tolower()), $splitLoc[1].toUpper() | |
} | |
else { | |
$Location = [System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ToTitleCase($location.tolower()) | |
} | |
} | |
if ($Force -OR (TestWT)) { | |
$w = Invoke-RestMethod -Uri "http://wttr.in/{$location}?format=2" | |
Write-Verbose "Getting local time settings for $Location" | |
$localtime = gettzdata (gettz $location) | |
[string]$date = "{0:g}" -f $localtime.time | |
$data = ($w.trim()) -replace "\s+", " " | |
$header = " {0}" -f $location | |
$headerAnsi = "{0}{1}" -f $textAnsi, $header | |
$value = "{0} {1}" -f $textAnsi, $data | |
$line1 = "{0}{1} {2} {3}{4}" -f $boxAnsi, $charHash.upperleft, $date, ([string]$charHash.horizontal * ($data.length - $date.length)), $charhash.upperRight | |
$line2 = "{0}{1}{2}{3}{4}" -f $boxAnsi, $charHash.Vertical, $headerAnsi.padright($line1.length - 1), $boxAnsi, $charHash.Vertical | |
$line3a = "{0}{1}{2}" -f $boxAnsi, $charHash.Vertical, $value | |
$line3b = "{0}{1}" -f $boxAnsi, $charHash.Vertical | |
$line4 = "{0}{1}{2}{3}{4}" -f $boxAnsi, $charHash.Lowerleft, ([string]$charHash.horizontal * ($data.length + 2)), $charhash.LowerRight, $closeAnsi | |
#display the weather summary one line at a time | |
Write-Verbose "Displaying weather summary" | |
Write-Host $line1 | |
Write-Host $line2 | |
Write-Host $line3a -NoNewline | |
#get the cursor position | |
$pos = $host.ui.RawUI.CursorPosition | |
#adjust it | |
$pos.x = $line1.Length - $boxAnsi.Length - 1 | |
#move the cursor so that the box element is aligned | |
$host.ui.RawUI.CursorPosition = $pos | |
#write the closing box element | |
Write-Host $line3b | |
Write-Host $line4 | |
} | |
else { | |
Write-Warning "This needs to be run in a Windows Terminal session." | |
} | |
} #process | |
End { | |
Write-Verbose "Ending $($MyInvocation.MyCommand)" | |
} #end | |
} #close Show-WeatherSummary |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The first version of this code is described at https://jdhitsolutions.com/blog/powershell/8163/friday-fun-powershell-weather-widget/