Private/Invoke-Process.ps1
# The Invoke-Process function is loosely based on code from https://github.com/guitarrapc/PowerShellUtil/blob/master/Invoke-Process/Invoke-Process.ps1 function Invoke-Process { [OutputType([PSCustomObject])] [CmdletBinding()] param ( [Parameter(Mandatory = $false, Position = 0)] [string]$FileName = "PowerShell.exe", [Parameter(Mandatory = $false, Position = 1)] [string]$Arguments = "", [Parameter(Mandatory = $false, Position = 3)] [Int]$TimeoutSeconds = 120, [Parameter(Mandatory = $false, Position =4)] [String]$stdoutFile = $null, [Parameter(Mandatory = $false, Position =5)] [String]$stderrFile = $null ) end { $WorkingDirectory = if ($IsLinux -or $IsMacOS) { "/tmp" } else { $env:TEMP } try { # new Process if ($stdoutFile) { $process = Start-Process -FilePath $FileName -ArgumentList $Arguments -WorkingDirectory $WorkingDirectory -NoNewWindow -PassThru -RedirectStandardOutput (Join-Path $WorkingDirectory $stdoutFile) -RedirectStandardError (Join-Path $WorkingDirectory $stderrFile) } else { $process = Start-Process -FilePath $FileName -ArgumentList $Arguments -WorkingDirectory $WorkingDirectory -NoNewWindow -PassThru } $handle = $process.Handle # cache process.Handle, otherwise ExitCode is null from powershell processes # wait for complete $Timeout = [System.TimeSpan]::FromSeconds(($TimeoutSeconds)) if (-not $process.WaitForExit($Timeout.TotalMilliseconds)) { Invoke-KillProcessTree $process.id Write-Host -ForegroundColor Red "Process Timed out after $TimeoutSeconds seconds, use '-TimeoutSeconds' to specify a different timeout" if ($stdoutFile) { # Add a warning in stdoutFile in case of timeout # problem: $stdoutFile was locked in writing by the process we just killed, sometimes it's too fast and the lock isn't released immediately # solution: retry at most 10 times with 100ms between each attempt For($i=0;$i -lt 10;$i++) { try { "<timeout>" | Out-File (Join-Path $WorkingDirectory $stdoutFile) -Append -Encoding ASCII break # if we're here it means the file wasn't locked and Out-File worked, so we can leave the retry loop } catch {} # file is locked Start-Sleep -m 100 } } } if ($IsLinux -or $IsMacOS) { Start-Sleep -Seconds 5 # On nix, the last 4 lines of stdout get overwritten upon return so pause for a bit to ensure user can view results } # Get Process result return $process.ExitCode } finally { if ($null -ne $process) { $process.Dispose() } } } } |