Creating Colorful Weather Report

In the previous tip we explained how you can retrieve weather forecast data using Invoke-WebRequest. This was pure black-and-white text.

To get a colorful report, on Windows 10 you can take advantage of control sequences supported by powershell.exe. Simply run the code below inside a PowerShell console:

$City = 'Hannover'

(Invoke-WebRequest "http://wttr.in/$City" -UserAgent curl).content -split "`n"

By setting the user agent to “curl”, the output includes the color control sequences which in turn are picked up by Windows 10 powershell.exe.

Twitter This Tip! ReTweet this Tip!

Get Weather Forecast

Invoke-WebRequest can easily retrieve web page content for you. If you run it without the –UseBasicParsing parameter, the HTML is even parsed by the Internet Explorer DOM. This way, PowerShell requires just a couple lines of code to retrieve the current weather forecast for almost any city in the world:

$City = 'New York'
$weather = Invoke-WebRequest -Uri "http://wttr.in/$City" 
$text = $weather.ParsedHtml.building.outerText

$text
$text | Out-GridView

A couple of things to note:

  • Out-GridView can only display a fixed number of text lines. To see the complete report, dump $text to the console
  • Invoke-WebRequest requires that the built-in Windows browser has been run and initialized at least once
  • The code above is fragile: once the web site author decides to reorganize the page content, it may no longer work

Twitter This Tip! ReTweet this Tip!

Avoid Read-Host

Do you use Read-Host to receive user input? If you do, rethink. Read-Host always prompts a user, and there is no way to automate scripts that use Read-Host:

$City = Read-Host -Prompt 'Enter City'

A much better easy way would look like this:

param
(
    [Parameter(Mandatory)]$City
)

This creates a mandatory parameter. If the user does not supply it, a prompt is created, very similar to Read-Host. Yet, the user can always submit the parameter to his script and automate it. Just make sure there is only one param() statement, and that it is at the beginning of your script. Use commas to separate multiple parameters.

And if you don’t like the standard prompt produced by param(), check out this:

param
(
    $City = (Read-Host -Prompt 'Enter City')
)

Here, you have full control over the prompting, yet the user can again submit the argument via parameter, and run the script unattended.

Twitter This Tip! ReTweet this Tip!

Using Online Help

PowerShell does not ship with help files, and installing help files locally requires Administrator privileges.

A much easier approach can often be to visit the online help for a cmdlet like this:

Get-Help -Name Get-Acl -Online

This opens a browser and navigates to the online help. Online help often is more up-to-date and easily approachable. It does require internet access, obviously, and there is not always online help available for every cmdlet.

Twitter This Tip! ReTweet this Tip!

Outputting and Assigning at the same time

In the previous tip we talked about logging script results, and how you can assign values and at the same time output the assigned values by using parentheses:

 
PS> ($a = Get-Process -Id $pid)

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1595     102   283200     325444      64,56   6436   1 powershell_ise                                                    



PS> $a

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1595     102   283200     325444      64,75   6436   1 powershell_ise                                                    



PS>  
 

The same can be accomplished by using the –OutVariable common parameter:

 
PS> Get-Process -Id $pid -OutVariable b

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1731     105   290336     341688      66,66   6436   1 powershell_ise                                                    



PS> $b

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1731     105   290336     341688      66,92   6436   1 powershell_ise                                                    



PS>  
 

And Tee-Object is a third approach:

 
PS> Get-Process -Id $pid | Tee-Object -Variable c

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1759     109   292300     343644      71,53   6436   1 powershell_ise                                                    



PS> $c

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1759     109   292300     343644      71,69   6436   1 powershell_ise                                                    



PS>  
 

Since this is using the pipeline, it is much slower. When you avoid the pipeline, performance is better:

 
PS> Tee-Object -InputObject (Get-Process -Id $pid) -Variable d

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1761     111   294568     345268      74,31   6436   1 powershell_ise                                                    



PS> $d

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                       
   1761     111   294568     345268      74,59   6436   1 powershell_ise                                                    



PS>
 

Twitter This Tip! ReTweet this Tip!

Logging Script Output

There are numerous ways to log script output but one especially lazy technique is to run Start-Transcript. In PowerShell 5, this cmdlet is supported in all full hosts, not just powershell.exe, so you can use it in PowerShell ISE or other editors as well. In addition, transcripts can be nested, so when you write a script, you can safely add Start-Transcript at the beginning and Stop-Transcript at the end.

Start-Transcript writes any input and any output to a text file. If you do not specify a path, the cmdlet picks a default path. You just would have to make sure that your script actually produces output that can be logged.

To make your script be more verbose, combine it with another trick: when you place assignments in parentheses, the assignment will also output the assigned data. This output would then be picked up by your transcript. Check it out:

# default assignment, no output
$a = Get-Service
$a.Count

# assignment in parentheses, outputs the assignment
($b = Get-Service)
$b.Count

Twitter This Tip! ReTweet this Tip!