user1670407
user1670407

Reputation:

Powershell pipe into exe and wait

I am piping an array of data into a executable program but I need it to block after every call in the foreach loop. It will leave the loop before it even opens the program from the first call.

 Set-Alias program "whatever.exe"

 foreach ($data in $all_data)
  {
       $data| %{ program /command:update /path:"$_" /closeonend:2 }
  }

Upvotes: 0

Views: 3031

Answers (3)

noam
noam

Reputation: 1983

Depending on your scenario, wait-job might be overkill. If you have a programmatic way to know that whatever.exe has done its thing, you could try something like

do {start-sleep -sec 2} until ($done -eq $true)

Oh and.

Upvotes: 0

Matt
Matt

Reputation: 5172

I can think of two ways to tackle this:

  1. pipe your executable call to Out-Null
  2. shell out the call to cmd.exe /c (as shown in @BobLobLaw's answer)

I made your sample code a little more specific so I could run and test my solutions; hopefully it'll translate. Here's what I started with to be equivalent to your sample code, i.e. the script executes with no waiting on the executable to finish.

# I picked a specific program
Set-Alias program "notepad.exe"

# And put some values in $all_data, specifically the paths to three text files.
$all_data = Get-Item B:\matt\Documents\*.txt

# This opens each file in notepad; three instances of notepad are running 
# when the script finishes executing.
$all_data | %{ program "$_" }

Here's the same code as above, but piping to Out-Null forces the script to wait on each iteration of the loop.

# I picked a specific program
Set-Alias program "notepad.exe"

# And put some values in $all_data, specifically the paths to three text files.
$all_data = Get-Item B:\matt\Documents\*.txt

# Piping the executable call to out-null forces the script execution to wait
# for the program to complete. So in this example, the first document opens
# in notepad, but the second won't open until the first one is closed, and so on.
$all_data | %{ program "$_" | Out-Null}

And, lastly, the same code (more or less) using cmd /c to call the executable and make the script wait.

# Still using notepad, but I couldn't work out the correct call for
# cmd.exe using Set-Alias. We can do something similar by putting
# the program name in a plain old variable, though.
#Set-Alias program "notepad.exe"
$program = "notepad.exe"

# Put some values in $all_data, specifically the paths to three text files.
$all_data = Get-Item B:\matt\Documents\*.txt

# This forces script execution to wait until the call to $program
# completes.  Again, the first document opens in notepad, but the second
# won't open until the first one is closed, and so on.
$all_data | %{ cmd /c $program "$_" }

Upvotes: 2

E.V.I.L.
E.V.I.L.

Reputation: 2166

I like PowerShell but I never really learned Invoke-Command. So whenever I need to run an EXE I always use cmd. If you type cmd /? you get its help, look at the "c" switch. I'd do something like this:

foreach ($data in $all_data){
    $data |
    Foreach-Object{
        cmd /c "whatever.exe" /command:update /path:"$_" /closeonend:2
    }
}

If you don't like the cmd /c thing you could use Jobs.

foreach ($data in $all_data){
    $data |
    Foreach-Object{
        $job = Start-Job -InitializationScript {Set-Alias program "whatever.exe"} -ScriptBlock {program /command:update /path:"$($args[0])" /closeonend:2} -ArgumentList $_
        while($job.Status -eq 'Running'){
            Start-Sleep -Seconds 3
            #Could make it more robust and add some error checking.
        }
    }
}

Upvotes: 2

Related Questions