Test out PowerShell 7 new features in WSL1

Finally, PowerShell 7 is now GA! As a heavy WSL user, I was keen to see how some of its new features will work in WSL1 (Ubuntu 4.4.0-18362-Microsoft). Below are the tests I have done.

Installation in WSL
Download the binary from Github repo to a local folder /usr/share/powershell

sudo wget https://github.com/PowerShell/PowerShell/releases/download/v7.0.0/powershell-7.0.0-linux-x64.tar.gz

Untar the file

sudo tar xzvf powershell-7.0.0-linux-x64.tar.gz

Add path for your shell

export PATH=/usr/share/PowerShell:$PATH

Reload .bashrc

source .bashrc

Remove the tar ball

sudo rm /usr/share/PowerShell/powershell-7.0.0-linux-x64.tar.gz

Run PowerShell 7 by run pwsh

Import Windows Modules in WSL
Install commonly Vendor released modules like VMware PowerCli

Install-Module -Name VMware.PowerCli

Install .Net based modules also works fine.

Install-Package PrtgApi

What about those module require Windows GUI, like Out-GridView? PowerShell 7 on Windows fully support this kind module. But for WSL some tweaks are required.

First Install GraphicalTools

Install-Module Microsoft.PowerShell.GraphicalTools

Tried to run Out-GridView but encountered Exception error.

PS /home/tom>

Unhandled Exception: System.TypeInitializationException: The type initializer for ‘OutGridView.Application.AvaloniaAppRunner’ threw an exception. —> System.Exception: XOpenDisplay failed

   at Avalonia.X11.AvaloniaX11Platform.Initialize(X11PlatformOptions options)

   at Avalonia.Controls.AppBuilderBase`1.Setup()

   at OutGridView.Application.AvaloniaAppRunner.BuildAvaloniaApp() in D:\a\1\s\src\OutGridView.Gui\AvaloniaAppRunner.cs:line 34

   at OutGridView.Application.AvaloniaAppRunner..cctor() in D:\a\1\s\src\OutGridView.Gui\AvaloniaAppRunner.cs:line 31

   — End of inner exception stack trace —

   at OutGridView.Application.Program.Main(String[] args) in D:\a\1\s\src\OutGridView.Gui\Program.cs:line 26

To walk around that, we need to install XServer in Windows. I use VCSXRV downloaded from SourceForge.

The installation of VCSXRV is just click the next buttons.

Keep VCSXRV running and back in WSL, exit pwsh type the command below

export DISPLAY=localhost:0

That’s it!. Let’s test it out

Get-Process | Out-GridView

Walah!!!

ForEach-Object Parallel option
This is another long wanted feature. I remember once I had to create thousands of large files on a hard disc and it was such a pain to wait for the loop to go through each creation process sequentially. With Parallel option, it can potentially save hours of waiting in this case.

Interestingly though, it is not necessarily a silver bullet for shortening your loop’s excution time. Let me show you some test results.

Parallel option slows the script

PS /home/tom/powershell/foo> measure-command {get-vm|foreach {$filename = $_.Name; New-Item $filename;Set-Content .\$filename “this is bunch of blah blah blah…..” }}

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 1

Milliseconds      : 16

Ticks             : 10161391

TotalDays         : 1.1760869212963E-05

TotalHours        : 0.000282260861111111

TotalMinutes      : 0.0169356516666667

TotalSeconds      : 1.0161391

TotalMilliseconds : 1016.1391

PS /home/tom/powershell/foo> measure-command {get-vm|foreach -parallel {$filename = $_.Name; New-Item $filename;Set-Content .\$filename “this is bunch of blah blah blah…..” }}

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 12

Milliseconds      : 234

Ticks             : 122341726

TotalDays         : 0.000141599219907407

TotalHours        : 0.00339838127777778

TotalMinutes      : 0.203902876666667

TotalSeconds      : 12.2341726

TotalMilliseconds : 12234.1726

As you can see, in this case the Parallel option actually makes the whole script slower, a lot slower. Why is that? The new ForEach-Object -Parallel parameter set uses existing PowerShell APIs for running script blocks in parallel. These APIs have been around since PowerShell v2, but are cumbersome and difficult to use correctly. This new feature makes it much easier to run script blocks in parallel. But there is a fair amount of overhead involved.

In our case, as the code calls to create a file is simple, putting the loop into Parallel adds a lot overhead and prolongs the running time of the script.

Parallel option improves performance
Now let’s add a wait condition into the code.

PS /home/tom/powershell/foo> measure-command {get-vm|ForEach-Object -parallel {$filename = $_.Name; New-Item $filename;Set-Content .\$filename “this is bunch of blah blah blah…..";sleep 1}}

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 35

Milliseconds      : 741

Ticks             : 357414908

TotalDays         : 0.000413674662037037

TotalHours        : 0.00992819188888889

TotalMinutes      : 0.595691513333333

TotalSeconds      : 35.7414908

TotalMilliseconds : 35741.4908

PS /home/tom/powershell/foo> measure-command {get-vm|ForEach-Object {$filename = $_.Name; New-Item $filename;Set-Content .\$filename “this is bunch of blah blah blah…..";sleep 1}}

Days              : 0

Hours             : 0

Minutes           : 2

Seconds           : 9

Milliseconds      : 848

Ticks             : 1298486786

TotalDays         : 0.00150287822453704

TotalHours        : 0.0360690773888889

TotalMinutes      : 2.16414464333333

TotalSeconds      : 129.8486786

TotalMilliseconds : 129848.6786

By adding sleep 1, each loop excution takes at least 1 second. This significantly increased the duration of the whole script. In this case the even with the overhead of Parallel, it is still beneficial to use the option.