concurrent do-loops in powershell

I'm looking for the simplest and/or best way to run two do-loops concurrently. I can do this with two separate scripts running in two separate windows...but I'm sure there's a more efficient way. I played a little with the "workspace" method, but haven't yet figured it all out. Is the workspace approach the best way? Is it the easiest way? A sample script that launches two do-until loops concurrently would be appreciated. Here are to two scripts I have running in separate windows now:

SCRIPT 1--

$relayoff = {

do {
$request = get-content relay.txt
} until ($request -notmatch '0')

&$relayon

}

$relayon = {

$port= new-object system.io.ports.serialport com7,4800,none,8,one

$port.open()

echo 1 > relay.txt

do {
$hold = get-content relay.txt
$port.writeline("1InthebeginningwastheWord,andtheWordwaswithGod,andtheWordwasGod.2HewasinthebeginningwithGod.3AllthingsweremadethroughHim,andwithoutHimnothingwasmadethatwasmade.4InHimwaslife,andthelifewasthelightofmen.5Andthelightshinesinthedarkness,andthedarknessdidnotcomprehend[a]it. ")
} until ($hold -match '0')

$port.close()

&$relayoff

}

&$relayoff

SCRIPT 2--

$wait = {

do {
$read = get-content relay.txt
$request = $read
} until ($read -notmatch '0')

do {
$read = get-content relay.txt
} until ($read -match '1')

&$play

}

$play = {

.\sounder.exe $request

Wait-Process sounder

echo 0 > relay.txt

&$wait

}

$read = get-content relay.txt

&$wait

Flags and other information are passed between these two scripts and a GUI via the text file "relay.txt".  So currently there are three programs running concurrently: two powershell windows and the GUI.  If I can combine the two scripts, I will eliminate one of these windows. I'll still need the text file for the sake of the GUI, but not for the do-loop variables.


  • Edited by Chalk-X CPG Monday, February 09, 2015 7:13 PM
February 9th, 2015 10:06pm

Free Windows Admin Tool Kit Click here and download it now
February 9th, 2015 10:09pm

I'll look at this method.  Is this simpler than the "workspace" approach?
  Can you give me an example with two do-until loops comparing variables and running concurrently?

Okay...looking at the help content.  Looks pretty simple.  Question: If I start two jobs, JOB1 and JOB2...and JOB1 creates a variable, can that variable be read by JOB2?

  • Edited by Chalk-X CPG Monday, February 09, 2015 7:50 PM
February 9th, 2015 10:14pm

I'll look at this method.  Is this simpler than the "workspace" approach?
  Can you give me an example with two do-until loops comparing variables and running concurrently?

Okay...looking at the help content.  Looks pretty simple.  Question: If I start two jobs, JOB1 and JOB2...and JOB1 creates a variable, can that variable be read by JOB2?

Variables generally cannot be shared between jobs.  You can use a synchronized hash table or collection to share information between runspaces, but that's different threads in the same process.  Never tried it with jobs, which is not going to be the same environment since the jobs are each a separate process.
Free Windows Admin Tool Kit Click here and download it now
February 9th, 2015 11:51pm

Okay...So I created a simple test script designed concurrently run a couple of (actually three) do-loops that all read the contents of a text file and echo responses back to the screen:

$job1 = {

$tweedledee = {

do {
$read = get-content C:\Users\Bob\Desktop\test\mediate.txt
} until ($read -match 'hello tweedledee')

echo 'tweedledee is alive'

&$returndee

}


$returndee = {

&$tweedledee

}

&$tweedledee

}


$job3 = {

$tweedledum = {

do {
$read = get-content C:\Users\Bob\Desktop\test\mediate.txt
} until ($read -match 'hello tweedledum')

echo 'tweedledum is alive'

&$returndum

}

$returndum = {

&$tweedledum

}

&$tweedledum

}

$monitor = {

do {
$check2 = $check1
$check1 = get-content mediate.txt
} until ($check1 -notmatch $check2)

&$screenecho

}

$screenecho = {

echo $check1

&$returnmonitor

}


$returnmonitor = {

&$monitor

}

$check1 = get-content mediate.txt
start-job -scriptblock {$job1}
start-job -scriptblock {$job3}
&$monitor

So far, of the three subroutines in this script, only the $monitor is responding to changes in the text file.  What am I doing wrong with these start-job commands?


  • Edited by Chalk-X CPG Thursday, February 12, 2015 7:50 PM
February 12th, 2015 10:48pm

First you need to post your code as formatted code so it is readable.  Next you need to understand that embedded loops are not concurrent in the sense I think you mean.

Jobs are asynchronous and can run simultaneously although I would not stress the term "concurrent" with jobs.

Free Windows Admin Tool Kit Click here and download it now
February 12th, 2015 10:51pm

There are not three jobs there are two jobs number job1 and job3

Here is how to "monitor" jobs

Get-Job | Wait-Job

This is the only useful code in $job1

$job1 = {
    do {
        $read = get-content C:\Users\Bob\Desktop\test\mediate.txt
    } until ($read -match 'hello tweedledee')   
    'tweedledee is alive'
}
It will likely never complete.  Start by creating and testing a job before adding complexity that adds to your confusion. One step at a time.

Here is what you code looks like formatted. It is just a lot of nonsense and does nothing functional or useful.

$job1 = {
    $tweedledee = {
        do {
            $read = get-content C:\Users\Bob\Desktop\test\mediate.txt
        } until ($read -match 'hello tweedledee')
        echo 'tweedledee is alive'
        &$returndee
    }
    $returndee = {
        &$tweedledee
    }
    &$tweedledee
}


$job3 = {
    $tweedledum = {
        do {
            $read = get-content C:\Users\Bob\Desktop\test\mediate.txt
        } until ($read -match 'hello tweedledum')
        echo 'tweedledum is alive'
        &$returndum
    }
    $returndum = {
        &$tweedledum
    }
    &$tweedledum
}

$monitor = {
    do {
        $check2 = $check1
        $check1 = get-content mediate.txt
    } until ($check1 -notmatch $check2)
    &$screenecho
}

$screenecho = {
     echo $check1
    &$returnmonitor
}

$returnmonitor = {
    &$monitor
}

$check1=get-content mediate.txt
start-job -scriptblock $job1 
start-job -scriptblock $job3
$monitor.Invoke()

We are better to use "Invoke" on a scriptblock although there is not point in using script blocks for any of this except the main job piece.

February 12th, 2015 11:01pm

Again, jrv, with the ARROGANCE and INSULTS...and no REAL ANSWERS.  You should just stay away from my postings if this is all you have to offer.
Free Windows Admin Tool Kit Click here and download it now
February 14th, 2015 12:04am

So, without pointless arrogance and insults, can someone tell me why the jobs created in my script are not passing information through the text file?
February 14th, 2015 12:18am

I haven't tested your code, but you appear to be under the impression that the echo commands are going to write data back to your local session as soon as it happens.

You have to do a Receive-Job to get anything back from a background job, and you're not doing that anywhere in your script.

That's all spelled out in the help file Bill gave you the reference to.

Free Windows Admin Tool Kit Click here and download it now
February 14th, 2015 12:42am

So, without pointless arrogance and insults, can someone tell me why the jobs created in my script are not passing information through the text file?

I think the issue is that none can figure out what you are talking about because your jobs do not really do anything that makes any sense.

This is not an insult it is just the plain truth.  You seem to not understand what a job is.  It takes a scriptblock that outputs objects and holds the output.  I tseems you are stuck thinking that somehow inside of a job a set of dol loops will become concurrent.  They won't  Only the jobs will.  You have two jobs which will appear to run concurrently.  You must use a polling mechanism to check for job completion. "Wait-Job" is the builtin polling scheme.

I recommend spending a little more time studying the very basic components of Powershell and programming in general.  It will help you avoid further misunderstandings.

The help posted for you would have cleared this up had you taken time to read it.  Learning how to program for the first time can be very confusing. It is worth sitting down ad experimenting carefully with each new thing you learn.

February 14th, 2015 3:42am

The script that we're talking about doesn't do anything useful.  It's a simple example that illustrates what I'm trying to accomplish. I thought it would be easier for everyone to follow than the actual script that I'm working on. I'm not expecting these jobs to echo information back to my local session.  As the script indicates I'm expecting them to write information into a text file, from which I can access it with a GUI.  I'm attempting to start two jobs that are perpetual, meaning that the do-loops in these jobs re-launch after each write to the text file. Will the start-job command not run script that's designed to perpetually loop? I need someone to work with me here. 
  • Edited by Chalk-X CPG Sunday, February 15, 2015 1:57 AM
Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 4:08am

Here is a job that loops forever and writes to a file.

start-Job -Scriptblock {while($true){ "$([datetime]::Now) file message out to file" | Out-File c:\temp\myfile.txt -append;sleep 10}}
cat  \temp\myfile.txt -tail 1 -wait

February 15th, 2015 4:30am

I have and will continue to experiment carefully with each new thing I learn.  It frustrates me that I have to wade through so much self-serving banter and personal insults to get one little nugget of real information that I can actually use.  Each time we've had these unpleasant exchanges I've noticed that you don't seem to understand my actual question or the goals I'm describing.  On another thread you eventually caught on and gave me some very useful information and tools that I was able to implement in that project.  If there's anything unclear in my postings, just ask me questions and I'll try to clarify. I'm not trying to build a nuclear aircraft carrier, just a sailboat...so throw me a hammer or a nail. Thanks in advance.

Let me try again to explain my goal and my question.  I need two perpetual loops running concurrently that can read data from and write data to a text file.  I don't need to monitor them or retrieve results from them through powershell, but only via the text file.  I have my reasons for this.  The two concurrently running scripts or jobs will need to pass data back and forth between them via the text file, and a third party GUI will also access the text file. As I stated earlier, I have achieved this with two separate powershell scripts running in two separate windows, but I'm hoping to find a better way.


  • Edited by Chalk-X CPG Sunday, February 15, 2015 1:59 AM
Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 4:38am

Your descriptions may be crystal clear to you but it appears that none of us can figure out exactly what it is that you are asking.

If you have script that run stand alone then just run it as a job.  I don't see why that needs odd examples of scriptblocks calling each other in an endless loop.

Just use a loop
while($true){
     # code here
}

That is an endless loop. Nothing has to call anything.

A good part of the confusion and your frustration come from your lack of very fundamental concepts of scripting/programming.  Once you address that you will find that things will get much easier.

February 15th, 2015 4:45am

Correct.  I'm not using "receive-job" because I'm expecting these jobs to write results to a text file, by which information will pass between the jobs and a third party GUI.  So...If these jobs are actually running in the background, shouldn't I be able to see them affecting change in the text file?
Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 5:15am

Only one process can have a file open for writing.

February 15th, 2015 5:20am

Thanks jrv. First, my apologies to everyone.  I went back to the top of my post and realized that the example script that I posted does NOT have the jobs writing to a text file...I obviously copied and pasted the wrong script.  I will re-post shortly with one that will make more sense.  Secondly, I must for this application have TWO loops running because one of them will be sending short spurts of data to a com port during the same time interval that the other loop is playing a media file. I realize it's hard to make sense of this...but this is what's required by the particular external hardware that I'm automating.  Standby for a more sensible script example.
Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 5:32am

Alright.  Here's an example of what I was actually testing.  I'm using notepad to make changes to the text file so that it reads "hello". But the background job, which I'm expecting to overwrite the text file with "background loop is working," is not responding.  (The $monitor routine in the foreground script simply detects changes to the text file and echoes them to the screen). 

$job1 = {
    $backgroundloop
= {
       
do {
            $read
= get-content mediate.txt
       
} until ($read -match 'hello')
        echo
'background loop is working' > mediate.txt
       
&$returntoloop
   
}
    $returntoloop
= {
       
&$backgroundloop
   
}
   
&$backgroundloop
}

$monitor = {
   
do {
        $check2
= $check1
        $check1
= get-content mediate.txt
   
} until ($check1 -notmatch $check2)
   
&$screenecho
}

$screenecho
= {
     echo $check1
   
&$returnmonitor
}

$returnmonitor
= {
   
&$monitor
}

$check1
=get-content mediate.txt
start
-job -scriptblock $job1
start
-job -scriptblock $job3
$monitor.Invoke()

February 15th, 2015 6:14am

Have you tried breaking out of the monitor script and doing a Receive-Job to see if there's any clues in the Jobs error or warning streams?
Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 6:35am

It doesn't return anything.  Powershell indicates the job is running.  I made several edits to the text file, then used ctrl-c to close the foreground (monitor) script, then typed "receive-job -name job1".  Is this procedure valid?
February 15th, 2015 7:11am

THe loops willnever workfor anumver of reasons.

1. A very tight loop that bothtries to read and write to the same for willliley deadlock on itself.
2. Multiple processes writing to the same file wil conflict.
3.  The structure of the jobes makes no sense.

Example:

$job1 = {
   while($true){ 
       do {
            $read = get-content mediate.txt
        } until ($read -match 'hello')
        echo 'background loop is working' > mediate.txt
    }
}

That accomplishes what you script assumes it is trying to do.  As I noted before you do not need and shouldnot use scriptblocks calling script blocks.

Here is a modified version that will be more likely to work.

''|Out-File  c:\test\mediate.txt
$jobscript = {
   while($true){  
		'starting outer loop'
       	do {
            $read = get-content c:\test\mediate.txt
			$read
			Start-Sleep 1
        } until ($read -match 'hello')
		'out of loop'
        'background loop is working'| Out-File c:\test\mediate.txt
		Start-Sleep 1
    }
}
$myjob=Start-Job -ScriptBlock $jobscript
# start monitor and write to file after starting the followong loop
while($true){
	Start-Sleep 1
	 $myjob  | Get-Job | Receive-Job 
}



In second PowerShell window paste these after starting the above:

 'goodbye'|Out-File  c:\test\mediate.txt
'sdfsdfdfdsfdsfsd'|Out-File  c:\test\mediate.txt
'hello'|Out-File  c:\test\mediate.txt

PS C:\scripts>

Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 7:21am

Here's what I'm seeing.  I removed the "monitor" portion of the script completely.  Launched the script and received the indication from powershell that it was "running".  I then sent "hello" to the text file, and checked for the appropriate response from job1, but it wasn't there.  So I typed "get-job", and received an indication that the job state was "completed". Apparently the job is not "staying alive" as expected. Maybe one of you guys can point me to the error of my ways.
February 15th, 2015 7:28am

Now look at what happens when you try to run two loops to the same file:

Get-Job | Remove-JOb -force
$jobscript = { while($true){ 'JOB1:starting outer loop' do { if($read=get-content c:\test\mediate.txt){ "JOB1: $read" }else{ 'JOB1: read empty' } Start-Sleep 1 } until ($read -match 'hello') 'JOB1:out of loop' 'goodbye'| Out-File c:\test\mediate.txt Start-Sleep 1 } } $myjob=Start-Job -ScriptBlock $jobscript $jobscript2 = { while($true){ 'JOB2:starting outer loop' do { if($read=get-content c:\test\mediate.txt){ "JOB2: $read" }else{ 'JOB2: read empty' } Start-Sleep 1 } until ($read -match 'goodbye') 'JOB2:out of loop' 'hello'| Out-File c:\test\mediate.txt Start-Sleep 1 } } $myjob2=Start-Job -ScriptBlock $jobscript2 while($true){ Get-Job | Receive-Job Start-Sleep 1 }

All of this code has been run and works as specified.

Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 7:32am

Thanks, jrv.  I'll study this.
February 15th, 2015 7:43am

Here is a way to get them to start and stay in sync because it forces a content into the file if it gets written as empty.

Get-Job | Remove-Job -force
#preset file
'goodbye'| Out-File c:\test\mediate.txt
$jobscript = {
   while($true){  
       	do {
            if($read=get-content c:\test\mediate.txt){
				Write-Host -fore Blue "JOB1: $read" -back yellow
            }else{
				Write-Host 'JOB1: read empty'
            }
			Write-Host 'JOB1:hello fron job'
			Start-Sleep 2
        } until ($read -match 'hello')
		Write-Host  'JOB1:out of loop'
        'goodbye'| Out-File c:\test\mediate.txt
		Start-Sleep 2
    }
}
$j=Start-Job -ScriptBlock $jobscript

$jobscript2 = {
   while($true){  
       	do {
            if($read=get-content c:\test\mediate.txt){
				Write-Host -fore blue "JOB2: $read" -back white
            }else{
				Write-Host -fore Green 'JOB2: read empty'
            }
			Write-Host  'JOB2:hello from job' -fore green
			Start-Sleep 2
        } until ($read -match 'goodbye')
		Write-Host -fore Green 'JOB2:out of loop'
        'hello'| Out-File c:\test\mediate.txt
		Start-Sleep 2
    }
}
$j=Start-Job -ScriptBlock $jobscript2

while($true){get-job|receive-job;sleep 1}


Just copy and paste as-is into PowerShell CLI window.  Be sure you have a folder c:\test.  Watche the output to see what it traces.

Free Windows Admin Tool Kit Click here and download it now
February 15th, 2015 7:55am

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics