You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
244 lines
8.1 KiB
244 lines
8.1 KiB
#!SEMICOLONS must be placed after each command as scriptdata needs to be sent to powershell directly with the -c parameter! |
|
; |
|
|
|
if ($PSVersionTable.PSVersion.Major -le 5) { |
|
# For Windows PowerShell, we want to remove any PowerShell 7 paths from PSModulePath |
|
#snipped from https://github.com/PowerShell/DSC/pull/777/commits/af9b99a4d38e0cf1e54c4bbd89cbb6a8a8598c4e |
|
#Presumably users are supposed to know not to have custom paths for powershell desktop containing a 'powershell' subfolder?? |
|
; |
|
$env:PSModulePath = ($env:PSModulePath -split ';' | Where-Object { $_ -notlike '*\powershell\*' }) -join ';'; |
|
}; |
|
|
|
$helper = @' |
|
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Linq.Expressions; |
|
using System.Management.Automation.Runspaces; |
|
|
|
public class RunspacedDelegateFactory |
|
{ |
|
public static Delegate NewRunspacedDelegate(Delegate _delegate, Runspace runspace) |
|
{ |
|
Action setRunspace = () => Runspace.DefaultRunspace = runspace; |
|
return ConcatActionToDelegate(setRunspace, _delegate); |
|
} |
|
|
|
private static Expression ExpressionInvoke(Delegate _delegate, params Expression[] arguments) |
|
{ |
|
var invokeMethod = _delegate.GetType().GetMethod("Invoke"); |
|
return Expression.Call(Expression.Constant(_delegate), invokeMethod, arguments); |
|
} |
|
|
|
public static Delegate ConcatActionToDelegate(Action a, Delegate d) |
|
{ |
|
var parameters = |
|
d.GetType().GetMethod("Invoke").GetParameters() |
|
.Select(p => Expression.Parameter(p.ParameterType, p.Name)) |
|
.ToArray(); |
|
|
|
Expression body = Expression.Block(ExpressionInvoke(a), ExpressionInvoke(d, parameters)); |
|
var lambda = Expression.Lambda(d.GetType(), body, parameters); |
|
var compiled = lambda.Compile(); |
|
return compiled; |
|
} |
|
} |
|
'@ |
|
add-type -TypeDefinition $helper |
|
|
|
#region console |
|
|
|
$consoleModeSource = @" |
|
using System; |
|
using System.Runtime.InteropServices; |
|
|
|
public class NativeConsoleMethods |
|
{ |
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] |
|
public static extern IntPtr GetStdHandle(int handleId); |
|
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] |
|
public static extern bool GetConsoleMode(IntPtr hConsoleOutput, out uint dwMode); |
|
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] |
|
public static extern bool SetConsoleMode(IntPtr hConsoleOutput, uint dwMode); |
|
|
|
public static uint GetConsoleMode(bool input = false) |
|
{ |
|
var handle = GetStdHandle(input ? -10 : -11); |
|
uint mode; |
|
if (GetConsoleMode(handle, out mode)) |
|
{ |
|
return mode; |
|
} |
|
return 0xffffffff; |
|
} |
|
|
|
public static uint SetConsoleMode(bool input, uint mode) |
|
{ |
|
var handle = GetStdHandle(input ? -10 : -11); |
|
if (SetConsoleMode(handle, mode)) |
|
{ |
|
return GetConsoleMode(input); |
|
} |
|
return 0xffffffff; |
|
} |
|
} |
|
"@ |
|
; |
|
[Flags()] |
|
enum ConsoleModeInputFlags |
|
{ |
|
ENABLE_LINE_INPUT = 0x0002 |
|
ENABLE_ECHO_INPUT = 0x0004 |
|
}; |
|
|
|
if (!('NativeConsoleMethods' -as [System.Type])) { |
|
Add-Type $consoleModeSource |
|
} |
|
|
|
function psmain { |
|
param ( |
|
[validateSet('enableRaw', 'disableRaw')] |
|
[string]$Action |
|
); |
|
# $inputflags = Get-ConsoleMode -StandardInput; |
|
if (!('NativeConsoleMethods' -as [System.Type])) { |
|
Add-Type $consoleModeSource |
|
} |
|
$inputFlags = [NativeConsoleMethods]::GetConsoleMode($true); |
|
$resultflags = $inputflags; |
|
if (($inputflags -band [ConsoleModeInputFlags]::ENABLE_LINE_INPUT) -eq [ConsoleModeInputFlags]::ENABLE_LINE_INPUT) { |
|
#cooked mode |
|
$initialstate = "cooked"; |
|
if ($action -eq "enableraw") { |
|
#disable cooked flags |
|
$disable = [uint32](-bnot [uint32][ConsoleModeInputFlags]::ENABLE_LINE_INPUT) -band ( -bnot [uint32][ConsoleModeInputFlags]::ENABLE_ECHO_INPUT); |
|
$adjustedflags = $inputflags -band ($disable); |
|
$resultflags = [NativeConsoleMethods]::SetConsoleMode($true,$adjustedflags); |
|
} |
|
} else { |
|
#raw mode |
|
$initialstate = "raw"; |
|
if ($action -eq "disableraw") { |
|
#set cooked flags |
|
$adjustedflags = $inputflags -bor [ConsoleModeInputFlags]::ENABLE_LINE_INPUT -bor [ConsoleModeInputFlags]::ENABLE_ECHO_INPUT; |
|
$resultflags = [NativeConsoleMethods]::SetConsoleMode($true,$adjustedflags); |
|
} |
|
} |
|
#return in format that can act as a tcl dict |
|
#write-host "startflags: $inputflags initialstate: $initialstate action: $Action endflags: $resultflags"; |
|
}; |
|
# psmain 'enableRaw'; |
|
#endregion console |
|
|
|
|
|
$consoleid = $args[0]; |
|
if ([string]::IsNullOrEmpty($consoleid)) { |
|
$consoleid= "<punkshell_consoleid>" |
|
}; |
|
$pipeName = "punkshell_ps_consolemode_$consoleid"; |
|
"pipename: $pipeName"; |
|
|
|
$pipeServer = New-Object System.IO.Pipes.NamedPipeServerStream( |
|
$pipeName, |
|
[System.IO.Pipes.PipeDirection]::In, |
|
1, |
|
[System.IO.Pipes.PipeTransmissionMode]::Byte, |
|
[System.IO.Pipes.PipeOptions]::Asynchronous |
|
); |
|
#$pipeServer = New-Object System.IO.Pipes.NamedPipeServerStream($pipeName); |
|
; |
|
|
|
# Define the callback function for when a client connects |
|
$callback = [System.AsyncCallback]{ |
|
param($asyncResult); |
|
|
|
$se = $asyncResult.AsyncState.Sync; |
|
$ps = $asyncResult.AsyncState.Pipeserver; |
|
$pn = $asyncResult.AsyncState.Pipename; |
|
Write-Host "Client connected - $pn"; |
|
|
|
# End the asynchronous wait operation |
|
; |
|
$ps.EndWaitForConnection($asyncResult); |
|
#?? |
|
; |
|
# You can now perform read/write operations with the client |
|
# For example, create a StreamReader and StreamWriter |
|
; |
|
$streamReader = New-Object System.IO.StreamReader($ps); |
|
#$streamWriter = New-Object System.IO.StreamWriter($pipeServer); |
|
#$streamWriter.AutoFlush = $true; |
|
try { |
|
$message = $streamReader.ReadLine(); |
|
Write-Host "Received: $message"; |
|
; |
|
#$asyncResult.Message = $message; |
|
; |
|
} catch { |
|
Write-Error "Error during communication: $($_.Exception.Message)"; |
|
} finally { |
|
# sever connection with client but keep the named pipe |
|
if ($streamReader -ne $null) { |
|
Write-Host "streamreader closing"; |
|
$streamReader.Close(); |
|
Write-Host "streamreader closed"; |
|
} |
|
Write-Host "Client disconnecting. $pn"; |
|
$ps.Disconnect(); |
|
Write-Host "Client disconnected. $pn"; |
|
#$ps.Disconnect(); |
|
#[System.Console]::Out.Flush(); |
|
; |
|
}; |
|
write-host "HERE"; |
|
|
|
$se.set(); |
|
|
|
# Optionally, you can call BeginWaitForConnection again to listen for another client |
|
# if your server is designed for multiple connections over time. |
|
# $pipeServer.BeginWaitForConnection($callback, $null) |
|
$ps.BeginWaitForConnection($callback, $null) |
|
; |
|
}; |
|
|
|
$syncEvent = New-Object System.Threading.ManualResetEvent($false); |
|
|
|
$runspacedDelegate = [RunspacedDelegateFactory]::NewRunspacedDelegate($callback, [Runspace]::DefaultRunspace); |
|
|
|
$loop = 0; |
|
while ($loop -lt 15) { |
|
Write-Host "Waiting for client connection on pipe '$pipeName'..."; |
|
# Begin the asynchronous wait for a client connection |
|
; |
|
$state = [PSCustomObject]@{ |
|
Loop = $loop |
|
Sync = $SyncEvent |
|
Pipeserver = $pipeServer |
|
Pipename = $pipename |
|
Message = "" |
|
}; |
|
$x = $pipeServer.BeginWaitForConnection($runspacedDelegate, $state ); |
|
$syncEvent.WaitOne(10000); |
|
# $x | Get-Member | write-host |
|
; |
|
write-host "msg: $(${x}.AsyncState.Message)" |
|
if ($x.IsCompleted) { |
|
write-host "completed"; |
|
}; |
|
$SyncEvent.reset(); |
|
|
|
$loop += 1; |
|
#$cli = New-Object System.IO.Pipes.NamedPipeClientStream($pipeName); |
|
#$cli.w |
|
} |
|
|
|
# Keep the script running to allow the asynchronous operation to complete |
|
# In a real-world scenario, you might have a loop or other logic here. |
|
#Read-Host "Press Enter to exit the server." |
|
|
|
# Clean up |
|
$pipeServer.Dispose(); |
|
|
|
|
|
|