Skip to content
Closed
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
256 changes: 256 additions & 0 deletions Archive/Draft/RFCxxxx-PS7-Bootstrapper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
---
RFC: RFCnnnn
Author: Steve Lee
Status: Draft
SupercededBy: n/a
Version: 0.1
Area: Install
Comments Due: Dec 31st, 2021
Plan to implement: Yes
---

# Bootstrapper for PS7 in Windows

## Motivation

As an admin,
I can use PS7 to provision a new Windows machine,
so that I can leverage new capabilities in PS7.

As a user,
I can use PS7 on a new Windows machine,
so that I can leverage new capabilities in PS7.

Explicitly installing PS7 is a blocker for some customers not only due to discoverability, but also some customers have policies that
don't allow for installing software onto Windows after initial provisioning.

## Shipping in Windows

There are several issues that prevent simply shipping PS7 in Windows:

- Size
- Support lifecycle differences

### Size constraints

A complete installation of PowerShell 7 currently is around 200 MB (unpacked).
This is due to including everything (modules and .NET assemblies) to provide parity with what Windows PowerShell 5.1 with .NET Framework provides.
There is currently no plan by Windows or the .NET team to ship newer .NET in Windows, so PS7 will need to continue to ship .NET with PS7.

### Support lifecycle

Windows has a 5+5 year support lifecycle.
.NET supports up to 3 years for Long Term Support (LTS) versions.
So even if size was not an issue, we cannot check in a version of PS7 with a .NET that is not supported while Windows itself is supported.

### Solution

To solve both of these issues, the proposal is to ship a bootstrapper in Windows that would be supported within the Windows support lifecycle.
The boostrapper will update PS7 as needed to ensure a supported version of .NET is being used.
Details of this bootstrapper follow.

## Specification

### pwsh.exe bootstrapper

We would check-in a `pwsh.exe` into Windows 11+ (under `System32`) written in [native code](#native-code) that will:

- Detect if PS7 is already installed
- If installed, pass-through all arguments to the new detached `pwsh` child process
- This means that if PS7 is already in the `PATH`, then that version (whether installed via MSI, MSIX, or other means)
needs to be updated outside of the bootstrapper
- Otherwise, [install](#installer) PS7 and then pass-through all arguments to the new detached `pwsh` child process

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like this would essentially circumvent software installation policies established by the enterprise and - in a worst case scenario - might become yet another hole enterprise will now need to be closing.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how would one control aspects of such installation? E.g. things like path, whether it is single/multi user install, logging and verbosity

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another issue that comes to mind: what about software that first checks for the presence of pwsh.exe, and then calls "pwsh.exe --version" to detect the installed PowerShell version? Not only the shim would fool most software into thinking it's already installed, but the "pwsh.exe --version" version call would trigger the actual installation.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this is the same problem the Python for Windows folks created. They have a python.exe alias that build scripts detected as "Python is installed". Terrible dev experience.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, PS7 should just be considered a Windows feature-on-demand (even though it doesn't use that mechanism specifically because a literal Feature-on-Demand requires the 10 year support lifecycle) and would install via Windows Update channel (this is in the RFC). So for all intents and purposes, pwsh.exe is in-box regardless if it needs to bootstrap itself initially. pwsh -version would work as though it was installed.


The boostrapper should explicitly create a detached child `pwsh` process and then exit.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appears to me it would break a range of scenarios where users formed PS command lines and used explicit process start and wait (ShellExecute, _wpopen, Process.Start, etc.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these problems are solvable although it might require the installed pwsh to be first in the path so that the bootstrapper is no longer called unless called explicitly after PS7 is installed

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might require the installed pwsh to be first in the path so that the bootstrapper is no longer called unless called explicitly after PS7 is installed

Yes please!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to add some specifics here.

Windows PowerShell is often used as a wrapper around poorly-written application installers. Software distribution systems, such as Configuration Manager or Microsoft Endpoint Manager (Intune), call powershell.exe and pass it the wrapper script. Termination of the powershell.exe process signals the caller (ConfigMgr, Intune, etc.) that the installation is complete, which triggers evaluation of application detection rules. If powershell.exe were to spawn another copy of itself and exit, the caller would run detection rules while the real installation was still in progress, and it would report failure to the user (e.g., in Software Center or Company Portal). If PowerShell (pwsh.exe) spawns another process and exits, then it cannot serve as a replacement for Windows PowerShell in this scenario.

That may not be a terribly compelling argument, since such uses would rarely require features beyond what Windows PowerShell provides; administrators could just keep using Windows PowerShell for that purpose. The same pattern is commonly used for other functionality, though, where the improved features of PowerShell may be highly useful and desirable. PowerShell is used as a gap-filler for functionality that is missing from such endpoint management products: If FunctionalityX is not provided by the system, an administrator can write a custom solution in PowerShell to implement the needed functionality and deploy it to devices as an "application" that can be installed and uninstalled. Again, if pwsh.exe were to launch a separate process and then exit, this scenario would be broken and render PowerShell unusable for this purpose.

As a detached child process, it will continue execution even after the parent has exited.

Expectation is that the bootstrapper will always be first in the `$env:PATH` and executed first, so it can also serve

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this add even more time to executing pwsh, you now have to wait for 2 processes to initialise and while it's minute it's still a problem today with just pwsh.exe itself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will add some time, but should be minimal impact as the shim is in native code, but there is a cost to starting a 2nd process, but I think overall it'll be minimal compared to the current limitations of pwsh startup with .NET

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @awakecoding's comment has a good point. He suggests that, if we decide to go with the shim approach, then the bootstrapper pwsh can actually host CoreCLR runtime, and calls into pwsh.dll via its entry point. In this way, we don't need to spin up 2 processes and handle STD io redirections.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@daxian-dbw it's actually even better than that: you can literally use the hostfxr APIs to call into the pwsh.exe command-line entry point... within the current process. You literally load pwsh.exe and launch it within the PowerShell native host process without a subprocess! When using this specific mode of launching with a PowerShell native host, you can only do it as a one-shot thing where you basically just call it once and let it return, but that's precisely what we want here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank @awakecoding, I just saw the run_pwsh_lib and run_pwsh_app in your project. What's the benefit of loading and launching pwsh.exe comparing to loading Microsoft.PowerShell.ConsoleHost.dll and calling into the entry point function Start(string[] args, int argc)? The former will load extra libraries (pwsh.exe and pwsh.dll).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank @awakecoding, I just saw the run_pwsh_lib and run_pwsh_app in your project. What's the benefit of loading and launching pwsh.exe comparing to loading Microsoft.PowerShell.ConsoleHost.dll and calling into the entry point function Start(string[] args, int argc)? The former will load extra libraries (pwsh.exe and pwsh.dll).

There is currently no way to load less than what pwsh.exe needs, and even if there was a way to do it (lazy loading of DLLs, etc) then the proper way would still be with a .NET native host process, so we're back to my technique again.

Also, how would you load ConsoleHost.dll from a process that isn't .NET, and without creating a subprocess? Chances are you would need to use the hostfxr APIs again to do this cleanly, and then you'd be limited to the command-line interface.

The PowerShell native host approach is the only one that avoids creating a subprocess and solves the problem very efficiently. Think of it as just replacing pwsh.exe out of the full PowerShell installation, except it doesn't rely on .NET at all, making it the perfect shim.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, how would you load ConsoleHost.dll from a process that isn't .NET, and without creating a subprocess? Chances are you would need to use the hostfxr APIs again to do this cleanly, and then you'd be limited to the command-line interface.

The pwrshplugin used by PowerShell for WSMan remoting loads System.Management.Automation.dll directly from native process to create a function pointer, see code here.

We also have an ancient native powershell host written in C++, and it used to load ConsoleHost.dll directly from native process, though it hasn't been used for a long time. See the code here.

We also have the DSC native agent that loads CoreCLR and calls into managed code form native code. So, I think it's doable, only that we need to figure out how to get the Trusted Assembly List (TPA) populated by using hostfx.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a similar approach that shouldn't change much, the sample you linked to appears to be using COM Interop to load PowerShell. While I believe it is still possible to use COM Interop on Windows with PowerShell 7, I do recall trying it on Linux only to realize the COM exports were missing on non-Windows.

The current project is only for Windows, but it wouldn't hurt to use the recommended hosting APIs, and that would mean the hostfxr APIs. Maybe the only thing we can conclude at this point is to use the hostfxr APIs to make a .NET host, and then move on to how we'd load and call PowerShell using it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Regardless of the implementation details, I believe we should make the bootstrapper a .NET host, if we want the bootstrapper a shim that always runs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having the pwsh bootstrapper be a .NET host is interesting. If it's simply hosting the consolehost and passes all arguments to it to evaluate, then I would agree that is a fine solution.

to [auto-update](#auto-updating) PS7.

This will allow `pwsh -c customer_script.ps1` to work seamlessly as though PS7 was available inbox.

The bootstrapper would need to start the real `pwsh.exe` and bind stdin/stdout so that inputs and outputs come from `pwsh.exe` seamlessly.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would also need to ensure this works in an interactive situation where just doing pwsh will spawn the process that inherits the console handles itself rather than a redirected stdio.

It also means if you do something like pwsh -c "my command" from WinPS it will not wait until until it is finished because the parent (bootstrap) process has ended.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good points, will make these explicit

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another issue is how do you get the exit code to bubble itself back up to the caller. You essentially need to either have the bootstrap process continue to run until pwsh is finished and have that set it's own exit code to that of pwsh's.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggestion of launching a subprocess pwsh.exe from the shim pwsh.exe has a lot of potential issues, but if we make the pwsh.exe shim a PowerShell native host process, we can actually make it behave exactly like the original without even spawning a subprocess. It would literally be the same as pwsh.exe but without PowerShell, and the ability to load the .NET runtime + launch PowerShell entirely from disk. I've done this before, just not with the full "let's find and download PowerShell on the fly" part.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea this does sound like a better solution, I'm not too well versed in hosting the CLR side but a colleague mentioned it should be possible for the pwsh shim to do the bootstrapping and then just host the CLR in the same process once that step is done. You save the hit of spawning yet another process and don't need to worry about IO redirection and other things like handle inheritance and the like.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the shim has to stay resident and manage the pwsh lifecycle. I have many scripts that depend on calling pwsh.exe synchronously.

Unlike Unix, there isn't a way to `exec` a new process that replaces itself so for the first execution, there would be two `pwsh.exe` processes.

However, if the bootstrapper detects that stdin, stdout, or stderr is redirected, then it would need to not exit and instead
continue to redirect until the child `pwsh.exe` process has exited.

Additional Windows requirements:

- registered with Windows so that `Start->Run->pwsh` will start the bootstrapper
- a separate Windows feature that can be uninstalled (so that using `pwsh` would not automatically work, or is being installed by other means)
- different icon for the bootstrapper to indicate it is a bootstrapper

### .ps1 registration

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ps1 registration/integration makes sense as feature of PowerShell installer; not something for bootstrapper to be solving.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be out-of-scope, but please consider the Hosted App Model.
PowerShell/PowerShell#15758


`pwsh.exe` will be registered to execute .ps1 scripts, by default.
However, it will have code to detect if started from the `explorer.exe` and instead
give an error message that scripts need to be run from the console and not from Explorer.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"and not from Explorer" - few questions:

why blocking a launch from shell?

and in doing so, why special treatment to explorer?
if I am using another shell - e.g. Total Commander, what should be different about it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two other aspects come into my mind:

I am using self elevating PowerShell scripts.
How would this affect the secondary instance that's elevated.

For Windows Explorer please consider an implementation that's compatible to have PowerShell 7 when using the address line entering PowerShell
This currently launcher a PowerShell in the directory currently Windows Explorer opened. (same as cmd does)

Copy link

@riverar riverar Dec 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if my script has no TUI/GUI and running via Explorer blindly is an expected/valid scenario? This constraint seems orthogonal to the bootstrapper story.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mention about explorer.exe is to prevent folks from downloading a .ps1 and accidentally executing it by double clicking it in Explorer. In this case, to support default execution by other processes (so they can just expect a foo.ps1 to work as foo.cmd does today), we would need to associate .ps1 with pwsh but special case the explorer.exe use case. Software today have to wrap .ps1 within a .cmd which makes them not write .ps1 and write batch files instead

This means that from cmd.exe, you can execute .ps1 scripts without explicitly calling `pwsh.exe` and that applications
Copy link

@rashil2000 rashil2000 Dec 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the .ps1 extension be added to the PATHEXT environment variable? I feel if the goal is to give PS scripts a first-class treatment on Windows similar to .bat and .cmd scripts, it'd make sense to give the ability to invoke them without having to specify the extension every time.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that is the intent so that foo.ps1 could just be executed as foo

can start depending on .ps1 scripts instead of wrapping them in batch files.
The default execution policy on both Client and Server SKUs should be RemoteSigned.

### Native code

We can't rely on .NET Framework being available on some Windows skus we want to support and keeping the bootstrapper as
small as possible, we don't want to rely on .NET (Core) and ship that runtime.
Also, we want the bootstrapper to have minimal dependencies as future Windows SKUs may not ship with certain dependencies.

#### Rust

Rust has the benefit over C/C++ of having well defined contracts for resource management thus not having issues that persist in C/C++ code
with regards to resource management which results in not only leaks but security issues.
Resulting Rust binary code is very similar in size and performance as C/C++.
Rust built code is supported in Windows.

Rust uses the MS C runtime at execution, but we should statically link so that there aren't external dependencies that may be missing on the system.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Statically linking the CRT will prevent servicing should the need arise (e.g. security). Instead, I would look into the hybrid CRT solution. https://github.com/microsoft/WindowsAppSDK/blob/main/docs/Coding-Guidelines/HybridCRT.md


Need to evaluate what APIs are available on the smallest Windows SKU for downloading.

This is the current preferred option.

### Installer

MSI has dependencies that are not available on Windows SKUs so would not be appropriate as the installer for the bootstrapper.
Instead, we should look at using [Squirrel](https://github.com/Squirrel/Squirrel.Windows) which supports installing even if the product (existing version)
is already in use.

The bootstrapper would download the installer using Windows Update as the store to avoid issues with enterprises not allowing
network access to other sites.
The installer and binaries may need to be Windows signed instead of Microsoft signed.
Packages of PS7 outside of this installer used by the boostrapper would continue to be Microsoft signed.

### User Experience

Since the initial bootstrapping will take time to download and install, the bootstrapper should have progress information and
indicator during download and installation via stderr.
Stderr is used instead of stdout so that user redirection of stdout only contains output from successful execution of their commandline.
Use of stderr for informational messages is a convention used by native commands already.

Should the install or download fail, the bootstrapper needs to output appropriate information and direct user to documentation on alternate
install method and return a non-zero exit code.

### Auto-updating

Upon startup of the bootstrapper (following rules of [admin vs non-admin](#admin-vs-non-admins)) will detect if the installed

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this really be part of Windows/Microsoft Update? I dislike the idea of pwsh trying to do even more work at startup and potentially change the ground that I'm working on by automatically updating. I feel like the bootstrap script if this goes ahead should just install the initial version and updates are managed through WU.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the original reason not to just use WU was because it wasn't supported on Nanoserver, but since we've decided Nano is out of scope, we should revisit this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of today, I think WU will work only if the installation is done through MSI and has the "use windows update" checked. How would it work for non-admin scenarios? I believe there will be many users using the non-admin installation.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jborean93 Agreed. I'm not comfortable with the idea that my set of build nodes will update to a newer version of PowerShell merely by running pwsh as part of a build. I prefer to be "in control" of when that happens.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use winget as fallback.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

winget is not available on Windows Server and Windows Server support is required

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SteveL-MSFT Since you say that Nano Server is out of scope, does that mean that PowerShell could be delivered via MSI after all (rather than Squirrel mentioned above)? IIRC, all SKUs of Windows other than Nano Server support Windows Installer.

version is installed by the bootstrapper and if so, if it is the latest stable version.

If the version is older, then it will asynchronously download updated PS7 and continue with execution.
A message will be emitted that on next startup PS7 will be updated.
Upon next startup, if a newer version is downloaded, then the signature will be validated and installed providing
progress information to the user.

In general, auto-updates will be to a servicing release like 7.x.y to 7.x.y+1.
However, when 7.x is out of support, then it should auto-update to 7.x+1.
This is consistent with how our Microsoft Update support works to keep users patched and on a supported release.

The auto-update applies regardless if PS7 is started interactively or via automation (explicitly using the `-noninteractive`, `-file`, or `-command` switch).
Copy link
Member

@daxian-dbw daxian-dbw Dec 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating from 7.x to 7.x+1 can potentially break existing automation workload. Here are 2 real-word issue reported after the users moved to 7.2 from 7.1:

  1. The reader's MaxDepth of 64 has been exceeded PowerShell#16457 -- PowerCLI module was broken in 7.2 because of a breaking change in Newtonsoft.Json that was made to prevent a DoS vulnerability.
  2. Multiple Ambiguous Error under Windows 11 but not Windows 10 PowerShell#16506 -- method resolution failed for a working script because new overloads were added to System.Text.Json.JsonSerializer.Deserialize(...) that causes a conflict in method resolution.

Even if PowerShell itself can be backward regression free (best case scenario), the assemblies shipped with PowerShell can break user's existing workload, and there is nothing PowerShell can do to prevent that from happening. So, I think we should never automatically update from 7.x to 7.x+1. That should always be an explicit decision made by the user.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a matter of opt-in or opt-out. Secure by default means you have to opt-out of automatic updates. I would expect folks who rely on automation to be experts vs folks who simply want to use a shell

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect folks who rely on automation to be experts vs folks who simply want to use a shell

I'm not necessarily arguing for or against automatic updates, but FWIW in my experience the opposite is true. At least on the Windows side, there's a much larger amount of less experienced folks who can cobble a script together than folks who are even a little comfortable in a shell.

Copy link

@afedyashov afedyashov Dec 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This auto-update is so scary.

I maintain few dozen of psm1 modules - several hundred of exported functions total, and I would not jump to a different version of PowerShell that had not been scrutinized by thorough testing before.

Imagine - one day, because of some apparently small change somewhere in ConvertTo-Json function behavior - all CI pipelines fall apart, just because somebody maintaining the server didn't read the fine print.

I feel this area of the proposal needs a bit more scrutiny.


### Configuration

Some registry configuration (settable via Group Policy) would be needed to disable auto-updating.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another reason for doing updates through WU, it's something already understood by admins and offers the ability for orgs to cache the update files on their own servers for distribution rather than having to find another way to get that data from the net.

However, auto-updating will be the default to ensure users have the latest version with security updates.
Configuration would allow for auto-updating, update via prompt, or don't update.

### Admin vs. Non-Admins

If the process is elevated, then the install will be for the system under `$env:ProgramFiles`.

However, the bootstrapper must work for non-admins.
Otherwise, PS7 is installed only for the current user if the process is non-elevated.
In this case, PS7 would be installed to `$env:LOCALAPPDATA\Microsoft\PowerShell7` and the user `$env:PATH` would be appended with this path.
`PowerShell7` as a folder is used instead of just `PowerShell` as that folder is already being used by PS7 for persisting state.

If PS7 was installed by the bootstrapper elevated so that it's available system wide (under `$env:PROGRAMFILES`), and the user
is non-admin, but the bootstrapper detects a newer version is available, then it should emit a message indicating that a newer
version is available, but requires elevation or an administrator to install.

>[Note] Need to verify that Squirrel supports admin installs for system-wide access

### Windows Terminal

Windows Terminal is now a default installed app and has code to detect PS7.
Currently, it will not detect the prescence of `pwsh.exe` bootstrapper if it exists in system32.
We may submit a PR to update their detection logic so that the bootstrapper is available as the default shell.

### Offline scenarios

Need to look into integration with [Windows ADK (Assessment and Deployment Kit)](https://docs.microsoft.com/en-us/windows-hardware/get-started/)
to support pre-provisioning Windows images that already include PS7 rather than bootstrapping at runtime where the machine may be on a factory
floor (WinPE) without internet access.

### Remoting endpoint

By default, neither WinRM nor SSHD will be setup for PS7 remoting.
So when remoting from one Windows machine into another, it would not connect to PS7 unless the user has manually configured it
(and thus also installed PS7).

We may consider adding capability to make it easy to setup PS7 remoting for large deployments in the future.
For example, maybe `pwsh.exe --enable-ssh-endpoint` and `pwsh.exe --enable-winrm-endpoint` as special switches only for the bootstrapper.

## Alternate Proposals and Considerations

### Reducing size

The bootstrapper itself is small, but installation would still carry a full PS7 package.
Details of reducing the size of PS7 post-install is outside the scope of this specific RFC.

### Auto-update when used non-interactively

Current design is based on auto-update (unless configuration is set not to) even if the usage is via automation.
For example, remotely or using task scheduler to execute a script.
A design decision could be made to not auto-update if we know the usage is not interactive,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having my automation engine upgrade outside of my patch cycle is kind of scary. I love the work the team has done to add PS7 to WU/MU. I believe that established process is the better method for upgrading versions.

but current design is to keep PS7 updated even in those cases unless configured otherwise.

### Feature-on-Demand

A Windows Feature-on-Demand (FOD) is similar to what is being proposed in that you would install the feature from the internet.
However, a FOD needs to be explicitly installed to be used and is also locked to a specific version built for that version of Windows.
In this case, it's critical to allow use of `pwsh.exe` right out of the box and have it execute a customer script and also
because PS7 aligns with .NET lifecycle, install the latest stable version.

### Windows Store MSIX pkg

Some applications have a shortcut that is shipped inbox and when started installs from the Windows Store.
This presents two problems:

- This works fine for interactive use, but for automation, they now have to bootstrap PS7 before they can use PS7 to bootstrap other configuration
- Windows Store is not supported on Windows Server which is required
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could alternatively investigate using AppInstaller. Or at least evaluate it and include the "why not" in this section.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that MSIX specific? MSIX is not supported on Windows Server

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SteveL-MSFT MSIX is supported on Windows Server. You might be thinking of the AppInstaller app (which is separate from the .appinstaller manifest).


### `Install-PS7` cmdlet in Windows PowerShell

Simplest solution may be to have a script cmdlet in Windows PowerShell that simply installs PS7.
This is an additional step required to provision PS7.
Some skus of Windows do not include Windows PowerShell so they would not be able to use this.

### PS7 zip pkg support

Instead of supporting bootstrapping using the zip package, in cases where the Windows SKU doesn't support MSI/MU, we may only
support offline installation at image creation time.

### [.NET NativeAOT](https://github.com/dotnet/runtimelab/tree/feature/NativeAOT)

We should look into this as an option, but this is still experimental and we may not be supported for production use.

### `pwshup.exe` instead of bootstrapper

There has been a community suggestion to have a [`pwshup`](https://github.com/PowerShell/PowerShell/issues/14217) for explicit but easy
installation of PS7.

This could be shipped in Windows instead of a bootstrapper (although the two are not mutually exclusive).
However, `pwshup` is more dev-centric and requires the user to initially use it to install PS7.
This means that an enterprise cannot simply start executing PS7 scripts and would need to initially use `pwshup` to bootstrap
the system to install PS7.

`pwshup` would also be useful in side-loading scenarios where an application has dependency on a specific version
of PS7 and doesn't want to ship and patch it themselves.

Also, for non-developers/ITPros that simply want to use the latest PowerShell as a shell, they would need to know
to run `pwshup` first instead of just running `pwsh` (or clicking on the pre-installed icon) and then simply getting an interactive shell.

### Out-of-scope features

- choice of installing preview, stable, or LTS releases of PS7
- ability to specify a specific version of PS7 or specify as argument like `pwsh -version 7.1`
- ability to use `#requires` to specify execution using WinPS vs PS7
- Nanoserver is out of scope