Patch/Cmdlets/Misc/Start-ProcessWithErrorHandling.ps1

<#
    .SYNOPSIS
        Starts a process to handle commands, standard output, and standard error redirection.
    .DESCRIPTION
        Starts a process to handle commands, standard output, and standard error redirection.
    .PARAMETER FilePath
        Specifies the path to the executable.
    .PARAMETER ArgumentList
        Lists of arguments passed to the executable
    .PARAMETER TimeOut
        Specifies the timeout for the process. If the value is set to 0, the function waits for the process to end.
#>

function Start-ProcessWithErrorHandling
{
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$true)]
        [string]$FilePath,
        [parameter(Mandatory=$true)]
        [string[]]$ArgumentList,
        [parameter(Mandatory=$false)]
        [int]$TimeOut = 0
    )

    Write-Verbose "Running external command: $FilePath $ArgumentList"

    $StdErrFile = [System.IO.Path]::GetTempFileName()
    $StdOutFile = [System.IO.Path]::GetTempFileName()

    $result = Start-Process -FilePath $FilePath -PassThru -NoNewWindow -RedirectStandardError $StdErrFile -RedirectStandardOutput $StdOutFile -ArgumentList $ArgumentList

    # progress indication, assume upper bound 500 sec
    # start the pogress indicator after 5 sec
    [int]$percent = 0;
    $program = Split-Path $FilePath -Leaf
    while ($result.WaitForExit(5000) -eq $false) {
        Write-Progress -Activity "Running $program..." -PercentComplete $percent -CurrentOperation "$percent% complete" -Status "Please wait."

        # naive algoritm stops progress indication at 95%
        if ($percent -lt 95) {
            $percent = $percent + 1;
        }

        if ($TimeOut -ne 0) {
            # Decrease timeout with wait cycles
            $TimeOut -= 5
            if ($TimeOut -le 0) {
                Write-Error "Running $program timed out"
                $result | Stop-Process -ErrorAction SilentlyContinue
                break
            }
        }
    }

    Write-Progress -Activity "Running $program..." -PercentComplete 100 -CurrentOperation "100% complete" -Completed -Status "Done."

    $outputFromProcess = Get-Content $StdOutFile
    $errorOutputFromProcess = Get-Content $StdOutFile

    # Many exe files send the same content to stderr and stdout
    # if we have the same number of lines in the stderr and stdout, we will only write log the stderr
    # if the line numbers are different we will write both logs
    if (@($outputFromProcess).Count -ne @($errorOutputFromProcess).Count) {
        $outputFromProcess | ForEach-Object {Write-Verbose " $_"} # indent
    }

    $errorOutputFromProcess | ForEach-Object {Write-Verbose " $_"} # indent

    [int]$exitCode = $result.ExitCode
    if ($exitCode -ne 0)
    {
        [string] $output = $errorOutputFromProcess
        Write-Error "$FilePath $ArgumentList failed with error $exitCode`n$output"
    }
}
Export-ModuleMember -Function Start-ProcessWithErrorHandling