Equivalent of *Nix 'which' command in PowerShell?
Asked Answered
B

18

514

How do I ask PowerShell where something is?

For instance, "which notepad" and it returns the directory where the notepad.exe is run from according to the current paths.

Barnes answered 15/9, 2008 at 15:13 Comment(1)
PowerShell equivalent to the Unix which command?Bootblack
E
505

The very first alias I made once I started customizing my profile in PowerShell was 'which'.

New-Alias which get-command

To add this to your profile, type this:

"`nNew-Alias which get-command" | add-content $profile

The `n at the start of the last line is to ensure it will start as a new line.

Envision answered 15/9, 2008 at 17:56 Comment(12)
You can put it in your profile script. More on profiles - msdn.microsoft.com/en-us/library/bb613488(VS.85).aspxSubnormal
i like running: Get-Command <command> | Format-Table Path, Name so i can get the path where the command sits too.Distressed
Is there any way to have the path all the time without to type '| Format-Table Path, Name' ?Resolution
In previous versions, Get-Command didn't provide sorted output. It does now. This is clearly the right answer today ;-)Scarab
If you are planning to use this in a script then there are some additional parameters that you should pass to get the same behavior as direct invcation in prompt. Here is an example if(!(get-command node -ErrorAction SilentlyContinue)){'node not found' | Write-Error }Deciliter
If you want the Unix-style behavior of giving you the path you'll need to pipe the output of get-command to select -expandproperty Path.Chaliapin
@Eld's solution is more true in spiritImportation
As Jason suggests, the which() function defined by Eld's solution is substantially superior to anything on offer here. If it's not the equivalent of Unix which, it's not the right answer.Flemish
Use (gcm <command>).definition to get the path(s) only. gcm is the default alias for Get-Command. You can also use wildcards, eg: (gcm win*.exe).definition.Tigerish
I'm learning ps at the moment and it seems to me that apart from maybe being a decent scripting language, it's pretty stupid for use on the command-line.Actinometer
Just in case anyone else is wondering, if you peek in the Automation DLL, Source returns Definition and Definition returns Path, so these three properties will always be equivalent (barring some future change on MS's part of course);Alcina
for absolute beginners: in order for this to work copy-paste the second command in the answer in your PowerShell terminal and run it and then copy-paste & run the first oneExtortion
D
203

Here is an actual *nix equivalent, i.e. it gives *nix-style output.

Get-Command <your command> | Select-Object -ExpandProperty Definition

Just replace with whatever you're looking for.

PS C:\> Get-Command notepad.exe | Select-Object -ExpandProperty Definition
C:\Windows\system32\notepad.exe

When you add it to your profile, you will want to use a function rather than an alias because you can't use aliases with pipes:

function which($name)
{
    Get-Command $name | Select-Object -ExpandProperty Definition
}

Now, when you reload your profile you can do this:

PS C:\> which notepad
C:\Windows\system32\notepad.exe
Diagonal answered 5/6, 2013 at 20:22 Comment(3)
I use this alternate syntax: "(Get-Command notepad).definition"Elect
@B00merang Your syntax is great--definitely more concise--but unfortunately, even with the pipe removed, it can't be added as an alias unless you include the name of the program you are looking for.Diagonal
This is an old post, but in case anyone is sent here by Google (like I was), this answer works with more types of Powershell commands than the accepted answer. For example, I have an alias named okta that points to a Powershell script named okta.ps1 that is not on my $PATH. Using the accepted answer returns the script name (okta -> okta.ps1). This is OK but it doesn't tell me the location of okta.ps1. Using this answer, however, gives me the whole path (C:\Users\blah\etc\scripts\okta.ps1). So +1 from me.Abrahamabrahams
P
117

I usually just type:

gcm notepad

or

gcm note*

gcm is the default alias for Get-Command.

On my system, gcm note* outputs:

[27] » gcm note*

CommandType     Name                                                     Definition
-----------     ----                                                     ----------
Application     notepad.exe                                              C:\WINDOWS\notepad.exe
Application     notepad.exe                                              C:\WINDOWS\system32\notepad.exe
Application     Notepad2.exe                                             C:\Utils\Notepad2.exe
Application     Notepad2.ini                                             C:\Utils\Notepad2.ini

You get the directory and the command that matches what you're looking for.

Precious answered 15/9, 2008 at 15:22 Comment(3)
its a bit messy, but way cleaner than custom functions and arbitrary splitsBarnes
When I type "gcm notepad" in my powershell command prompt, I just get the first two columns, and a third column called 'ModuleName' which is empty. Do you know how to force it to list the 'Definition' column by default?Closehauled
@PiyushSoni that's probably because of an updated version of PowerShell. You can always display the other columns by doing something like gcm note* | select CommandType, Name, Definition. If you run it often, you should probably wrap it in a function, though.Precious
C
45

Try this example:

(Get-Command notepad.exe).Path
Cussed answered 1/4, 2014 at 4:17 Comment(3)
Please add more code or explanation so that the OP can understand you better. Thank you.Subjoinder
Thank you for adding less code so I can actually remember this for once :PPathological
This is what I wanted! It works with gcm as well: (gcm py.exe).pathClymer
B
12

My proposition for the Which function:

function which($cmd) { get-command $cmd | % { $_.Path } }

PS C:\> which devcon

C:\local\code\bin\devcon.exe
Barmy answered 17/11, 2015 at 10:14 Comment(1)
This is a better answer than the accepted one. It allows you to add the postprocessing suffixes suggested above to provide better output; an alias doesn't.Talon
J
10

A quick-and-dirty match to Unix which is

New-Alias which where.exe

But it returns multiple lines if they exist so then it becomes

function which {where.exe command | select -first 1}
Jesuitism answered 8/4, 2017 at 19:6 Comment(6)
where.exe where should tell you C:\Windows\System32\where.exeJesuitism
where.exe is equivalent to which -a, as it will give back all matching executables, not just the first one to be executed. That is, where.exe notepad gives c:\windows\notepad.exe and c:\windows\system32\notepad.exe. So this is particularly not suitable for the form $(which command). (Another problem is that it will print a nice, helpful error message if the command is not found, which will also not expand nicely in $() -- that can be remedied with /Q, but not as an alias.)Wishywashy
point taken. I edited answer but yes it's no longer so neat a solutionJesuitism
Please note that where seems to search the system PATH variable and not the current shell PATH variable. See this questionRoughspoken
function which {where.exe $args[0] | select -first 1} would make it reusable. Also, posh seems way more reliable in dealing with paths, quotes, and whitespaces, so function which {$(gcm $args[0]).source | select -first 1} might be a better choice.Charlatanism
also note where is an alias of Where-Object as gcm where* will tell you. You have to include the .exe to restricted it to where.exe. (FYI sc.exe is another one.) A frequent suggestion is always use the .exe as habit to avoid this problem.Oriel
S
7

I like Get-Command | Format-List, or shorter, using aliases for the two and only for powershell.exe:

gcm powershell | fl

You can find aliases like this:

alias -definition Format-List

Tab completion works with gcm.

To have tab list all options at once:

set-psreadlineoption -editmode emacs
Selfcentered answered 11/4, 2017 at 19:29 Comment(0)
L
3

This seems to do what you want (I found it on http://huddledmasses.org/powershell-find-path/):

Function Find-Path($Path, [switch]$All = $false, [Microsoft.PowerShell.Commands.TestPathType]$type = "Any")
## You could comment out the function stuff and use it as a script instead, with this line:
#param($Path, [switch]$All = $false, [Microsoft.PowerShell.Commands.TestPathType]$type = "Any")
   if($(Test-Path $Path -Type $type)) {
      return $path
   } else {
      [string[]]$paths = @($pwd);
      $paths += "$pwd;$env:path".split(";")

      $paths = Join-Path $paths $(Split-Path $Path -leaf) | ? { Test-Path $_ -Type $type }
      if($paths.Length -gt 0) {
         if($All) {
            return $paths;
         } else {
            return $paths[0]
         }
      }
   }
   throw "Couldn't find a matching path of type $type"
}
Set-Alias find Find-Path
Lachlan answered 15/9, 2008 at 15:16 Comment(1)
But it's not really "which" since it works with any file(type) and doesn't find cmdlets, functions or aliasesScarab
C
3

Check this PowerShell Which.

The code provided there suggests this:

($Env:Path).Split(";") | Get-ChildItem -filter notepad.exe
Cranwell answered 15/9, 2008 at 15:16 Comment(1)
I know it's years on, but my path had "%systemroot%\system32\..." and PowerShell doesn't expand that environment variable and throws errors doing this.Aurie
W
2

Try the where command on Windows 2003 or later (or Windows 2000/XP if you've installed a Resource Kit).

BTW, this received more answers in other questions:

Is there an equivalent of 'which' on Windows?

PowerShell equivalent to Unix which command?

Wasteful answered 13/12, 2011 at 5:14 Comment(1)
where aliases to the Where-Object commandlet in Powershell, so typing where <item> in a Powershell prompt yields nothing. This answer is thus completely incorrect - as noted in the accepted answer in the first linked question, to get the DOS where, you need to type where.exe <item>.Amphigory
H
2

If you want a comamnd that both accepts input from pipeline or as paramater, you should try this:

function which($name) {
    if ($name) { $input = $name }
    Get-Command $input | Select-Object -ExpandProperty Path
}

copy-paste the command to your profile (notepad $profile).

Examples:

❯ echo clang.exe | which
C:\Program Files\LLVM\bin\clang.exe

❯ which clang.exe
C:\Program Files\LLVM\bin\clang.exe
Hellenize answered 1/6, 2020 at 7:8 Comment(0)
T
1

I have this which advanced function in my PowerShell profile:

    function which {
    <#
    .SYNOPSIS
    Identifies the source of a PowerShell command.
    .DESCRIPTION
    Identifies the source of a PowerShell command. External commands (Applications) are identified by the path to the executable
    (which must be in the system PATH); cmdlets and functions are identified as such and the name of the module they are defined in
    provided; aliases are expanded and the source of the alias definition is returned.
    .INPUTS
    No inputs; you cannot pipe data to this function.
    .OUTPUTS
    .PARAMETER Name
    The name of the command to be identified.
    .EXAMPLE
    PS C:\Users\Smith\Documents> which Get-Command
    
    Get-Command: Cmdlet in module Microsoft.PowerShell.Core
    
    (Identifies type and source of command)
    .EXAMPLE
    PS C:\Users\Smith\Documents> which notepad
    
    C:\WINDOWS\SYSTEM32\notepad.exe
    
    (Indicates the full path of the executable)
    #>
        param(
        [String]$name
        )
    
        $cmd = Get-Command $name
        $redirect = $null
        switch ($cmd.CommandType) {
            "Alias"          { "{0}: Alias for ({1})" -f $cmd.Name, (. { which $cmd.Definition } ) }
            "Application"    { $cmd.Source }
            "Cmdlet"         { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
            "Function"       { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
            "Workflow"       { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
            "ExternalScript" { $cmd.Source }
            default          { $cmd }
        }
    }
Thermotherapy answered 5/3, 2018 at 18:3 Comment(0)
R
0

Use:

function Which([string] $cmd) {
  $path = (($Env:Path).Split(";") | Select -uniq | Where { $_.Length } | Where { Test-Path $_ } | Get-ChildItem -filter $cmd).FullName
  if ($path) { $path.ToString() }
}

# Check if Chocolatey is installed
if (Which('cinst.bat')) {
  Write-Host "yes"
} else {
  Write-Host "no"
}

Or this version, calling the original where command.

This version also works better, because it is not limited to bat files:

function which([string] $cmd) {
  $where = iex $(Join-Path $env:SystemRoot "System32\where.exe $cmd 2>&1")
  $first = $($where -split '[\r\n]')
  if ($first.getType().BaseType.Name -eq 'Array') {
    $first = $first[0]
  }
  if (Test-Path $first) {
    $first
  }
}

# Check if Curl is installed
if (which('curl')) {
  echo 'yes'
} else {
  echo 'no'
}
Ritual answered 22/12, 2013 at 11:6 Comment(0)
K
0

You can install the which command from https://goprogram.co.uk/software/commands, along with all of the other UNIX commands.

Kindrakindred answered 20/7, 2020 at 12:50 Comment(0)
P
0

If you have scoop you can install a direct clone of which:

scoop install which
which notepad
Prowess answered 6/11, 2021 at 22:44 Comment(0)
E
0

There also always the option of using which. there are actually three ways to access which from Windows powershell, the first (not necessarily the best) wsl -e which command (this requires installation of windows subsystem for Linux and a running distro). B. gnuwin32 which is a port of several gnu binaries in .exe format as standle alone bundled lanunchers option three, install msys2 (cross compiler platform) if you go where it installed in /usr/bin you'll find many many gnu utils that are more up-to-date. most of them work as stand alone exe and can be copied from the bin folder to your home drive somewhere amd added to your PATH.

Everything answered 26/3, 2022 at 11:29 Comment(0)
M
0

It's better to wrap where.exe into the function so that it takes binary as command line argument and put the function into $PROFILE. Also, to find the directory where the binary is located, it's better to use where.exe over (Get-Command $binary).Source method.

Why? Let's consider (Get-Command $binary).Source where $binary matches an alias already written in $PROFILE like, say, New-Alias curl C:\curl-7.81.0-win64-mingw\bin\curl.exe (because you want to use the curl installed by yourself, not the one in system32). Then the (Get-Command curl).Source will output nothing. Moreover, even (Get-Command curl.exe).Source will only output the path to system32:

C:\Windows\System32\curl.exe

when where.exe curl output looks like this:

C:\Windows\System32\curl.exe
C:\curl-7.81.0-win64-mingw\bin\curl.exe

The same is for default PowerShell aliases, such as where. The expected output of (Get-Command where).Source or (Get-Command where).Definition would be C:\Windows\System32\where.exe but it just returns nothing instead and "Where-Object" respectively.

So, the code to add into the $PROFILE:

function Find-Binary($binary) {
    $location = where.exe $binary 2>$null
    Write-Output $location
}

New-Alias wi Find-Binary

wi is short for whereis

Then use it like this:

wi your_binary

or

Find-Binary your_binary
Mitzi answered 6/2 at 9:53 Comment(0)
E
-1

There also always the option of using which. there are actually three ways to access which from Windows powershell

  • The first, (though not the best) is wsl(windows subsystem for linux)
wsl -e which command 

This requires installation of windows subsystem for Linux and a running distro.

  • Next is gnuwin32 which is a port of several gnu binaries in .exe format as standle alone bundled lanunchers

  • Third, install msys2 (cross compiler platform) if you go where it installed in /usr/bin you'll find many many gnu utils that are more up-to-date. most of them work as stand alone exe and can be copied from the bin folder to your home drive somewhere amd added to your PATH.

Everything answered 26/3, 2022 at 11:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.