├── images └── powershim.gif ├── powershim.examples.ps1 ├── powershim.performance.ps1 ├── LICENSE ├── powershim.psm1 └── README.md /images/powershim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamdriscoll/powershim/HEAD/images/powershim.gif -------------------------------------------------------------------------------- /powershim.examples.ps1: -------------------------------------------------------------------------------- 1 | Import-Module (Join-Path $PSScriptRoot 'powershim.psm1') -Force 2 | 3 | Get-SmbShare 4 | 5 | Invoke-Shim { 6 | Get-SmbShare 7 | } 8 | 9 | Get-VM 10 | 11 | Invoke-Shim { 12 | Get-VM 13 | } -------------------------------------------------------------------------------- /powershim.performance.ps1: -------------------------------------------------------------------------------- 1 | Import-Module (Join-Path $PSScriptRoot 'powershim.psm1') -Force 2 | 3 | Measure-Command { 4 | 1..100 | % { 5 | Invoke-Shim { 6 | Get-SmbShare 7 | } 8 | } 9 | } 10 | 11 | Measure-Command { 12 | 1..100 | % { 13 | powershell -noprofile -output xml Get-SmbShare | Out-Default 14 | } 15 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Adam Driscoll 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /powershim.psm1: -------------------------------------------------------------------------------- 1 | function New-OutOfProcRunspace { 2 | param($ProcessId) 3 | 4 | $ci = New-Object -TypeName System.Management.Automation.Runspaces.NamedPipeConnectionInfo -ArgumentList @($ProcessId) 5 | $tt = [System.Management.Automation.Runspaces.TypeTable]::LoadDefaultTypeFiles() 6 | 7 | $Runspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace($ci, $Host, $tt) 8 | 9 | $Runspace.Open() 10 | 11 | $PowerShell = $null 12 | try { 13 | $PowerShell = [System.Management.Automation.PowerShell]::Create() 14 | $PowerShell.Runspace = $Runspace 15 | $PowerShell.AddScript("`$Env:PSModulePath = (Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment').GetValue('PSModulePath')") | Out-Null 16 | 17 | $PowerShell.Invoke() 18 | } 19 | finally { 20 | $PowerShell.Dispose() 21 | } 22 | 23 | $Runspace 24 | } 25 | 26 | function Invoke-Shim { 27 | param($ScriptBlock, $ArgumentList) 28 | 29 | $PowerShell = $null 30 | try { 31 | $PowerShell = $ScriptBlock.GetPowerShell() 32 | $PowerShell.Runspace = $Runspace 33 | $PowerShell.Invoke() 34 | } 35 | finally { 36 | $PowerShell.Dispose() 37 | } 38 | } 39 | 40 | $Process = Start-Process PowerShell -ArgumentList @("-NoExit") -PassThru -WindowStyle Hidden 41 | $Runspace = New-OutOfProcRunspace -ProcessId $Process.Id -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerShim 2 | 3 | ## Invoke Windows PowerShell from PowerShell Core 4 | 5 | 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. 6 | 7 | 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. 8 | 9 | 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. 10 | 11 | Cmdlet return values are serialized over PowerShell remoting so you will have objects returned by Invoke-Shim. 12 | 13 | ## Give it a shot 14 | 15 | ![](./images/powershim.gif) 16 | 17 | ``` 18 | PS> Import-Module PowerShim 19 | PS> Get-SmbShare 20 | PS> Invoke-Shim { 21 | Get-SmbShare 22 | } 23 | ``` 24 | 25 | ## Why? 26 | 27 | You can also achieve this by just calling PowerShell. 28 | 29 | ``` 30 | powershell -NoProfile -Output XML Get-SmbShare | Out-Default 31 | ``` 32 | 33 | The main reason is likely performance. Assume you run the following test. 34 | 35 | ``` 36 | Measure-Command { 37 | 1..100 | % { 38 | Get-SmbShare 39 | } 40 | } 41 | 42 | Measure-Command { 43 | 1..100 | % { 44 | Invoke-Shim { 45 | Get-SmbShare 46 | } 47 | } 48 | } 49 | 50 | Measure-Command { 51 | 1..100 | % { 52 | powershell -noprofile -output xml Get-SmbShare | Out-Default 53 | } 54 | } 55 | ``` 56 | 57 | The result would be: 58 | 59 | ``` 60 | 61 | # Get-SmbShare in Windows PowerShell 62 | 63 | Days : 0 64 | Hours : 0 65 | Minutes : 0 66 | Seconds : 1 67 | Milliseconds : 402 68 | Ticks : 14026910 69 | TotalDays : 1.6234849537037E-05 70 | TotalHours : 0.000389636388888889 71 | TotalMinutes : 0.0233781833333333 72 | TotalSeconds : 1.402691 73 | TotalMilliseconds : 1402.691 74 | 75 | # Get-SmbShare using Invoke-Shim 76 | 77 | Days : 0 78 | Hours : 0 79 | Minutes : 0 80 | Seconds : 8 81 | Milliseconds : 260 82 | Ticks : 82605931 83 | TotalDays : 9.56087164351852E-05 84 | TotalHours : 0.00229460919444444 85 | TotalMinutes : 0.137676551666667 86 | TotalSeconds : 8.2605931 87 | TotalMilliseconds : 8260.5931 88 | 89 | # Get-SmbShare using PowerShell.exe 90 | 91 | Days : 0 92 | Hours : 0 93 | Minutes : 2 94 | Seconds : 17 95 | Milliseconds : 305 96 | Ticks : 1373050396 97 | TotalDays : 0.00158917869907407 98 | TotalHours : 0.0381402887777778 99 | TotalMinutes : 2.28841732666667 100 | TotalSeconds : 137.3050396 101 | TotalMilliseconds : 137305.0396 102 | ``` 103 | 104 | ## A note on WindowsPSModulePath 105 | 106 | You can install the [WindowsPSModulePath](https://www.powershellgallery.com/packages/WindowsPSModulePath/1.0.0) 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. 107 | 108 | For example, if you try to load the ActiveDirectory module is PS Core, you will receive the following error. 109 | 110 | ``` 111 | PS C:\Program Files\PowerShell\6.0.1> Install-Module WindowsPSModulePath -Scope CurrentUser -Force 112 | PS C:\Program Files\PowerShell\6.0.1> Add-WindowsPSModulePath 113 | PS C:\Program Files\PowerShell\6.0.1> Import-Module ActiveDirectory 114 | Import-Module : Could not load type 'System.Management.Automation.PSSnapIn' from assembly 'System.Management.Automation, Version=6.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. 115 | At line:1 char:1 116 | + Import-Module ActiveDirectory 117 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 118 | + CategoryInfo : NotSpecified: (:) [Import-Module], TypeLoadException 119 | + FullyQualifiedErrorId : System.TypeLoadException,Microsoft.PowerShell.Commands.ImportModuleCommand 120 | 121 | ``` 122 | 123 | ## An idea for the future 124 | 125 | Import a Windows PowerShell module into PowerShell Core and generate function wrappers around Invoke-Shim to call into Windows PowerShell. 126 | 127 | ``` 128 | Import-WindowsPowerShellModule Hyper-V 129 | 130 | $Vms = Get-VM 131 | ``` 132 | 133 | The above would generate all the functions in the Hyper-V module like: 134 | 135 | ``` 136 | function Get-VM { 137 | param(...) 138 | 139 | Invoke-Shim { 140 | Get-VM $args... 141 | } -ArgumentList @(...) 142 | } 143 | ``` 144 | 145 | 146 | --------------------------------------------------------------------------------