Skip to content

Add side-by-side support to pwsh.exe #202

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 29, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 253 additions & 0 deletions X-Rejected/RFC0038-Side-By-Side-Support
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
---
RFC: RFC0038
Author: Kirk Munro
Status: Rejected
SupercededBy: none
Version: 0.1
Area: CLI, SDK
Comments Due: July 21, 2019
Plan to implement: Maybe
---

# Side-by-side support in PowerShell 7 and later

Historically, upgrading Windows PowerShell meant replacing your existing
version with a newer version. The were only two notions of side-by-side support
with Windows PowerShell:

1. Support for running `powershell.exe -version 2` in Windows PowerShell
versions 3.x-5.x. That wasn't quite the same as running PowerShell version 2
though, because your modules that were installed by default and not available
in the PowerShell Gallery may not be compatible with version 2 and therefore
couldn't load.
1. Support for installing multiple versions of modules side-by-side and
importing the version that you needed in Windows PowerShell version 3.x-5.x.

Unfortunately, there are many scenarios where upgrading Windows PowerShell
isn't an option for users, such as:

1. When you are using a product that has a dependency on a specific version
of PowerShell.
1. When you have automation scripts or other management solutions that have a
dependency on a specific version of PowerShell.

In order to keep systems and management processes running the way they must in
an enterprise, many users have no choice but to stick with a downlevel version
of Windows PowerShell for a very long time. There are even some organizations
still using PowerShell version 2 today!

All of this has lead to much of the community pushing hard for downlevel
support for updates via modules as much as possible so that they can use the
new features and functionality in older versions of PowerShell. The serious
downside to that approach is that modules that offer downlevel support have to
be designed for downlevel versions, perhaps opting in to additional
functionality with logic that checks for specific versions of PowerShell. The
end result is that this holds us back as a community, and we need to find a way
to enable us to move forward more quickly.

Fortunately, the upcoming release of PowerShell 7 provides a rare opportunity
for the PowerShell Community: its release marks the first time that a successor
to a Windows PowerShell release can be installed side-by-side with Windows
PowerShell (note: PowerShell Core 6.x was not a true successor to Windows
PowerShell, but PowerShell 7 is the successor to both Windows PowerShell 5.x
and PowerShell Core 6.x). It will even have a separate executable (`pwsh.exe`),
and can be installed to specific locations. That means users will be able to
install and use PowerShell 7 side-by-side with other versions of PowerShell,
which is a great help for users looking for opportunities to move forward.
There are still some products and/or scenarios that aren't supported in
PowerShell 7, but this release brings us much, much closer to parity and gives
us an opportunity to spend more time looking forward than backward.

Unfortunately, according to the [Microsoft blog post about the forthcoming
PowerShell 7 release](https://devblogs.microsoft.com/powershell/the-next-release-of-powershell-powershell-7/),
PowerShell 7 will align more closely with the .NET Core support lifecycle,
which brings in support for LTS (Long Term Servicing) and non-LTS releases.
Non-LTS (aka Current) releases are supported for three months after a
subsequent Current release or an LTS release. This means you'll have to update
those releases regularly, which helps move the community forward. On the other
hand, LTS releases will be supported either for three years after general
availability or for a 12 month maintenance period after the next LTS release
ships, whichever is longer (i.e. if it takes them longer than expected to get
an LTS release out the door for some reason, the previous LTS release could be
supported for even longer). This means you'll be able to stick your heels in
the ground and use an LTS release for a very long time, which risks holding us
back.

In order to keep the focus on moving forward, the purpose of this proposal is
to support side-by-side installations of PowerShell such that...:

* ...it is easy to see what versions of PowerShell are installed.
* ...it is easy to launch a specific installed version of PowerShell from a
command line.
* ...having multiple installed versions of PowerShell doesn't cause problems
for automation, products, or services built for a specific version of PowerShell.

## Motivation

As a user,
I can easily install newer versions of PowerShell side-by-side with old versions,
so that I can continue to use products/solutions for specific versions of PowerShell while using newer versions when needed.

As a user,
I can use the command line to see which versions of PowerShell are installed,
so that I can know what versions are available to me to use.

As a user,
I can launch the version of PowerShell I need from the command line,
so that I can use automation built and tested against specific versions of PowerShell while still being able to use the latest version on the same system.

## User Experience

### Installing a specific version of PowerShell

The end goal is for users to be easily able to do any of the following with a
PowerShell installer:

* install the latest version of PowerShell side-by-side with an existing
version from a UI (e.g. `.msi`, `.pkg`, `.deb`)
* install the latest version of PowerShell side-by-side with an existing
version from the command line (e.g. `sudo apt-get install ...`, `brew cask
install ...`, `choco install ...`)

_Note: I'm a little uncertain of these details here, so please correct me where
appropriate._

The current release process seems to include updated published versions of
packages in the various package repositories (for `apt-get`, homebrew, and
Chocolatey). The problem with this approach is that it does not support
side-by-side installations at the command line. For example, if I have
PowerShell Core 6.2.0 installed on macOS and I want to install PowerShell Core
6.2.1 side-by-side, I cannot. I can upgrade my installed version, reinstall
the current version, or install a preview version (since that comes from a
different package name), but I cannot install a different version side-by-side.

Instead, if the release process not only updated the latest package but also
created a version-specific package in the various repositories, then users
could specify a specific version that they want to install (e.g. `brew cask
install [email protected]`) to install different versions of PowerShell
side-by-side with one another, with the versions automatically being installed
in an appropriate version folder (which they are already anyway). Chocolatey
already has support for installing a specific version, but it does not seem to
work at the moment (I tried installing PowerShell Core 6.2.0 and ended up with
6.2.1, with an error indicating that 6.2.0 was not installed).

The UI installers should provide options to upgrade the latest installed
version of PowerShell or install a new version side-by-side.

### Listing installed versions of PowerShell

```bash
# This launches the latest version of PowerShell, returns a list of installed
# versions and their installation location, and then exits
pwsh -ListVersions
# This does the same thing
pwsh -lv
```

```output
6.2.1 [/usr/local/microsoft/powershell/6.2.1/]
7.0.100-preview1 [/usr/local/microsoft/powershell/7.0.100-preview1]
```

```powershell

# This returns a list of installed versions and their installation location as
# objects
Get-InstalledPSVersion
```

```output
Version InstallLocation
------- ---------------
6.2.1 C:\ProgramFiles\PowerShell\6.2.1
7.0.100-preview1 C:\ProgramFiles\PowerShell\7.0.100-preview1
```

### Launching a specific version of PowerShell

```bash
# This launches the latest version of PowerShell, gets the installation
# location of the specified version, launches pwsh for that version, and exits
# when the launched version exits
pwsh -Version 6.2.1
# This does the same thing
pwsh -v 6.2.1
```

```output
# A new window with the desired version of PowerShell open.
# If it is possible to do have this window on a new tab in the new Terminal,
# that would be great.
```

## Specification

* create a `Get-InstalledPSVersion [<CommonParameters>]` cmdlet that returns
the installed versions of PowerShell along with their locations
* update the `-version` argument of `pwsh.exe` to attempt to launch a specific
version of PowerShell
* add a `-ListVersions` argument to `pwsh.exe` that internally invokes
`Get-InstalledPSVersion`, formats and outputs the results, and exits
* update the release packaging process to produce versioned packages

## Alternate Proposals and Considerations

### Include Windows PowerShell version support

It would be worth considering having `Get-InstalledPSVersion` return the
installed version of Windows PowerShell along with its location, and having
`pwsh -version` support launching Windows PowerShell. That would allow users to
launch any installed PowerShell version from `pwsh.exe`, making it easy to set
up automation with one command to invoke. Arguments from `pwsh.exe` could be
mapped to arguments on `powershell.exe`.

### Are containers and Docker enough to solve this need?

While discussing this with a colleague of mine, they asked if this is really
needed, or if containers and Docker solve this problem already. While I believe
containers can allow users to use different versions of PowerShell, I also
suspect that most users don't know how to set that up, if they even use Docker
at all. I think it would be easier for everyone if we could just launch the
proper version of PowerShell via `pwsh.exe`.

### Maintain backwards compatibility with pwsh.exe -version

In PowerShell Core 6.2, if you invoke `pwsh -version` you get the current
PowerShell version. That support could remain in place if this RFC is approved,
returning the current (latest) version when invoked without a version, or
launching the requested version when invoked with a version.

### Windows Update

If PowerShell is added back as a component of Windows, some consideration needs
to be given to Windows Update. With side-by-side installations, it would not
make much sense to update older versions, so the most recently installed stable
version should be treated as the default version to check for updates.

Unfortunately I do not have much insight into what Windows Update requires.
@iSazonov mentioned he remembers it requiring the _same_ installation folder,
and if that is the case, how would that work with a SxS updateable PowerShell.
If someone who knows what is actually required to make Windows Update work
could share what could/should be done here, that would be appreciated. Ideally
PowerShell would work like dotnet works, supporting side-by-side installations
while being updateable via Windows Update as well.

### Version discovery and registration

Currently the PowerShell installer allows you to install PowerShell into any
folder you want. This flexibility comes at a cost, because it means registering
installations of PowerShell on a system to make sure they are discoverable.

Since PowerShell is a runtime that other products need to be able to depend on,
some thought needs to be given towards how best to install it. I believe it
would be better to only install to known locations for all users/system or for
the current user so that we could check the filesystem to discover versions of
PowerShell that are installed, regardless of what platform we are on. It is
likely that this would also make building solutions on top of side-by-side
installations of PowerShell easier, so that they can check for the required
version easily.

It is worth mentioning that the dotnet sdk installer does not ask you where
you want to install it. Instead it installs to one of two locations, depending
on whether or not you are an admin (i.e. it installs to an all users/system
location if you are admin, or to a user location if you are not).