{"id":8163,"date":"2021-02-12T10:30:30","date_gmt":"2021-02-12T15:30:30","guid":{"rendered":"https:\/\/jdhitsolutions.com\/blog\/?p=8163"},"modified":"2021-02-18T09:43:27","modified_gmt":"2021-02-18T14:43:27","slug":"friday-fun-powershell-weather-widget","status":"publish","type":"post","link":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/","title":{"rendered":"Friday Fun: PowerShell Weather Widget"},"content":{"rendered":"\n<p>Recently, someone on Twitter turned me on to an resource that could be used in a PowerShell session to display weather information. This is apparently a well-established and well-regarded source. Once I worked out the basics, I naturally wanted to see what else I could do it with. Here's what I came up with.<\/p>\n\n\n\n<p>Everything I want to talk about today involves consuming a REST API using Invoke-RestMethod. The primary URI, which you can test in your browser is http:\/\/wttr.in. Include a location in the URI like <a href=\"http:\/\/wttr.in\/chicago\" target=\"_blank\" rel=\"noreferrer noopener\">http:\/\/wttr.in\/chicago<\/a>. But it gets better. The API source and documentation can be found at <a href=\"https:\/\/github.com\/chubin\/wttr.in\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/github.com\/chubin\/wttr.in<\/a>. Once I spent a little time researching what I could do, I settled on a basic command like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Invoke-RestMethod -Uri http:\/\/wttr.in\/Syracuse?format=2 -UseBasicParsing -DisableKeepAlive<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1001\" height=\"110\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png\" alt=\"\" class=\"wp-image-8164\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png 1001w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic-300x33.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic-768x84.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic-850x93.png 850w\" sizes=\"auto, (max-width: 1001px) 100vw, 1001px\" \/><\/a><\/figure>\n\n\n\n<p>I thought that was pretty cool. Although the emojis only display in a terminal console that supports them, like a PowerShell session running in Windows Terminal. You'll have less luck running this in the PowerShell ISE or a VS Code console. <\/p>\n\n\n\n<p>Now I need to push this concept.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Formatting the Location<\/h2>\n\n\n\n<p>It was simple enough to build a quick script to run this command. I even added a location parameter. The location can be a ZIP code or place name. I was hoping to create output that included the location. But I wanted to make sure the location was properly formatted.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">if&nbsp;($Location&nbsp;-match&nbsp;'^([a-zA-Z\\s\\.\\,])+$')&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;$Location&nbsp;=&nbsp;[System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ToTitleCase($location.tolower())\n}<\/code><\/pre>\n\n\n\n<p>If the location is a string, like \"chicago\",  this snippet of text will convert it to \"Chicago\".  A string like \"las vegas\"   becomes \"Las Vegas\".<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using the Local Time<\/h2>\n\n\n\n<p>As I was developing my code, I was including the current date and time. But then I realized that if I was running my script for another location, like Las Vegas, displaying my time in the Eastern time zone, might be confusing. I needed to get the time zone for the location so that I could adjust the time accordingly.<\/p>\n\n\n\n<p>I couldn't find anything in the basic wttr.in request that would include that information until I came across the optional v2 API. The format looks like <a href=\"http:\/\/v2.wttr.in\/chicago\" target=\"_blank\" rel=\"noreferrer noopener\">http:\/\/v2.wttr.in\/chicago<\/a>. Unfortunately, there is no way to get the result as structured data like JSON or XML. So I had to resort to a regular expression to parse out the time zone name. I built a helper function to do that.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Function&nbsp;GetTZ&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;Param([string]$location)\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Getting&nbsp;v2&nbsp;data&nbsp;from&nbsp;wttr.in&nbsp;for&nbsp;$location\"\n&nbsp;&nbsp;&nbsp;&nbsp;$tmp&nbsp;=&nbsp;Invoke-RestMethod&nbsp;-uri&nbsp;\"http:\/\/v2.wttr.in\/$location\"&nbsp;-disableKeepAlive&nbsp;-useBasicParsing\n&nbsp;&nbsp;&nbsp;&nbsp;$rx&nbsp;=&nbsp;[System.Text.RegularExpressions.Regex]::new(\"\\b([a-z_]+\\\/[a-z_]+)\\b\",\"IgnoreCase,Multiline\")\n&nbsp;&nbsp;&nbsp;&nbsp;$timezone&nbsp;=&nbsp;$rx.match($tmp).Value\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Detected&nbsp;timezone&nbsp;$timezone\"\n&nbsp;&nbsp;&nbsp;&nbsp;$timezone\n}<\/code><\/pre>\n\n\n\n<p>This will give me a value like America\/Chicago. The next step is to determine the timezone offset. Fortunately, I had another code snippet that uses a REST API at <a href=\"http:\/\/worldtimeapi.org\" target=\"_blank\" rel=\"noreferrer noopener\">http:\/\/worldtimeapi.org<\/a>. With this API, I create a custom object.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"105\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata-1024x105.png\" alt=\"\" class=\"wp-image-8166\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata-1024x105.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata-300x31.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata-768x78.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata-1536x157.png 1536w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata-850x87.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/tzdata.png 1938w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>My custom object includes the local time in that time zone which I can then use in my output.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Make It Pretty with ANSI<\/h2>\n\n\n\n<p>The last step was to make it pretty. I wanted to draw colored line box around the weather and location information using ANSI and special characters. Normally, this isn't too difficult because I can calculate line lengths. <\/p>\n\n\n\n<p>However, there is a little challenge with emoji-strings. Even though PowerShell might show identical length for two different locations, if the weather emoji was different it could throw off the spacing. This meant my closing | for the line with the weather might be off.  I have not found a way to account for kerning issues when using emojis, so I resorted to using Write-Host.<\/p>\n\n\n\n<p>With this approach, I could save the cursor position of the previous line, display the weather line, move the cursor, and then display the closing |.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\">Write-Host&nbsp;$line1\nWrite-Host&nbsp;$line2\nWrite-Host&nbsp;$line3a&nbsp;-NoNewline\n<em>#get&nbsp;the&nbsp;cursor&nbsp;position<\/em>\n$pos&nbsp;=&nbsp;$host.ui.RawUI.CursorPosition\n<em>#adjust&nbsp;it<\/em>\n$pos.x&nbsp;=&nbsp;$line1.Length&nbsp;-&nbsp;$boxAnsi.Length&nbsp;-&nbsp;1\n<em>#move&nbsp;the&nbsp;cursor<\/em>\n$host.ui.RawUI.CursorPosition&nbsp;=&nbsp;$pos\n<em>#write&nbsp;the&nbsp;closing&nbsp;box&nbsp;element<\/em>\nWrite-Host&nbsp;$line3b\nWrite-Host&nbsp;$line4<\/code><\/pre>\n\n\n\n<p>I'm not proud of the hack, but it works.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-style-default\"><a href=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/weather-samples.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"905\" src=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/weather-samples-1024x905.png\" alt=\"\" class=\"wp-image-8167\" srcset=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/weather-samples-1024x905.png 1024w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/weather-samples-300x265.png 300w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/weather-samples-768x679.png 768w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/weather-samples-850x751.png 850w, https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/weather-samples.png 1182w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>The ANSI sequences are written to run in Windows PowerShell or PowerShell 7. Here's the complete script.<\/p>\n\n\n\n<pre title=\"Show-WeatherSummary.ps1\" class=\"wp-block-code\"><code lang=\"powershell\" class=\"language-powershell\"><em>#requires&nbsp;-version&nbsp;5.1<\/em>\n\n<em>#&nbsp;see&nbsp;https:\/\/github.com\/chubin\/wttr.in&nbsp;for&nbsp;API&nbsp;information<\/em>\n\n<em>#this&nbsp;must&nbsp;be&nbsp;run&nbsp;in&nbsp;a&nbsp;Windows&nbsp;Terminal&nbsp;session&nbsp;that&nbsp;supports&nbsp;the&nbsp;glyphs<\/em>\n<em>#or&nbsp;use&nbsp;-Force&nbsp;if&nbsp;you&nbsp;know&nbsp;you&nbsp;are.<\/em>\n\n[cmdletbinding()]\nParam([string]$Location&nbsp;=&nbsp;\"Syracuse,NY\",&nbsp;[switch]$Force)\n\nFunction&nbsp;TestWT&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;$parent&nbsp;=&nbsp;Get-CimInstance&nbsp;-ClassName&nbsp;win32_process&nbsp;-Filter&nbsp;\"processid=$pid\"-Property&nbsp;ParentProcessID\n&nbsp;&nbsp;&nbsp;&nbsp;(Get-Process&nbsp;-Id&nbsp;$parent.ParentProcessId).ProcessName&nbsp;-eq&nbsp;\"WindowsTerminal\"\n}\nFunction&nbsp;GetTZ&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;Param([string]$location)\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Getting&nbsp;v2&nbsp;data&nbsp;from&nbsp;wttr.in&nbsp;for&nbsp;$location\"\n&nbsp;&nbsp;&nbsp;&nbsp;$tmp&nbsp;=&nbsp;Invoke-RestMethod&nbsp;-uri&nbsp;\"http:\/\/v2.wttr.in\/$location\"&nbsp;-disableKeepAlive&nbsp;-useBasicParsing\n&nbsp;&nbsp;&nbsp;&nbsp;$rx&nbsp;=&nbsp;[System.Text.RegularExpressions.Regex]::new(\"\\b([a-z_]+\\\/[a-z_]+)\\b\",\"IgnoreCase,Multiline\")\n&nbsp;&nbsp;&nbsp;&nbsp;$timezone&nbsp;=&nbsp;$rx.match($tmp).Value\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Detected&nbsp;timezone&nbsp;$timezone\"\n&nbsp;&nbsp;&nbsp;&nbsp;$timezone\n}\nFunction&nbsp;GetTZData&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;[cmdletbinding()]\n&nbsp;&nbsp;&nbsp;&nbsp;[OutputType(\"pscustomobject\",\"TimeZoneData\")]\n&nbsp;&nbsp;&nbsp;&nbsp;Param(\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Parameter(<em>Position<\/em>&nbsp;=&nbsp;0,&nbsp;<em>Mandatory<\/em>,&nbsp;<em>ValueFromPipeline<\/em>,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>HelpMessage<\/em>&nbsp;=&nbsp;\"Enter&nbsp;a&nbsp;timezone&nbsp;location&nbsp;like&nbsp;Pacific\/Auckland.&nbsp;It&nbsp;is&nbsp;case&nbsp;sensitive.\")]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[string]$TimeZoneArea,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[parameter(<em>HelpMessage<\/em>&nbsp;=&nbsp;\"Return&nbsp;raw,&nbsp;unformatted&nbsp;data.\")]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[switch]$Raw\n&nbsp;&nbsp;&nbsp;&nbsp;)\n&nbsp;&nbsp;&nbsp;&nbsp;Begin&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Starting&nbsp;$($myinvocation.mycommand)\"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$base&nbsp;=&nbsp;\"http:\/\/worldtimeapi.org\/api\/timezone\"\n&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<em>#begin<\/em>\n\n&nbsp;&nbsp;&nbsp;&nbsp;Process&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Getting&nbsp;time&nbsp;zone&nbsp;information&nbsp;for&nbsp;$TimeZoneArea\"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$target&nbsp;=&nbsp;\"$base\/$TimeZoneArea\"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Try&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data&nbsp;=&nbsp;Invoke-RestMethod&nbsp;-Uri&nbsp;$target&nbsp;-DisableKeepAlive&nbsp;-UseBasicParsing&nbsp;-ErrorAction&nbsp;Stop&nbsp;-ErrorVariable&nbsp;e\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Catch&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Throw&nbsp;$e.innerexception\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;($data&nbsp;-AND&nbsp;$Raw)&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elseif&nbsp;($data)&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;($data.utc_offset&nbsp;-match&nbsp;\"\\+\")&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$offset&nbsp;=&nbsp;($data.utc_offset.substring(1)&nbsp;-as&nbsp;[timespan])\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$offset&nbsp;=&nbsp;($data.utc_offset&nbsp;-as&nbsp;[timespan])\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[datetime]$dt&nbsp;=&nbsp;$data.DateTime\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[pscustomobject]@{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PSTypename&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;\"TimeZoneData\"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Timezone&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;$data.timezone\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Abbreviation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;$data.abbreviation\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Offset&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;$offset\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DaylightSavingTime&nbsp;=&nbsp;$data.dst\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;$dt.ToUniversalTime().Addseconds($data.raw_offset)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<em>#&nbsp;(Get-Date&nbsp;($data.datetime&nbsp;-split&nbsp;\"[\\+-]\\d{2}:\\d{2}\")[0])<\/em>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<em>#process<\/em>\n\n&nbsp;&nbsp;&nbsp;&nbsp;End&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Ending&nbsp;$($myinvocation.mycommand)\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<em>#end<\/em>\n\n}&nbsp;<em>#close&nbsp;GetTZData<\/em>\n\n<em>#characters&nbsp;for&nbsp;building&nbsp;a&nbsp;line&nbsp;box<\/em>\n$charHash&nbsp;=&nbsp;@{\n&nbsp;&nbsp;&nbsp;&nbsp;upperLeft&nbsp;&nbsp;=&nbsp;[char]0x250c\n&nbsp;&nbsp;&nbsp;&nbsp;upperRight&nbsp;=&nbsp;[char]0x2510\n&nbsp;&nbsp;&nbsp;&nbsp;lowerRight&nbsp;=&nbsp;[char]0x2518\n&nbsp;&nbsp;&nbsp;&nbsp;lowerLeft&nbsp;&nbsp;=&nbsp;[char]0x2514\n&nbsp;&nbsp;&nbsp;&nbsp;horizontal&nbsp;=&nbsp;[char]0x2500\n&nbsp;&nbsp;&nbsp;&nbsp;vertical&nbsp;&nbsp;&nbsp;=&nbsp;[char]0x2502\n}\n\nWrite-Verbose&nbsp;\"Getting&nbsp;weather&nbsp;summary&nbsp;for&nbsp;$location\"\n\n<em>#ANSI&nbsp;sequences<\/em>\n$boxAnsi&nbsp;=&nbsp;\"$([char]0x1b)[38;5;11m\"\n$closeAnsi&nbsp;=&nbsp;\"$([char]0x1b)[0m\"\n$textAnsi&nbsp;=&nbsp;\"$([char]0x1b)[38;5;191m\"\n\n<em>#convert&nbsp;location&nbsp;to&nbsp;title&nbsp;case&nbsp;if&nbsp;it&nbsp;is&nbsp;words<\/em>\nif&nbsp;($Location&nbsp;-match&nbsp;'^([a-zA-Z\\s\\.\\,])+$')&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;$Location&nbsp;=&nbsp;[System.Globalization.CultureInfo]::CurrentCulture.TextInfo.ToTitleCase($location.tolower())\n}\nif&nbsp;($Force&nbsp;-OR&nbsp;(TestWT))&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;$w&nbsp;=&nbsp;Invoke-RestMethod&nbsp;-Uri&nbsp;\"http:\/\/wttr.in\/{$location}?format=2\"\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Verbose&nbsp;\"Getting&nbsp;local&nbsp;time&nbsp;settings&nbsp;for&nbsp;$Location\"\n&nbsp;&nbsp;&nbsp;&nbsp;$localtime&nbsp;=&nbsp;gettzdata&nbsp;(gettz&nbsp;$location)\n&nbsp;&nbsp;&nbsp;&nbsp;[string]$date&nbsp;=&nbsp;&nbsp;\"{0:g}\"&nbsp;-f&nbsp;$localtime.time\n\n&nbsp;&nbsp;&nbsp;&nbsp;$data&nbsp;=&nbsp;($w.trim())&nbsp;-replace&nbsp;\"\\s+\",\"&nbsp;\"\n&nbsp;&nbsp;&nbsp;&nbsp;<em>#internal&nbsp;sum&nbsp;of&nbsp;the&nbsp;individual&nbsp;elements.&nbsp;Trying&nbsp;to&nbsp;figure&nbsp;out&nbsp;kerning&nbsp;or&nbsp;spacing<\/em>\n&nbsp;&nbsp;&nbsp;&nbsp;<em>#$internalLength&nbsp;=&nbsp;$($data.split()&nbsp;|&nbsp;foreach&nbsp;{&nbsp;$_.length}&nbsp;|&nbsp;measure-object&nbsp;-sum).sum<\/em>\n&nbsp;&nbsp;&nbsp;&nbsp;$header&nbsp;=&nbsp;\"&nbsp;{0}\"&nbsp;-f&nbsp;$location\n&nbsp;&nbsp;&nbsp;&nbsp;$headerAnsi&nbsp;=&nbsp;\"{0}{1}\"&nbsp;-f&nbsp;$textAnsi,&nbsp;$header\n&nbsp;&nbsp;&nbsp;&nbsp;$value&nbsp;=&nbsp;\"{0}&nbsp;{1}\"&nbsp;-f&nbsp;$textAnsi,&nbsp;$data\n\n&nbsp;&nbsp;&nbsp;&nbsp;$line1&nbsp;=&nbsp;\"{0}{1}&nbsp;{2}&nbsp;{3}{4}\"&nbsp;-f&nbsp;$boxAnsi,&nbsp;$charHash.upperleft,&nbsp;$date,&nbsp;([string]$charHash.horizontal&nbsp;*&nbsp;($data.length-$date.length)),&nbsp;$charhash.upperRight\n&nbsp;&nbsp;&nbsp;&nbsp;$line2&nbsp;=&nbsp;\"{0}{1}{2}{3}{4}\"&nbsp;-f&nbsp;$boxAnsi,&nbsp;$charHash.Vertical,$headerAnsi.padright($line1.length-1),&nbsp;$boxAnsi,$charHash.Vertical\n&nbsp;&nbsp;&nbsp;&nbsp;$line3a&nbsp;=&nbsp;\"{0}{1}{2}\"&nbsp;-f&nbsp;$boxAnsi,&nbsp;$charHash.Vertical,$value\n&nbsp;&nbsp;&nbsp;&nbsp;<em>#($value.padright($header.length))<\/em>\n\n&nbsp;&nbsp;&nbsp;&nbsp;$line3b&nbsp;=&nbsp;\"{0}{1}\"&nbsp;-f&nbsp;$boxAnsi,$charHash.Vertical\n&nbsp;&nbsp;&nbsp;&nbsp;$line4&nbsp;=&nbsp;\"{0}{1}{2}{3}{4}\"&nbsp;-f&nbsp;$boxAnsi,&nbsp;$charHash.Lowerleft,&nbsp;([string]$charHash.horizontal&nbsp;*&nbsp;($data.length+2)),&nbsp;$charhash.LowerRight,&nbsp;$closeAnsi\n\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Host&nbsp;$line1\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Host&nbsp;$line2\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Host&nbsp;$line3a&nbsp;-NoNewline\n&nbsp;&nbsp;&nbsp;&nbsp;<em>#get&nbsp;the&nbsp;cursor&nbsp;position<\/em>\n&nbsp;&nbsp;&nbsp;&nbsp;$pos&nbsp;=&nbsp;$host.ui.RawUI.CursorPosition\n&nbsp;&nbsp;&nbsp;&nbsp;<em>#adjust&nbsp;it<\/em>\n&nbsp;&nbsp;&nbsp;&nbsp;$pos.x&nbsp;=&nbsp;$line1.Length&nbsp;-&nbsp;$boxAnsi.Length&nbsp;-&nbsp;1\n&nbsp;&nbsp;&nbsp;&nbsp;<em>#move&nbsp;the&nbsp;cursor<\/em>\n&nbsp;&nbsp;&nbsp;&nbsp;$host.ui.RawUI.CursorPosition&nbsp;=&nbsp;$pos\n&nbsp;&nbsp;&nbsp;&nbsp;<em>#write&nbsp;the&nbsp;closing&nbsp;box&nbsp;element<\/em>\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Host&nbsp;$line3b\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Host&nbsp;$line4\nelse&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;Write-Warning&nbsp;\"This&nbsp;needs&nbsp;to&nbsp;be&nbsp;run&nbsp;in&nbsp;a&nbsp;Windows&nbsp;Terminal&nbsp;session.\"\n}\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Next Steps<\/h2>\n\n\n\n<p>I should turn this into a function with an alias to make it easy to run. I might dig deeper into the source files for wttri.in and see if I can't make some of those calls directly. This might make it easier to grab the time zone information at the same time. I might also try adding this to my PowerShell prompt function and display it in a corner of my session.<\/p>\n\n\n\n<p>Give it a try, have some fun, and let me know what you think.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><em>Update<\/em><\/h2>\n\n\n\n<p>I have posted an updated version of this function on GitHub at <a href=\"https:\/\/gist.github.com\/jdhitsolutions\/f2fb0184c2dbab107f2416fb775d462b.\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/gist.github.com\/jdhitsolutions\/f2fb0184c2dbab107f2416fb775d462b. <\/a>This version accepts pipeline input.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently, someone on Twitter turned me on to an resource that could be used in a PowerShell session to display weather information. This is apparently a well-established and well-regarded source. Once I worked out the basics, I naturally wanted to see what else I could do it with. Here&#8217;s what I came up with. Everything&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"New onf the blog: Friday Fun = Building PowerShell Weather Widget with REST, Regex, and ANSI.","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[4,8],"tags":[628,429,534,268,649],"class_list":["post-8163","post","type-post","status-publish","format-standard","hentry","category-powershell","category-scripting","tag-ansi","tag-invoke-restmethod","tag-powershell","tag-regex","tag-rest"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Friday Fun: PowerShell Weather Widget &#8226; The Lonely Administrator<\/title>\n<meta name=\"description\" content=\"Here&#039;s how I built a PowerShell weather widget using REST APIs, ANSI escape sequences, and regular expressions.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Friday Fun: PowerShell Weather Widget &#8226; The Lonely Administrator\" \/>\n<meta property=\"og:description\" content=\"Here&#039;s how I built a PowerShell weather widget using REST APIs, ANSI escape sequences, and regular expressions.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/\" \/>\n<meta property=\"og:site_name\" content=\"The Lonely Administrator\" \/>\n<meta property=\"article:published_time\" content=\"2021-02-12T15:30:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-02-18T14:43:27+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png\" \/>\n<meta name=\"author\" content=\"Jeffery Hicks\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:site\" content=\"@JeffHicks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jeffery Hicks\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/\"},\"author\":{\"name\":\"Jeffery Hicks\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"headline\":\"Friday Fun: PowerShell Weather Widget\",\"datePublished\":\"2021-02-12T15:30:30+00:00\",\"dateModified\":\"2021-02-18T14:43:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/\"},\"wordCount\":741,\"commentCount\":7,\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/02\\\/wttr-basic.png\",\"keywords\":[\"ANSI\",\"Invoke-RestMethod\",\"PowerShell\",\"regex\",\"REST\"],\"articleSection\":[\"PowerShell\",\"Scripting\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/\",\"name\":\"Friday Fun: PowerShell Weather Widget &#8226; The Lonely Administrator\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/02\\\/wttr-basic.png\",\"datePublished\":\"2021-02-12T15:30:30+00:00\",\"dateModified\":\"2021-02-18T14:43:27+00:00\",\"description\":\"Here's how I built a PowerShell weather widget using REST APIs, ANSI escape sequences, and regular expressions.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#primaryimage\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/02\\\/wttr-basic.png\",\"contentUrl\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/02\\\/wttr-basic.png\",\"width\":1001,\"height\":110},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/powershell\\\/8163\\\/friday-fun-powershell-weather-widget\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"PowerShell\",\"item\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/category\\\/powershell\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Friday Fun: PowerShell Weather Widget\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/\",\"name\":\"The Lonely Administrator\",\"description\":\"Practical Advice for the Automating IT Pro\",\"publisher\":{\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/jdhitsolutions.com\\\/blog\\\/#\\\/schema\\\/person\\\/d0258030b41f07fd745f4078bdf5b6c9\",\"name\":\"Jeffery Hicks\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\",\"caption\":\"Jeffery Hicks\"},\"logo\":{\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Friday Fun: PowerShell Weather Widget &#8226; The Lonely Administrator","description":"Here's how I built a PowerShell weather widget using REST APIs, ANSI escape sequences, and regular expressions.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/","og_locale":"en_US","og_type":"article","og_title":"Friday Fun: PowerShell Weather Widget &#8226; The Lonely Administrator","og_description":"Here's how I built a PowerShell weather widget using REST APIs, ANSI escape sequences, and regular expressions.","og_url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/","og_site_name":"The Lonely Administrator","article_published_time":"2021-02-12T15:30:30+00:00","article_modified_time":"2021-02-18T14:43:27+00:00","og_image":[{"url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png","type":"","width":"","height":""}],"author":"Jeffery Hicks","twitter_card":"summary_large_image","twitter_creator":"@JeffHicks","twitter_site":"@JeffHicks","twitter_misc":{"Written by":"Jeffery Hicks","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#article","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/"},"author":{"name":"Jeffery Hicks","@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"headline":"Friday Fun: PowerShell Weather Widget","datePublished":"2021-02-12T15:30:30+00:00","dateModified":"2021-02-18T14:43:27+00:00","mainEntityOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/"},"wordCount":741,"commentCount":7,"publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png","keywords":["ANSI","Invoke-RestMethod","PowerShell","regex","REST"],"articleSection":["PowerShell","Scripting"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/","url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/","name":"Friday Fun: PowerShell Weather Widget &#8226; The Lonely Administrator","isPartOf":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#primaryimage"},"image":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#primaryimage"},"thumbnailUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png","datePublished":"2021-02-12T15:30:30+00:00","dateModified":"2021-02-18T14:43:27+00:00","description":"Here's how I built a PowerShell weather widget using REST APIs, ANSI escape sequences, and regular expressions.","breadcrumb":{"@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#primaryimage","url":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png","contentUrl":"https:\/\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2021\/02\/wttr-basic.png","width":1001,"height":110},{"@type":"BreadcrumbList","@id":"https:\/\/jdhitsolutions.com\/blog\/powershell\/8163\/friday-fun-powershell-weather-widget\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"PowerShell","item":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},{"@type":"ListItem","position":2,"name":"Friday Fun: PowerShell Weather Widget"}]},{"@type":"WebSite","@id":"https:\/\/jdhitsolutions.com\/blog\/#website","url":"https:\/\/jdhitsolutions.com\/blog\/","name":"The Lonely Administrator","description":"Practical Advice for the Automating IT Pro","publisher":{"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jdhitsolutions.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/jdhitsolutions.com\/blog\/#\/schema\/person\/d0258030b41f07fd745f4078bdf5b6c9","name":"Jeffery Hicks","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","url":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg","caption":"Jeffery Hicks"},"logo":{"@id":"https:\/\/secure.gravatar.com\/avatar\/832ae5d438fdcfc1420d720cd1991307927de8a0b12f2342e81c30f773e21098?s=96&d=wavatar&r=pg"}}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":7278,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/7278\/friday-fun-powershell-ascii-art\/","url_meta":{"origin":8163,"position":0},"title":"Friday Fun PowerShell ASCII Art","author":"Jeffery Hicks","date":"February 14, 2020","format":false,"excerpt":"Today's post is definitely on the fun side. In fact, I apologize in advance for the afternoon you are about to blow playing with this code. Those of you of a certain age will recall dial up modems and bulletin boards. Part of the experience was visual. Board operators often\u2026","rel":"","context":"In &quot;Friday Fun&quot;","block_context":{"text":"Friday Fun","link":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/02\/image_thumb-17.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/02\/image_thumb-17.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/02\/image_thumb-17.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2020\/02\/image_thumb-17.png?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":4222,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/4222\/baby-its-cold-outside\/","url_meta":{"origin":8163,"position":1},"title":"Baby, It&#8217;s Cold Outside","author":"Jeffery Hicks","date":"February 16, 2015","format":false,"excerpt":"I don't know about your neck of the woods, but it is downright Arctic here. So I thought I'd polish up my PowerShell function to get weather data. #requires -version 3.0 Function Get-MyWeather { <# .Synopsis Get the weather for a US zip code .Description This command will query the\u2026","rel":"","context":"In &quot;PowerShell&quot;","block_context":{"text":"PowerShell","link":"https:\/\/jdhitsolutions.com\/blog\/category\/powershell\/"},"img":{"alt_text":"weather","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2015\/02\/weather-300x138.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":3140,"url":"https:\/\/jdhitsolutions.com\/blog\/scripting\/3140\/friday-fun-quote-of-the-day-revised\/","url_meta":{"origin":8163,"position":2},"title":"Friday Fun: Quote of the Day Revised","author":"Jeffery Hicks","date":"June 28, 2013","format":false,"excerpt":"This week TrainSignal has been running a contest to celebrate my new PowerShell 3.0 course . All you have to do to win is enter some off-the-wall, silly or non-production use of PowerShell. I've posted a few examples on the TrainSignal blog this week. \u00a0These Friday Fun posts I write\u2026","rel":"","context":"In &quot;Friday Fun&quot;","block_context":{"text":"Friday Fun","link":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},"img":{"alt_text":"talkbubble-v3","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2012\/05\/talkbubble-v3-150x150.png?resize=350%2C200","width":350,"height":200},"classes":[]},{"id":4618,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/4618\/friday-fun-holiday-shopping-with-powershell\/","url_meta":{"origin":8163,"position":3},"title":"Friday Fun: Holiday Shopping with PowerShell","author":"Jeffery Hicks","date":"November 27, 2015","format":false,"excerpt":"Once again, the holiday shopping season is upon us. But perhaps PowerShell can make it a little easier or at least a bit more fun. I'm sure many of you have shopped at NewEgg.com. Perhaps you plan to do so again this year for friends, family or even yourself. So\u2026","rel":"","context":"In &quot;Friday Fun&quot;","block_context":{"text":"Friday Fun","link":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":5132,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/5132\/downloading-git-tips-with-powershell\/","url_meta":{"origin":8163,"position":4},"title":"Downloading Git Tips with PowerShell","author":"Jeffery Hicks","date":"June 27, 2016","format":false,"excerpt":"So I've been sharing a number of PowerShell tools I've created for working with Git, including a few for getting tips from the Git Tips project on GitHub. My initial work was based on the fact that I had a local clone of that repository and wanted to search the\u2026","rel":"","context":"In &quot;Git&quot;","block_context":{"text":"Git","link":"https:\/\/jdhitsolutions.com\/blog\/category\/git\/"},"img":{"alt_text":"getting all online git tips with PowerShell","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2016\/06\/image_thumb-22.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2016\/06\/image_thumb-22.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2016\/06\/image_thumb-22.png?resize=525%2C300 1.5x"},"classes":[]},{"id":3627,"url":"https:\/\/jdhitsolutions.com\/blog\/powershell\/3627\/friday-fun-with-rest-regex-and-replacements\/","url_meta":{"origin":8163,"position":5},"title":"Friday Fun with REST, Regex and Replacements","author":"Jeffery Hicks","date":"January 24, 2014","format":false,"excerpt":"I just love using the web cmdlets that were introduced in PowerShell 3.0. One of the cmdlets I use the most is Invoke-RESTMethod. This isn't because I'm dealing with sites that offer REST-ful services, but rather I like that the cmdlet does all the heavy lifting for me when I\u2026","rel":"","context":"In &quot;Friday Fun&quot;","block_context":{"text":"Friday Fun","link":"https:\/\/jdhitsolutions.com\/blog\/category\/friday-fun\/"},"img":{"alt_text":"computereye","src":"https:\/\/i0.wp.com\/jdhitsolutions.com\/blog\/wp-content\/uploads\/2012\/04\/computereye-150x150.png?resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=8163"}],"version-history":[{"count":0,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/8163\/revisions"}],"wp:attachment":[{"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=8163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=8163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jdhitsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=8163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}