powershim icon indicating copy to clipboard operation
powershim copied to clipboard

Invoke Windows PowerShell from PowerShell Core

PowerShim

Invoke Windows PowerShell from PowerShell Core

There are a lot of modules that do not yet support PowerShell Core. To work around this, you can use PowerShim to execute Windows PowerShell cmdlets and return the results to PowerShell Core.

Thie module executes code in an out-of-proc Windows PowerShell instance and uses PowerShell Remoting to communicate with it from PowerShell Core. This uses the same protocol as Enter-PSHostProcess.

This isn't perfect. Some script blocks won't work but should allow you to call cmdlets you wouldn't normally be able to call in PowerShell Core.

Cmdlet return values are serialized over PowerShell remoting so you will have objects returned by Invoke-Shim.

Give it a shot

PS> Import-Module PowerShim
PS> Get-SmbShare
PS> Invoke-Shim {
    Get-SmbShare
}

Why?

You can also achieve this by just calling PowerShell.

powershell -NoProfile -Output XML Get-SmbShare | Out-Default

The main reason is likely performance. Assume you run the following test.

Measure-Command {
    1..100 | % {
        Get-SmbShare 
    }    
}

Measure-Command {
    1..100 | % {
        Invoke-Shim {
            Get-SmbShare 
        }
    }    
}

Measure-Command {
    1..100 | % {
        powershell -noprofile -output xml Get-SmbShare | Out-Default 
    }
}

The result would be:


# Get-SmbShare in Windows PowerShell

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 1
Milliseconds      : 402
Ticks             : 14026910
TotalDays         : 1.6234849537037E-05
TotalHours        : 0.000389636388888889
TotalMinutes      : 0.0233781833333333
TotalSeconds      : 1.402691
TotalMilliseconds : 1402.691

# Get-SmbShare using Invoke-Shim

Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 8
Milliseconds      : 260
Ticks             : 82605931
TotalDays         : 9.56087164351852E-05
TotalHours        : 0.00229460919444444
TotalMinutes      : 0.137676551666667
TotalSeconds      : 8.2605931
TotalMilliseconds : 8260.5931

# Get-SmbShare using PowerShell.exe

Days              : 0
Hours             : 0
Minutes           : 2
Seconds           : 17
Milliseconds      : 305
Ticks             : 1373050396
TotalDays         : 0.00158917869907407
TotalHours        : 0.0381402887777778
TotalMinutes      : 2.28841732666667
TotalSeconds      : 137.3050396
TotalMilliseconds : 137305.0396

A note on WindowsPSModulePath

You can install the WindowsPSModulePath module to add the Windows PowerShell module path to PS Core. This will enable location of Windows PowerShell modules in PowerShell Core. It will not necessarily enable the ability to load those modules in PS Core.

For example, if you try to load the ActiveDirectory module is PS Core, you will receive the following error.

PS C:\Program Files\PowerShell\6.0.1> Install-Module WindowsPSModulePath -Scope CurrentUser -Force
PS C:\Program Files\PowerShell\6.0.1> Add-WindowsPSModulePath
PS C:\Program Files\PowerShell\6.0.1> Import-Module ActiveDirectory
Import-Module : Could not load type 'System.Management.Automation.PSSnapIn' from assembly 'System.Management.Automation, Version=6.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.
At line:1 char:1
+ Import-Module ActiveDirectory
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [Import-Module], TypeLoadException
+ FullyQualifiedErrorId : System.TypeLoadException,Microsoft.PowerShell.Commands.ImportModuleCommand

An idea for the future

Import a Windows PowerShell module into PowerShell Core and generate function wrappers around Invoke-Shim to call into Windows PowerShell.

Import-WindowsPowerShellModule Hyper-V 

$Vms = Get-VM 

The above would generate all the functions in the Hyper-V module like:

function Get-VM {
    param(...)

    Invoke-Shim {
        Get-VM $args...
    } -ArgumentList @(...)
}