I have scripts that need PowerShell Core, but also need to use some ancient modules Microsoft won't bother to update for PowerShell Core (ActiveDirectory/GroupPolicy specifically), so it also needs to run some commands in PowerShell 5.1. Import-Module -UseWindowsPowerShell doesn't cut it, as it makes most information i need unaccessable through serialization.
So my idea was, use PSRemoting to make a new session running 5.1, and connect to this. Should be no problem using a session configuration that's targeting 5.1, right?
I quickly found out that there is no session configuration for 5.1 under Core by default. So i grabbed the default configuration for a 5.1 Session and tried to register it under Core:
$registerPSSessionConfigurationSplat = @{
"RunAsPassword" = ""
"ResourceUri" = "http://schemas.microsoft.com/powershell/microsoft.powershell"
"Capability" = @("Shell")
"PSVersion" = "5.1"
"AutoRestart" = $false
"ExactMatch" = $true
"RunAsVirtualAccount" = $false
"SDKVersion" = "2"
"Uri" = "http://schemas.microsoft.com/powershell/microsoft.powershell"
"MaxConcurrentCommandsPerShell" = "2147483647"
"IdleTimeoutms" = "7200000"
"ParentResourceUri" = "http://schemas.microsoft.com/powershell/microsoft.powershell"
"RunAsUser" = ""
"OutputBufferingMode" = "Block"
"Architecture" = "64"
"MaxMemoryPerShellMB" = "2147483647"
"MaxProcessesPerShell" = "2147483647"
"Filename" = "%windir%\\system32\\pwrshplugin.dll"
"MaxShellsPerUser" = "2147483647"
"MaxShells" = "2147483647"
"SupportsOptions" = $true
"lang" = "de-DE"
"MaxIdleTimeoutms" = "2147483647"
"xmlns" = "http://schemas.microsoft.com/wbem/wsman/1/config/PluginConfiguration"
"Enabled" = $true
"SecurityDescriptorSddl" = "O:NSG:BAD:P(A;;GA;;;BA)(A;;GA;;;IU)(A;;GA;;;RM)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)"
"Name" = "Powershell.5.1"
"ProcessIdleTimeoutSec" = "0"
"MaxConcurrentUsers" = "2147483647"
"UseSharedProcess" = $false
"RunAsVirtualAccountGroups" = ""
"XmlRenderingType" = "text"
"Permission" = "NT-AUTORITÄT\\INTERAKTIV AccessAllowed", "VORDEFINIERT\\Administratoren AccessAllowed", "VORDEFINIERT\\Remoteverwaltungsbenutzer AccessAllowed"
}
Register-PSSessionConfiguration @registerPSSessionConfigurationSplat
It came back with this:
Cannot bind parameter 'PSVersion' to the target. Exception setting "PSVersion": "PowerShell remoting endpoint versioning is not supported on PowerShell Core.
Yea, thanks for nothing. I am out of ideas. What are my options to achieve my goal?
I have a workaround, sort of, by calling powershell.exe with the 5.1 specific code and parse the output, but that's likely prone to several formatting issues that might occur, and i would really like to avoid those.
If, from a PowerShell (Core) 7 session, you're looking to run code in a Windows PowerShell session locally, use the Windows PowerShell Compatibility feature:
Create a Windows PowerShell session with New-PSSession
-UseWindowsPowerShell
.
Pass this session to Invoke-Command
-Session
along with a script block containing statement(s) to be executed in the Windows PowerShell session.
Caveat:
The statements executing inside the Windows PowerShell session support full type fidelity among them.
However, what the script block outputs, i.e. what is seen by the PowerShell 7 caller is subject to the usual type-fidelity limitations that affect any form of cross-process serialization in PowerShell. See this answer for details.
A simple example:
# ->, e.g.: '5.1.26100.2161'
Invoke-Command -Session ($winPsSess = New-PSSession -UseWindowsPowerShell) {
# Place all statements you want to be executed by *Windows PowerShell*
# here.
[string] $PSVersionTable.PSVersion
}
Note:
New-PSSession -UseWindowsPowerShell
creates a hidden powershell.exe
process that hosts a Windows PowerShell session and which the caller communicates with in a manner similar to running a background job.
Notably, this is different from creating a new - bona fide, "loopback" - remoting session, which invoking New-PSSession
without arguments would create, which uses the WS-MAN network transport instead of directly communicating with a hidden background process (of necessity on the same machine).
Notably, the latter - unlike when you use -UseWindowsPowerShell
- only works when invoked from an elevated (run-as-admin) process (see the bottom section for more information).
In the event that you need to conserve resources, you can remove the Windows PowerShell session later with Remove-PSSession $winPsSess
As for your later comments:
as i said, the Configuration "microsoft.powershell" doesn't exist for me on Core.
While Get-PSSessionConfiguration
(which must be run from an elevated session) reports available remoting end-point configurations, only in Windows PowerShell does it report the configurations for both PowerShell editions:
microsoft.powershell
configuration didn't show up.once i figure out why Core isn't the default endpoint for remote sessions
Indeed, using PowerShell remoting as of PowerShell (Core) 7.5.0 still targets Windows PowerShell on remote machines by default, unless overridden via a -ConfigurationName
argument on the client side or via the $PSSessionConfigurationName
preference variable.
See this answer for details.
GitHub issue #11616 suggests changing the default to targeting PowerShell (Core) 7 on remote machines for PowerShell (Core) 7 callers.
Note: I'm hazy on the lower-level details, but I'm hoping the big picture I'm painting is correct.
New-PSSession
-UseWindowsPowerShell
(i.e. creation of a session via the Windows PowerShell Compatibility feature) uses local IPC (inter-process communication) to communicate directly with a hidden (background) powershell.exe
process, i.e. with a Windows PowerShell process; specifically, named pipes are used.
By contrast, New-PSSession
(i.e. creation of a "loopback" remoting session to the local machine) uses the networking infrastructure to communicate with Windows PowerShell, specifically, it uses a WS-MAN-based network transport, in the form of Microsoft's implementation of this standard, WinRM.
$PSSessionConfigurationName
preference variable, which defaults tohttp://schemas.microsoft.com/powershell/Microsoft.PowerShell
.New-PSSession -ConfigurationName microsoft.powershell
The upshot: New-PSSession -UseWindowsPowerShell
(the Windows PowerShell Compatibility feature) is preferable to loopback remoting for several reasons:
PowerShell remoting needn't be enabled on a given machine.
You can run the code from a regular, non-elevated PowerShell 7 session, whereas use of loopback remoting requires elevation (running as admin); this means that your user account doesn't even need to a member of the administrators group.
You don't incur the overhead from communicating via the network infrastructure - though that may not make a noticeable difference in practice.