Invoke-NativeCommand.ps1

function Invoke-NativeCommand {
    [CmdletBinding()]
    [OutputType([hashtable])]
    param (
        [Parameter(Mandatory, Position = 0)]
        [string] $LiteralPath,

        [Parameter(ValueFromRemainingArguments)]
        [string[]] $Arguments
    )

    $result = @{
        CommandLine = "$LiteralPath $([string]::Join(" ", $Arguments))"
        ExitCode = 0
        Stderr = @()
        Stdout = @()
    }

    # Ensure PowerShell does not treat error records in stdout as (non-)terminating errors
    $previousErrorActionPreference = $ErrorActionPreference
    $ErrorActionPreference = "Continue"

    # Let PowerShell redirect stderr to stdout, PowerShell will wrap stderr lines in an error record
    $output = & $LiteralPath @Arguments 2>&1
    $result.ExitCode = $LASTEXITCODE

    $ErrorActionPreference = $previousErrorActionPreference

    foreach ($item in $output) {
        if ($item -is [string]) {
            $result.Stdout += $item
        }

        if ($item -is [System.Management.Automation.ErrorRecord]) {
            if ($null -ne $item.TargetObject) {
                $result.Stderr += $item.TargetObject
            }
            else {
                $result.Stderr += $item.Exception.Message
            }
        }
    }

    return $result
}