Public/Start-ProcessWithOutput.ps1

function Start-ProcessWithOutput {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$File,
        [Parameter()][string]$Arguments,
        [string]$WorkingDirectory,
        [switch]$NoEcho
    )
    begin {
        If (-Not $WorkingDirectory) {
            $WorkingDirectory = "$((Get-Location).Path)"
        }

        $exitCode = -1
        $outputLevel = If ($NoEcho.IsPresent) { [LogLevels]::None } Else { [LogLevels]::Info }
        $errorLevel = If ($NoEcho.IsPresent) { [LogLevels]::None } Else { [LogLevels]::Error }
        $builder = New-Object System.Text.StringBuilder
        $psi = New-Object System.Diagnostics.ProcessStartInfo
        $psi.FileName = $File;
        $psi.Arguments = $Arguments;
        $psi.CreateNoWindow = $true;
        $psi.RedirectStandardError = $true;
        $psi.RedirectStandardOutput = $true;
        $psi.UseShellExecute = $false;
        $psi.WorkingDirectory = $WorkingDirectory;

        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $psi
    }

    process {
        Try {
            $p.Start() | Out-Null
            While (!$p.HasExited) {
                Start-Sleep -Milliseconds 10
                Write-ProcessLog -Stream $p.StandardOutput -Output $builder -Level $outputLevel
                Write-ProcessLog -Stream $p.StandardError -Output $builder -Level $errorLevel
            }
            $exitCode = $p.ExitCode
        } Finally {
            $p.Dispose()
        }
    }
    end {
        RETURN @{
            ExitCode = $exitCode;
            Output = $builder.ToString().Trim();
        }
    }
}

function Write-ProcessLog {
    param(
        [System.IO.StreamReader]$Stream,
        [System.Text.StringBuilder]$Output,
        [LogLevels]$Level
    )
    While (!$stream.EndOfStream) {
        $msg =  $Stream.ReadLine()
        Write-Log "$msg" -Level $Level
        $Output.AppendLine($msg) | Out-Null
    }
}