-
Notifications
You must be signed in to change notification settings - Fork 130
Importing Windows PowerShell modules in PowerShell Core #226
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
Changes from 15 commits
c697c0c
41b950f
7fdc10f
6461dd6
ac4591b
5e9faa8
988c065
6b9a715
6aec095
c6445e4
ff270c3
bf27e93
34e6a8f
b50a110
8084796
fa9a19c
2e97c78
14eb2f2
012e342
80e55e6
60382e1
2cb3f35
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
--- | ||
RFC: | ||
Author: Andrew Menagarishvili | ||
Status: Draft | ||
SupercededBy: | ||
Version: 0.1 | ||
Area: Language | ||
Comments Due: 10/10/2019 | ||
Plan to implement: Yes | ||
--- | ||
|
||
# Importing Windows PowerShell modules in PowerShell Core | ||
|
||
One of the big factors preventing existing Windows PowerShell users from moving to PowerShell Core has been cmdlet coverage. Specifically being able to use existing Windows PowerShell modules in PowerShell Core. Non-compatibility is due to the different .NET runtimes used between Windows PowerShell and PowerShell Core. Ease of UX is important when addressing this problem - working with 'WindowsPS-only' modules from PS Core should not be any different than working with 'PS Core - compatible' modules. Also this should not require any setup from the user. | ||
|
||
## Motivation | ||
|
||
As a PowerShell user, | ||
I can use modules written for Windows PowerShell in PowerShell Core, | ||
so that I could migrate from Windows PowerShell to PowerShell Core. | ||
|
||
## User Experience | ||
|
||
Example that shows using commands from 'WindowsPS-only' module located in `System32` module path in PS Core: | ||
```PowerShell | ||
PS C:\> $PSVersionTable.PSEdition | ||
Core | ||
PS C:\> Import-Module DesktopOnlyModuleOnSystem32ModulePath | ||
VERBOSE: Please note that module 'DesktopOnlyModuleOnSystem32ModulePath' is imported in a remote Windows PowerShell session, so all objects that are returned by commands from this module are deserialized and are not 'live' objects. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure that user scripts will works well with deserialized objects. I always had problems when I switched to deserialized objects. I'd expect that we use the technology only for modules compatible with serialization. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, I think it's impossible for us to know whether that's the case. I still think we're going to end up with more successful script executions if we automatically load system32 modules (which are known to be incompatible post-Server 2019 and are demarcated as such) than if we simply fail to load them |
||
PS C:\> (Get-Module DesktopOnlyModuleOnSystem32ModulePath).CompatiblePSEditions | ||
Desktop | ||
PS C:\> DesktopOnlyModuleOnSystem32ModulePathFunction | ||
Success | ||
``` | ||
Proof-of-concept test was successfull. | ||
|
||
For reference, here is current behaviour that this RFC is targeting to change: | ||
```PowerShell | ||
PS C:\> $PSVersionTable.PSEdition | ||
Core | ||
PS C:\> Import-Module DesktopOnlyModuleOnSystem32ModulePath | ||
Import-Module : Module 'C:\windows\system32\WindowsPowerShell\v1.0\Modules\DesktopOnlyModuleOnSystem32ModulePath\DesktopOnlyModuleOnSystem32ModulePath.psd1' does not support current PowerShell edition 'Core'. Its supported editions are 'Desktop'. Use 'Import-Module -SkipEditionCheck' to ignore the compatibility of this module. | ||
``` | ||
|
||
## Specification | ||
|
||
Today a module manifest (since Windows PowerShell 5) may contain a `CompatiblePSEditions` property to indicate if it is compatible with PowerShell Core (value of `Core`) or Windows PowerShell (value of `Desktop`). If `CompatiblePSEditions` property is missing then the value of `Desktop` is assumed.<br /> | ||
Functionality of this RFC will replace showing of the `PSEditionNotSupported` error message (`Module '{0}' does not support current PowerShell edition '{1}'. Its supported editions are '{2}'. Use 'Import-Module -SkipEditionCheck' to ignore the compatibility of this module.`) in scenarios where it is currently displayed:<br /> | ||
During `Import-Module` a module wil be loaded into a separete Windows PowerShell process instead of current PowerShell Core if:<br /> | ||
anmenaga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(A module is located in `System32` module path) and ((`CompatiblePSEditions` is `Desktop`) or (`CompatiblePSEditions` is missing))<br /> | ||
If this condition is detected PowerShell Core: | ||
1. creates a hidden `WindowsPS Compatibility` Windows PS process (unless one already exists) | ||
2. creates PS Remoting connection to its IPC pipe | ||
3. loads the module in remote Windows PS process | ||
4. generates local proxy module/commands using IPC remoting connection and `Import-PSSession` cmdlet | ||
5. when 'WindowsPS-only' module unload request is detected - unload module in remote process, close PS remoting channel, close remote process | ||
anmenaga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### PS Remoting Transport | ||
|
||
IPC / Named Pipe is to be used for connections to remote PowerShell process. Today a named pipe listener is created with each Windows PowerShell process. IPC transport has good performance and secured endpoints, however (unlike, for example, SSH transport) it is not currently supported by New-PSSession. | ||
anmenaga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
So a new IPC-specific parameter set will be added to New-PSSession: `New-PSSession -ProcessId <Int32> [-Name <String>] [-AppDomainName <String>]` | ||
Here is the pseudo-code that shows the essence of proposed implementation of a new parameter set in New-PSSession: | ||
```csharp | ||
NamedPipeConnectionInfo connectionInfo = new NamedPipeConnectionInfo(WindowsPS_ProcessId, WindowsPS_AppDomainName); | ||
TypeTable typeTable = TypeTable.LoadDefaultTypeFiles(); | ||
RemoteRunspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo, this.Host, typeTable) as RemoteRunspace; | ||
remoteRunspace.Name = NamedPipeRunspaceName; | ||
try | ||
{ | ||
remoteRunspace.Open(); | ||
} | ||
catch (RuntimeException e) | ||
{ | ||
// handle connection errors | ||
} | ||
PSSession remotePSSession = new PSSession(remoteRunspace); | ||
this.RunspaceRepository.Add(remotePSSession); | ||
WriteObject(remotePSSession); | ||
// In case of 'Windows PS Compatibility' scenario, Import-PSSession is then run on remotePSSession to generate proxy cmdlets. | ||
``` | ||
|
||
anmenaga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
### Lifetime of 'compatibility' Windows PowerShell process and module | ||
|
||
Overall RFC goal is to have familiar 'local module' user experience even though actual operations are working with a module in a separate 'compatibility' process. This drives following: | ||
|
||
1. One 'compatibility' Windows PowerShell process corresponds to one local PowerShell Core process. E.g. if a same user creates 2 local PowerShell Core processes and loads 'WindowsPS-only' module in each one, this will result in creating 2 Windows PS processes and loading the actuall module in each one of them. | ||
anmenaga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
2. Lifetime of the module on 'compatibility' side (Windows PowerShell) should be the same as on local side (PS Core). This is important because some modules save their global state in-between command calls. | ||
* Local Load-Module for 'WindowsPS-only' module will have same behaviour/effect in 'compatibility' Windows PS process as it would have been done locally on an compartible module. In addition, this will create `WindowsPS Compatibility` Windows PS process if one does not already exist. | ||
* Local Remove-Module for 'WindowsPS-only' module will have same behaviour/effect in 'compatibility' Windows PS process as it would have been done locally on an compartible module. In addition, this will remove `WindowsPS Compatibility` Windows PS process if it is no longer needed. | ||
3. When removing a module, there is an `OnRemove` event on the module that will execute. This event allows Compat proxy module to react to being removed and perform cleanup of 'compatibility' process if necessary. | ||
4. PS process exit does Not perform graceful cleanup of modules, so it needs to be handled separately. There is an event that allows to react to the closing of the PowerShell process (to do 'compatibility' process cleanup): `Register-EngineEvent -SourceIdentifier ([System.Management.Automation.PsEngineEvent]::Exiting) -Action $OnRemoveScript` | ||
|
||
### Objects returned by remote operations | ||
|
||
With PS Remoting objects returned from remote 'compatibility' side are not actual `live` objects. This will be the same in case of this RFC. Documentation will make sure that users understand that even though the experience will look like they are working with 'WindowsPS-only' modules locally, objects returned by these modules are deserialized copies. | ||
|
||
## Alternate Proposals and Considerations | ||
|
||
### Windows PowerShell Compatibility module | ||
|
||
[Windows PowerShell Compatibility module](https://github.com/PowerShell/WindowsCompatibility) was initial step toward solving the problem of using WindowsPS modules in PS Core. It has following drawbacks: | ||
- It uses WinRM-based PS remoting which: | ||
+ requires setup | ||
+ not the best transport performance-wise | ||
- Introduces additional cmdlets to work with 'WindowsPS-only' modules, i.e. does not have transparent user experience. | ||
|
Uh oh!
There was an error while loading. Please reload this page.