pf-args.ps1

function Get-Argument ($name, [switch]$switch, [switch]$remove, $default = $null) {
    $stack = Get-PSCallStack
    $methodArgs = $stack[1].InvocationInfo.UnboundArguments
    $pos  = $methodArgs.FindIndex( [Predicate[object]] { $args[0] -eq ( '-' + $name ) } )
    if ($pos -lt 0) {
        if ($switch) {
            return [switch]$false
        }
        return $default
    }
    if ($remove) {
        $methodArgs.RemoveAt($pos)
    }
    else {
        $pos++
    }

    if ($switch) {
        return [switch]$true
    }

    $hasResults = $false
    while ($methodArgs.Count -gt $pos ) {
        $value = $methodArgs[$pos];
        if ( $value -is [string] -and $value.StartsWith('-') ) {
            break    
        } 
        if ($remove) {
            $methodArgs.RemoveAt($pos)
        }
        return $value
    }
    if (-not $hasResults) {
        return $default
    }
} 

function Get-Argument:::Test {
        function Dummy {
            $UnboundArgs = $MyInvocation.UnboundArguments;
            $UnboundArgs.Count | Should -Be 7
            Get-Argument 'nopresent' -remove | Should -Be $null
            Get-Argument 'nopresent' -remove -default 1 | Should -Be 1
            Get-Argument 'ok' -remove | Should -Be 1
            $UnboundArgs.Count  | Should -Be 5
            Get-Argument 'NoOutput' -switch -remove | Should -BeTrue
            $UnboundArgs.Count | Should -Be 4 
            ( Get-Argument 'Array' -remove ) -is [Array] | Should -BeTrue
        }
        Dummy -ok 1 -NoOutput -Array 1, 2, 3 ping -a
}

function Get-CmdUnboundArgs([object[]]$argList) {
    $pairedArgs = [Ordered]@{}
    if ( -not $argList ) {
        return $pairedArgs;
    }

    $paramValueList = @()
    for($i = 0; $i -lt $argList.Count; $i++) {
        $param = $argList[$i]
        if ($param -like '-*' ) {
            $paramName = $param.Substring(1);
            if ($paramName.EndsWith(':') ) {
                $paramName = $paramName.Substring(0, $paramName.Length - 1)
            }

            $paramValueList = @()
            
            for($j = $i+1; $j -lt $argList.Count; $j++) {
                $paramValue = $argList[$j]
                if ($paramValue -like '-*') {
                    break;
                }
                $paramValueList += $paramValue
                $i = $j
            }
            $pairedArgs += @{ $paramName = $paramValueList }
        }
        else {
            $paramValueList += $param
        }
    }
    $pairedArgs
}

function Get-CmdUnboundArgs:::Test {
    function AnyCmd($pa,$pz) {
        $myInv = $MyInvocation
        Get-CmdUnboundArgs $myInv.UnboundArguments
    }

    $res = AnyCmd -pa 1 -pc 2, 3 -pd -pz 100 -pe:@(1,2,3) -pf:$false -pg 'val1' -ph 4 5
    $res.pc | Should -Be @(2,3)
    $res.pd | Should -Be @()
    $res.pe | Should -Be @(1,2,3)
    $res.pf | Should -Be $false
    $res.pg | Should -Be 'val1'
    $res.ph | Should -Be @(4, 5)
}

function Get-CmdAllArgs($invInfo) {
    $UnboundArguments = Get-CmdUnboundArgs $invInfo.UnboundArguments
    $result = [Ordered]@{}
    $result += $invInfo.BoundParameters
    $result += $UnboundArguments
    return $result
}