private/Split-ExecutableAndArguments.ps1

function Split-ExecutableAndArguments {
    <#
        .SYNOPSIS
        This function seperates the exeutable path from its command line arguments
        and returns the absolute path to the executable (resolves relative) as well
        as the arguments separately.
 
        Returns NULL if unsuccessful
    #>


    Param (
        [ValidateNotNullOrEmpty()]
        [string]$Command,
        [Parameter( Mandatory = $true )]
        [string]$WorkingDirectory
    )

    # Only search the Machine-Scope PATH
    # Package commands would not rely on a user-specific PATH setup so skip it to avoid false matches
    [string[]]$MachinePathDirectories = [System.Environment]::GetEnvironmentVariable("Path", "Machine").Split(';') | Where-Object { $_ }
    [string[]]$MachinePathExtensions  = [System.Environment]::GetEnvironmentVariable("PATHEXT", "Machine").Split(';') | Where-Object { $_ }

    # Workaround for #57
    if ($Command.StartsWith('START /WAIT')) {
        $Command = $Command.Substring(11).TrimStart()
    }
    $pathParts = $Command -split ' '

    # Repeatedly remove parts of the string from the end and test
    for ($end = $pathParts.Count - 1; $end -ge 0; $end--) {
        $testPath = [String]::Join(' ', $pathParts[0..$end])

        # We have to trim quotes because they mess up GetFullPath() and Join-Path
        $testPath = $testPath.Trim('"')

        if ( [System.IO.File]::Exists($testPath) ) {
            return @(
                [System.IO.Path]::GetFullPath($testPath),
                "$($pathParts | Select-Object -Skip ($end + 1))"
            )
        }

        $testPathRelative = Join-Path -Path $WorkingDirectory -ChildPath $testPath

        if ( [System.IO.File]::Exists($testPathRelative) ) {
            return @(
                [System.IO.Path]::GetFullPath($testPathRelative),
                "$($pathParts | Select-Object -Skip ($end + 1))"
            )
        }
    }

    # Some commands call/rely on executables in PATH and even call
    # them without their file extension (see issue #57). To support this
    # we also have to search PATH with PATHEXT for potential file matches
    $testPath = $pathParts[0].Trim('"')

    foreach ($MachinePathDir in $MachinePathDirectories) {
        $testPathInPath = Join-Path -Path $MachinePathDir -ChildPath $testPath
        if ([System.IO.File]::Exists($testPathInPath)) {
            return @(
                [System.IO.Path]::GetFullPath($testPathInPath),
                "$($pathParts | Select-Object -Skip 1)"
            )
        }
        foreach ($FileExtension in $MachinePathExtensions) {
            $testPathInPathWithExt = $testPathInPath + $FileExtension
            if ([System.IO.File]::Exists($testPathInPathWithExt)) {
                return @(
                    [System.IO.Path]::GetFullPath($testPathInPathWithExt),
                    "$($pathParts | Select-Object -Skip 1)"
                )
            }
        }
    }
}