Public/Invoke-Shell.ps1

function Invoke-Shell {
    param(
        [Parameter(Position = 0, Mandatory)][string]$Command,
        [Parameter(Position = 1)][string]$Name = '',
        [string]$WorkingDirectory,
        [int[]]$ValidCodes = @(0),
        [string]$Shell = $null,
        [switch]$Result,
        [switch]$NoEcho,
        [switch]$SkipAssert
    )

    Write-Log "$Command" -Level Debug
    $IsWin = [System.Environment]::OSVersion.Platform -eq 2
    If (-Not $Shell) {
        $Shell = If ($IsWin) { 'cmd.exe' } Else { 'sh' }
    }
    $ShArg = If ($IsWin) { "/C $Command" } Else {
        #escape the double quotes with 2x double quotes
        $Command = $Command -replace "`"", "`""""
        "-c ""$($Command)"""
    }
    $Res = Start-ProcessWithOutput -File $Shell -Arguments $ShArg -NoEcho:$NoEcho -WorkingDirectory $WorkingDirectory
    If (-Not $ValidCodes.Contains($Res.ExitCode)) {
        Write-Log "$Name exit code $($Res.ExitCode)" -Level Error
        If ($SkipAssert.IsPresent) {
            Write-Log "Skipping the assertion"
        }
        Else {
            throw [InvalidShellCodeException]::new($Res.ExitCode)
        }
    }

    If ($Result.IsPresent) {
        RETURN $Res.Output
    }
}


class InvalidShellCodeException : System.Exception {
    [int]$ExitCode

    InvalidShellCodeException([int]$exitCode) : base("Bad exit code $exitCode") {
        $this.ExitCode = $exitCode
    }
}