whence in PowerShell

[Update: Thanks to Joel Bennett for the comments; my original version didn’t account for external scripts and applications having the same precedence, but this revised version does]

Recently a fellow MVP pointed out that PowerShell doesn’t have a whence command readily available.  whence is a command from the Korn Shell.  When a name is provided to the whence command, it returns the way in which that name will be interpreted by the shell.

While PowerShell doesn’t have that functionality out of the box today, you can easily add it with the addition of a simple function to your PowerShell profiles.  Here’s my interpretation of the whence command in a PowerShell function:

function whence {
    param(
        [
string[]]$command,
        [
Switch]$ReturnAll

    )

    # Put any additional arguments in $command
    if ($args.Count -gt 0) {
        $command += [string[]]$args
   
}

    # Read the current path environment variable
    $path = $env:Path.Trim(;).Split(;)

    # Store an array of all command types that have equal
    # precedence
    $equalPrecedence = ExternalScript,Application


    #
Set the command precedence expression for sorting
    $cmdPrecedence = {
        if ($equalPrecedence -contains $_.CommandType) {
            [
Management.Automation.CommandTypes]`
                $equalPrecedence[0]
        }
else {
            $_.CommandType
        }
    }

    # Set the path precedence expression for sorting
    $pathPrecedence = {
        if ($equalPrecedence -contains $_.CommandType) {
            [
Array]::IndexOf(
                $path,
                [
IO.Path]::GetDirectoryName($_.Definition)
            )
+ 1
        }
else {
            1
        }
    }

    # Filter out all but the first command if appropriate
    foreach ($item in $command) {
        if ($ReturnAll) {
            Get-Command -Name $item `
                |
Sort-Object `
                    -Property $cmdPrecedence,$pathPrecedence `
        }
else {
            Get-Command -Name $item `
                |
Sort-Object `
                    -Property $cmdPrecedence,$pathPrecedence `
                |
Select-Object -First 1
        }
    }
}

This function supports retrieving multiple commands at once, whether they are passed in as an array or not.  For example, you can retrieve the commands for Get-Help and Get-Command by calling either of the following:

  1. whence Get-Help,Get-Command
  2. whence Get-Help Get-Command

It also supports retrieving all results for a specific command so that you can determine why the command you want isn’t executing when you try to call it by name.  Here’s an exaggerated example, to illustrate the value here:

PS C:\> whence Get-Help -ReturnAll

CommandType    Name         Definition
———–    —-         ———-
Alias          get-help     get-help
Function       Get-Help     begin {…
Cmdlet         Get-Help     Get-Help [[-Na…
ExternalScript Get-Help.ps1 C:\Get-Help.ps1
Application    get-help.exe C:\get-help.exe

If I had multiple executable applications, such as get-help.exe and get-help.cmd, this would return them in their precedence order.  If I was trying to execute any command here other than the alias, this would help me figure out why it wasn’t executing when I was simply calling get-help.To use this command in your PowerShell environment, simply copy the function into your PowerShell profile and it will be available the next time your profile is run.

Enjoy!

Kirk out.

Technorati Tags: ,,

Share this post :

2 thoughts on “whence in PowerShell

  1. If only it were that simple…

    Sadly, “ExternalScript” and “Application”s have exactly the same priority to the shell, and which one is executed first depends entirely on which one is found first in your env:\PATH … the only way that sorting the output of get-command works out the same is if you have all your scripts in one folder, and make sure to put that folder FIRST in your path.

    By the way, do you know how to get a “Script” CommandType?

Leave a comment