Skip to content

Instantly share code, notes, and snippets.

@jdhitsolutions
Created February 18, 2021 14:38
Show Gist options
  • Save jdhitsolutions/f2fb0184c2dbab107f2416fb775d462b to your computer and use it in GitHub Desktop.
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.
#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
@jdhitsolutions
Copy link
Author

@jdhitsolutions
Copy link
Author

image
This version accepts pipeline input.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment