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
        $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.RedirectStandardInput = $true;
        $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden;
        $psi.UseShellExecute = $false;
        $psi.WorkingDirectory = $WorkingDirectory;

        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $psi
        $p.EnableRaisingEvents = $true;

        $errEvent = Register-ObjectEvent -InputObject $p -EventName ErrorDataReceived -Action {
            If (-Not $NoEcho.IsPresent) { Write-Log ($EventArgs.Data) -Level Error }
            $Output.AppendLine($EventArgs.Data) | Out-Null
        }
        $outEvent = Register-ObjectEvent -InputObject $p -EventName OutputDataReceived -Action {
            If (-Not $NoEcho.IsPresent) { Write-Log ($EventArgs.Data) }
            $Output.AppendLine($EventArgs.Data) | Out-Null
        }
    }

    process {
        Try {
            $p.Start() | Out-Null
            $p.BeginErrorReadLine()
            $p.BeginOutputReadLine()
            $p.WaitForExit()
            $exitCode = $p.ExitCode
        } Finally {
            Unregister-Event -SubscriptionId $errEvent.Id
            Unregister-Event -SubscriptionId $outEvent.Id
            $p.Dispose()
        }
    }
    end {
        RETURN @{
            ExitCode = $exitCode;
            Output = $builder.ToString().Trim();
        }
    }
}