Last active
          May 9, 2025 11:30 
        
      - 
      
- 
        Save jborean93/7d4cb107fa06251b080fa10ec844893e to your computer and use it in GitHub Desktop. 
    Windows PowerShell SSH Remoting Stub
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | <# | |
| .SYNOPSIS | |
| Windows PowerShell SSH Server Subsystem Shim. | |
| .DESCRIPTION | |
| Used as a basic wrapper for Windows PowerShell that allows it to be used as a target for SSH based remoting sessions. | |
| This allows a PowerShell client to target a Windows host through SSH without having PowerShell 7 installed. | |
| .NOTES | |
| This is experimental and used as a POC. | |
| It is not guaranteed to be stable or bug free. | |
| See https://gist.github.com/jborean93/7d4cb107fa06251b080fa10ec844893e?permalink_comment_id=4093819#gistcomment-4093819 for more info. | |
| #> | |
| [CmdletBinding()] | |
| param () | |
| $ErrorActionPreference = 'Stop' | |
| Add-Type -Namespace PSSSH -Name NativeMethods -MemberDefinition @' | |
| [DllImport("Kernel32.dll", EntryPoint = "GetStdHandle", SetLastError = true)] | |
| private static extern IntPtr GetStdHandleNative( | |
| int nStdHandle); | |
| public static Microsoft.Win32.SafeHandles.SafeFileHandle GetStdHandle(int handleId) | |
| { | |
| IntPtr handle = GetStdHandleNative(handleId); | |
| if (handle == (IntPtr)(-1)) { | |
| throw new System.ComponentModel.Win32Exception(); | |
| } | |
| // Std handles should not be freed. | |
| return new Microsoft.Win32.SafeHandles.SafeFileHandle(handle, false); | |
| } | |
| '@ | |
| # Cannot use [System.Console]::OpenStandardInput() as it's a ConsoleStream and | |
| # will be unable to read input from an SSH based process. | |
| # https://github.com/PowerShell/PowerShell/issues/14478#issuecomment-1064764004 | |
| $stdin = [PSSSH.NativeMethods]::GetStdHandle(-10) | |
| $stdinFS = New-Object System.IO.FileStream $stdin, "Read" | |
| $version = $PSVersionTable.PSVersion | |
| $proc = New-Object System.Diagnostics.Process | |
| $proc.StartInfo.FileName = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" | |
| $proc.StartInfo.Arguments = "-Version $($version.Major).$($version.Minor) -NoLogo -ServerMode" | |
| $proc.StartInfo.CreateNoWindow = $true | |
| $proc.StartInfo.RedirectStandardInput = $true | |
| $proc.StartInfo.UseShellExecute = $false | |
| $null = $proc.Start() | |
| $utf8 = New-Object System.Text.UTF8Encoding $false | |
| $stdinSR = New-Object System.IO.StreamReader $stdinFS, $utf8 | |
| while ($true) { | |
| $line = $stdinSR.ReadLine() | |
| $proc.StandardInput.WriteLine($line) | |
| $proc.StandardInput.Flush() | |
| # Sent by the server to indicate the Runspace Pool is closed. | |
| if ($line.StartsWith("<CloseAck PSGuid='00000000-0000-0000-0000-000000000000' />")) { | |
| break | |
| } | |
| } | |
| $proc | Stop-Process -Force | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
            
This is absolute gold.
I was pulling my hairs out trying to get PS7 -> PS5.1 working over SSH. Your script seems to work beautifully.
You deserve a cookie, my man.