Reputation: 3464
Starter is used for starting target script process:
# STARTING PS (TARGET) SCRIPT COMPILED TO EXE
$processStartInfo = New-Object System.Diagnostics.ProcessStartInfo
$processStartInfo.FileName = $somePath
$processStartInfo.WorkingDirectory = (Get-Location).Path
$processStartInfo.RedirectStandardInput = $true
$processStartInfo.RedirectStandardError = $true
$processStartInfo.UseShellExecute = $false
$process = [System.Diagnostics.Process]::Start($processStartInfo)
# SOME OTHER CODE ...
# HERE I'M SENDING "EXIT" TO RUNSPACE RUNNING INSIDE TARGET SCRIPT
$process.StandardInput.WriteLineAsync("exit") | Out-Null
Target script (compiled to *.exe) creates runspace that synchonously waits for ReadLine
data from starter
function main {
. createRunspace
while ($true) {
# PARENT LOOP RUNS IN PARALLEL TO RUNSPACE LOOP
sleep -s 1
try {
if ($hash.flags.exit) {
# CLEAN UP AND BREAK
} else {
# RUN OTHER CODE
}
} catch {
# CAN NOT NOTIFY RUNSPACE ABOUT ERROR USING SYNCHRONIZED HASTABLE,
# BECAUSE RUNSPACE IS STUCK ON `ReadLine`.
# ALSO CAN NOT WRITE TO STANDRAD INPUT (DON'T KNOW HOW).
}
}
}
function createRunspace {
#CREATING RUNSPACE WITH SYNCHRONIZED HASTABLE
$hash = [hashtable]::Synchronized(@{ flags: @{} })
$runspace= [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('hash', $hash)
$powershell= [powershell]::Create()
$powershell.Runspace = $runspace
$powershell.AddScript({
# RUNSPACE LOOP
while ($true) {
$value = [Console]::In.ReadLine()
if ($value -eq "exit") {
$hash.flags.exit = $true
break
} elseif ($value -eq "valueFromParent") {
# DO STUFF
}
}
}) | Out
}
# OTHER CODE
. main
Is there a way to send standard input
data from parent to runspace?
Upvotes: 2
Views: 679
Reputation: 437353
The PowerShell-script-packaged-as-an-*.exe
packaging script you're using for some reason doesn't pass stdin input through to the wrapped script, so your script never receives the "exit"
line you send from the caller.
I don't know your exact requirements, but here's a much simplified solution that shows that your approach works in principle:
# The code to execute in the background.
$backgroundScript = {
while ($true) {
$value = [Console]::In.ReadLine()
if ($value -eq "exit") {
"Background: Exiting."
break
}
else {
"Background: Performing task: $value"
}
}
}
# Start the background script.
$processStartInfo = [System.Diagnostics.ProcessStartInfo] @{
FileName = "powershell.exe"
Arguments = '-NoProfile', '-Command', $backgroundScript -replace '"', '\"'
WorkingDirectory = $PWD.ProviderPath
RedirectStandardInput = $true
RedirectStandardError = $true
RedirectStandardOutput = $true
UseShellExecute = $false
}
$process = [System.Diagnostics.Process]::Start($processStartInfo)
# Ask the background script to perform a task.
"Submitting task 'doStuff'"
$process.StandardInput.WriteLine("doStuff")
# Ask the background script to exit.
"Submitting exit request."
$process.StandardInput.WriteLine("exit")
# Wait for the background script's process to exit,
# then print its stdout.
$process.WaitForExit()
$process.StandardOutput.ReadToEnd()
The above yields:
Submitting task 'doStuff'
Submitting exit request.
Background: Performing task: doStuff
Background: Exiting.
Upvotes: 1