The WSL Onion


Calling powershell.exe from PowerShell inside WSL

The other day I was playing around in WSL with a colleague of mine and we did this:

# We start out in WSL Debian and enter PowerShell Core
marco@box:~$ pwsh
PowerShell 7.2.2
Copyright (c) Microsoft Corporation.

https://aka.ms/powershell
Type 'help' to get help.

# Then we get the major version of the active PowerShell session
PS /home/marco> ($PSVersionTable.PSVersion).Major
7
# Then we call powershell.exe and get a completely different version!
PS /home/marco> (powershell.exe -Command {$PSVersionTable.PSVersion}).Major
5

What, How and Why?

We start with running the command (powershell.exe -Command {$PSVersionTable.PSVersion}).Major. PowerShell Core does not know how to execute this and then passes the powershell.exe -Command {$PSVersionTable.PSVersion} part of the command to it’s host operating system, in this case WSL Debian.

WSL2 Debian then gets powershell.exe -Command {$PSVersionTable.PSVersion} to execute. It tries to find a binary with that name and, as it doesn’t have one, passes the call on to its Windows host.

The Windows host knows powershell.exe is a valid binary, calls and runs it like asked, and returns the result of this call to WSL Debian.1

WSL Debian then passes it back to PowerShell Core which calls .Major on it and produces the output.

Is there any use for this?

Honestly, I can’t think of any use case for this whole chain of events - However, both parts on their own are quite useful concepts to understand and keep in mind when working in such environments.

WSL to Windows Host

For the most part the WSL to Windows host behaves just as expected, it actually looks for an aptly named binary in WSL and if it finds one doesn’t call the host.

# Opens PowerShell as expected
marco@box:~$ powershell.exe

# Let's create a powershell.exe in /usr/bin
marco@box:~$ cp /usr/bin/curl /usr/bin/powershell
# Now invokes curl
marco@box:~$ powershell.exe

You can even alias commands to Windows bound calls

marco@box:~$ alias cmd=cmd.exe
# This now starts cmd.exe
marco@box:~$ cmd

PowerShell Core to Host

All in all it works the same as with WSL to Windows communication, possibly also with other operating systems like MacOS.

See also