PowerShell's process invocation is shaky and bug riddled at best, so when you need something that doesn't sporadically hang like Start-Process, or captures output to the pipeline, while still preserving $lastexitcode, most people seem to use Process/ProcessStartInfo. Some processes write a lot to the output or may be long running, so we don't want to wait until they finish to see the output stream (not necessarily the host...might be a log file). So I made this function
function Invoke-Cmd {
<#
.SYNOPSIS
Executes a command using cmd /c, throws on errors and captures all output. Writes error and info output to pipeline (so uses .NET process API).
#>
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][string]$Cmd,
[Parameter(Position=1,Mandatory=0)][ScriptBlock]$ErrorMessage = ({"Error executing command: $Cmd - Exit Code $($p.ExitCode)"}),
[Parameter()][int[]]$ValidExitCodes = @(0)
)
begin {
$p = New-Object System.Diagnostics.Process
$pi = New-Object System.Diagnostics.ProcessStartInfo
$pi.FileName = "cmd.exe"
$pi.Arguments = "/c $Cmd 2>&1"
$pi.RedirectStandardError = $true
$pi.RedirectStandardOutput = $true
$pi.UseShellExecute = $false
$pi.CreateNoWindow = $true
$p.StartInfo = $pi
$outputHandler = {
if ($EventArgs.Data -ne $null) { Write-Output $EventArgs.Data }
}
Write-Output "Executing..."
$stdOutEvent = Register-ObjectEvent -InputObject $p `
-Action $outputHandler -EventName 'OutputDataReceived'
$stdErrEvent = Register-ObjectEvent -InputObject $p `
-Action $outputHandler -EventName 'ErrorDataReceived'
}
process {
$p.Start() | Out-Null
$p.BeginOutputReadLine()
$p.BeginErrorReadLine()
$p.WaitForExit() | Out-Null
}
end {
Unregister-Event -SourceIdentifier $stdOutEvent.Name
Unregister-Event -SourceIdentifier $stdErrEvent.Name
if (!($ValidExitCodes -contains $p.ExitCode)) {
throw (& $ErrorMessage)
}
}
}
The problem is that Write-Output in my event handler doesn't work in the same execution context as Invoke-Cmd itself... How can I get my event handler to Write-Output to the parent functions output stream?
Thank you