PowerShell / WindowsCompatibility

Module that allows Windows PowerShell Modules to be used from PSCore6
Other
137 stars 33 forks source link

Tabcomplete no longer works after running CompatibilitySession.Tests.ps1 #7

Closed SteveL-MSFT closed 6 years ago

SteveL-MSFT commented 6 years ago

Run the CompatibilitySession.Tests.ps1 tests. Now in PSCore6 try to use tabcomplete for file path. Doesn't complete.

markekraus commented 6 years ago

repro:

.\build.ps1
Import-Module .\WinCompatibilityPack\bin\release\netstandard2.0\publish\WinCompatibilityPack.psd1
Import-WinModule Microsoft.PowerShell.Management

I have tested Import-WinModule on a few other modules and it seems fine, but once I import Microsoft.PowerShell.Management tab completion stops working.

For clarity, this kills tab completion when done in both PSCore and 5.1

SteveL-MSFT commented 6 years ago

@BrucePay can you look into this?

BrucePay commented 6 years ago

It appears to be caused by the presence of the second Microsoft.PowerShell.Management module. If you do

 Get-Module  Microsoft.PowerShell.Management | where ModuleType -eq Script | Remove-Module

then file completion comes back. I'm looking into PSReadline to see why this matters.

BrucePay commented 6 years ago

OK - here's what's happening. When you import the proxy module it doesn't clobber existing commands but does add a second module in memory with the same name as the original. Now if you use a module-qualified name e.g. Microsoft.PowerShell.Management\Get-ChildItem it will resolve this command against the newer proxy module instead of against the original binary module. As it turns out, the file name completion code uses module-qualified names exclusively and so it breaks when the proxy module is in memory. Fixing this is tricky. The best solution is to add a parameter -ModulePrefix to Import-Module so both modules don't have the same name. However that requires a new version of PowerShell to go with the module. For now, blocking the import of Microsoft.PowerShell.Management is probably the right thing to do.

markekraus commented 6 years ago

not that this is a terrific idea.... but since I'm pretty sure users want commands from this module (especially event logs).. we could special case this one module and use reflection to rename it after import.

For example, I can do the following:

$module = Import-WinModule Microsoft.PowerShell.Management -PassThru
$module.
    GetType().
    GetMethod("SetName",[System.Reflection.BindingFlags]'Instance, NonPublic').
    Invoke($module, @("WCP-"+$module.Name))

And Tab completion works and the imported commands work.

We could special case that for just Microsoft.PowerShell.Management until we can add a native -ModulePrefix to PS.

iSazonov commented 6 years ago

We could simply use standard prefix WCP. Just use, just document.

markekraus commented 6 years ago

@iSazonov While we could prefix the command names to avoid the problem, that then defeats one of the primary goals of the module. For example, If I have a script that uses Get-EventLog, and I wanted to run it on core and Windows PowerShell, I would Import this module on core to get access to the command without having to modify my script.

What is needed is the ability to prefix the module name so that Microsoft.PowerShell.Management Imports as WCP-Microsoft.PowerShell.Management or something. Currently that is not available in PowerShell. That is why I suggested the special casing of reflection.

BrucePay commented 6 years ago

I thought about reflection too but this has to be done for every proxy module that conflicts with an existing module so I'd rather do it in a supportable public way. (Which won't work on 5.1 of course.)

markekraus commented 6 years ago

Stretching the imagination here. What if we import the commands with a prefix like WCP so the command is imported as Get-WCPEventLog then we alias the nonclobbered commands New-Alias -Name Get-EventLog -Value Microsoft.PowerShell.Management\Get-WCPEventLog