1

I am seeing some odd behavior with a benchmark that has been working for years. The benchmark is for Autodesk Revit, which can use journal files to automate tasks and log times. The benchmark will read an XML file for a series of modular journal files, which can be processed in different sequences depending on what Revit features one wants to benchmark. As a result, Revit is launched with different journals, and closes at completion of each journal, to be relaunched with the next journal. I have been using Start-Process with the -wait option in a loop like this...

$exitCode = (Start-Process -FilePath:$executable -argumentList:"`"$journalFile`"" -wait -errorAction:stop -PassThru).ExitCode

What has been happening of late is VERY long pauses between a journal running to completion & closing Revit and control coming back to PowerShell so the next journal can be launched. Like, sometimes 3-5 minutes, which becomes a problem when there are 10 different journal files to process. This seems to only happen in Windows 10, but I have not yet been able to verify if it's limited to a specific build, or if all Windows 10 is behaving this way.

I have found some references to Start-Process -wait being problematic, so I started looking for alternatives.

First I tried...

$process = Start-Process -FilePath:$executable -argumentList:"`"$journalFile`""
Wait-Process $process

But this doesn't seem to actually wait. Revit is launched multiple times in parallel, and since each journal is sometimes dependent on files created in previous ones, this fails. So then I found a reference to using [System.Diagnostics.ProcessStartInfo] like this...

$processInfo = New-Object System.Diagnostics.ProcessStartInfo
$processInfo.RedirectStandardError = $true
$processInfo.RedirectStandardOutput = $true
$processInfo.UseShellExecute = $false
$process = New-Object System.Diagnostics.Process

with this in the loop...

$processInfo.FileName = $executable
$processInfo.Arguments = "`"$journalFile`""
$process.StartInfo = $processInfo
[Void]$process.Start()
$process.WaitForExit()
exitCode = $process.ExitCode

This seems to solve the wait problem, but results in Revit failing to process one particular journal, always at exactly the same place. But that makes no sense, as I assume Revit can have no awareness of how it was launched.

Does anyone have any suggestions on either what I might be doing wrong with either of these approaches, or a third option that I should try? And, does anyone have some solid information about what is "wrong" with Start-Process -wait?

Gordon
  • 6,257
  • 6
  • 36
  • 89

1 Answers1

2

If Start-Process's -Wait parameter doesn't work for you (I have no information on why long delays might occur), you can indeed work with the System.Diagnostics.Process instance that Start-Process returns that represents the newly created process, assuming you have used the -PassThru switch:

# Simple example (Windows): launch Notepad asynchronously,
# and, thanks to -PassThru, return a System.Diagnostics.Process describing 
# the newly created process.
$ps = Start-Process -PassThru Notepad

If you want to use Wait-Process to wait for the process to exit, you have two syntax options:

$ps | Wait-Process

or

Wait-Process $ps.ID  # parameter -ID implied

Note that Wait-Process $ps does not work, because it tries to bind to the -Name parameter, causing $ps.ToString() to be used as the (useless) value.

However, you can also use the Process type's .WaitForExit() method directly:

$ps.WaitForExit()

Once the process has terminated, you can query its .ExitCode property to obtain its exit code.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • That's the trick I needed. Is there any argument for or against `.WaitForExit()` vs `Wait-Process $ps.ID`? I have tried both and they both seem to work well. Still need to try both in Windows 7/PS2.0 as well, since some Architects are still using it. – Gordon Jul 14 '20 at 20:08
  • @Gordon: The two approaches are interchangeable, though as a general habit to form my recommendation is to stick with PowerShell-native features (unless you're forced to use other approaches for reasons of _performance_). It's not a realistic concern here, but, due to dynamic overload resolution, method calls can inadvertently change their behavior between PowerShell versions, if the underlying .NET types introduce new overloads. As for a direct performance comparison: on the _first_ call, the `Wait-Process` call may be faster, because method calls are JIT-compiled - I doubt that matters here. – mklement0 Jul 14 '20 at 20:29
  • Ugh, that's a bummer that .NET methods can't be trusted version to version. That may inform some decisions I need to make on another project, since I had been gravitating towards .NET by default for performance reasons. I guess if I want to depend on .NET I probably need to move to C# and compile an EXE. – Gordon Jul 14 '20 at 20:36
  • 1
    @Gordon: To be sure: it is _rare_, but it does happen; for a prominent example, see the bottom section of [this answer](https://stackoverflow.com/a/41905031/45375). If you meticulously apply explicit casting of arguments to ensure that the exact type expected is passed, you can guard against such problems. – mklement0 Jul 14 '20 at 20:42