Private/Invoke-ExternalCommand.ps1
|
function Invoke-ExternalCommand( [Parameter(Mandatory)] [scriptblock]$Command, [int[]]$SuccessExitCodes = @(0), [string]$ErrorMessage, [switch]$Passthru ) { $stdoutAndErr = & $Command 2>&1 # Split stdout and stderr -- https://stackoverflow.com/a/68106198/33244 # The [string[]] cast converts the [ErrorRecord] instances to strings too. $stdout, [string[]]$stderr = $stdoutAndErr.Where({ $_ -is [string] }, 'Split') if ($SuccessExitCodes -notcontains $LASTEXITCODE) { # If the command failed, we throw an exception with the stderr output. if (-not $ErrorMessage) { $ErrorMessage = "Command exited with code $LASTEXITCODE." } $exceptionMessages = @() if ($stderr) { $exceptionMessages = @("$ErrorMessage. Output is:") + $stderr } else { $exceptionMessages = @($ErrorMessage) } throw $($exceptionMessages -join [Environment]::NewLine) } if ($Passthru) { # If the Passthru switch is specified, we return both stdout and stderr. $result = [PSCustomObject]@{ StdOut = $stdout StdErr = $stderr ExitCode = $LASTEXITCODE } # Reset $LASTEXITCODE so callers (e.g. GitHub Actions run: steps) are not # affected by non-zero exit codes from tools that exit non-zero on success # (e.g. gstat -z exits 1 on Windows even when it succeeds). $global:LASTEXITCODE = 0 return $result } # Reset $LASTEXITCODE for the same reason. $global:LASTEXITCODE = 0 } |