Executing a Command Line Utility from PowerShell, and Waiting for it to Finish

(I am reissuing this article, to incorporate a suggestion from Jeffrey Snover, which makes the scriptlet even neater, and which suggestion is gratefully acknowledged. But more seriously, I also note a strange effect with the 64-bit version of PowerShell.)

I occasionally need to execute a command line utility, which runs out of process, from within a PowerShell script, and to wait on its completion before proceeding to the next task. Ordinarily, PowerShell would kick off the process and then go straight on to its next script line, without waiting for completion. Examples that I have scripted in this way include NTBackup and WinZip. Here’s how I do it, taking NTBackup as the utility:

[System.Diagnostics.Process]::Start(“NTBackup.exe”, $NTBackupParameters)
$NTBackupProcess = (Get-Process | `
                        Where-Object { $_.ProcessName -ieq “ntbackup” })

$NTBackupParameters is a string I built earlier in the script, defining the type of backup, which files to back up, and the file to backup to and so on, see the ntbackup.exe documentation for details. The crux of the method is to identify the process involved, and then suspend execution until that process has exited. The above example does assume that there will only be one process with that name; if this can’t be guaranteed, some further check must be used (start time?) to identify the relevant one.

Note that we directly invoke the static method Start() of the .NET class System.Diagnostics.Process, since there isn’t a PowerShell cmdlet available for this purpose. This simple little scriptlet is thus an illustration of Raw .NET Access. See Jeffrey Snover’s excellent article ‘Exposing the Power of .NET in a Admin-friendly way’ at http://blogs.msdn.com/powershell/archive/2006/04/25/583273.aspx for an explanation of the three levels of .NET access from PowerShell.

Scripts incorporating the above scriptlet work just fine with the 32-bit version of PowerShell. However, if the 64-bit version is being used, the script fails at the [System.Diagnostics.Process]::Start command, with the error: ‘Exception calling “Start” with “2” argument(s): “The system cannot find the file specified” ‘. Since, when the 64-bit version is installed, the 32-bit version is also installed, I can always actually run the script, at 32-bit even on a 64-bit machine, pending resolution of the issue, but it makes sense to publicise it here.