Categories
command-line path-variables windows

Is there an equivalent of ‘which’ on the Windows command line?

2681

As I sometimes have path problems, where one of my own cmd scripts is hidden (shadowed) by another program (earlier on the path), I would like to be able to find the full path to a program on the Windows command line, given just its name.

Is there an equivalent to the UNIX command ‘which’?

On UNIX, which command prints the full path of the given command to easily find and repair these shadowing problems.

10

  • 3

    Foredecker: “which” searches the PATH for the executable that will be run if you type a command at the shell prompt.

    Nov 20, 2008 at 4:28

  • 3

    for example, if you have 5 versions of Java installed and you don’t know which one is being used you can type “which java” and it gives you the PATH to the binary

    – ninesided

    Nov 20, 2008 at 4:41

  • 11

    @Foredecker, MR says it’s “where” in Win2k3 but Win2k3 wasn’t part of the question. If “where” isn’t in the other Windows versions, other answers are also valid. IMNSHO, the answer that works on all Windows versions is the best. Also, the other answers aren’t wrong, just different ways of doing it.

    – paxdiablo

    Nov 22, 2008 at 12:55

  • 42

    I know this question arose before SuperUser, but it probably belongs there.

    – palswim

    Oct 12, 2010 at 17:04

  • 25

    There is no which command in standard Unix. The POSIX utility is type. The C Shell has a which command, and some systems have it as an external executable. For instance, on Debian Linux, which comes from a package called debutils. This external which does not “see” shell built-ins, aliases or functions. type does; Bash’s type has an option to suppress that and just do a path lookup.

    – Kaz

    Apr 17, 2015 at 16:09


2866

Windows Server 2003 and later (i.e. anything after Windows XP 32 bit) provide the where.exe program which does some of what which does, though it matches all types of files, not just executable commands. (It does not match built-in shell commands like cd.) It will even accept wildcards, so where nt* finds all files in your %PATH% and current directory whose names start with nt.

Try where /? for help.

Note that Windows PowerShell defines where as an alias for the Where-Object cmdlet, so if you want where.exe, you need to type the full name instead of omitting the .exe extension. Alternatively, you can set an alias for it:

Set-Alias which where.exe

Update: Using Get-Command (alias: gcm) is recommended since it’s native to PS and will get all command types: aliases, cmdlets, executables, and functions. Example:

gcm notepad*

14

  • 31

    No, because grep examines the contents of its input, which you have to give explicitly. which and where.exe only look at the names of the files in a set of directories set in the PATH environment variables.

    Dec 10, 2011 at 23:46

  • 12

    @Ajedi32 – Correct, which is not in XP. As I said, “Windows Server 2003 and later”.

    Sep 25, 2012 at 5:40

  • 74

    watch out that this wont work in powershell unless you type where.exe

    – JonnyRaa

    Jan 28, 2014 at 14:46


  • 19

    Remember that where.exe is not a shell builtin, you need to have %windir%\system32 on your %PATH% – which may not be the case, as using where suggests that you may be working on problems with your path!

    Jul 8, 2015 at 9:00

  • 16

    powershell Get-Command or gcm as mentioned in another answer is equivalent to where

    – tkokasih

    Sep 6, 2017 at 5:51

313

While later versions of Windows have a where command, you can also do this with Windows XP by using the environment variable modifiers, as follows:

c:\> for %i in (cmd.exe) do @echo.   %~$PATH:i
   C:\WINDOWS\system32\cmd.exe

c:\> for %i in (python.exe) do @echo.   %~$PATH:i
   C:\Python25\python.exe

You don’t need any extra tools and it’s not limited to PATH since you can substitute any environment variable (in the path format, of course) that you wish to use.


And, if you want one that can handle all the extensions in PATHEXT (as Windows itself does), this one does the trick:

@echo off
setlocal enableextensions enabledelayedexpansion

:: Needs an argument.

if "x%1"=="x" (
    echo Usage: which ^<progName^>
    goto :end
)

:: First try the unadorned filenmame.

set fullspec=
call :find_it %1

:: Then try all adorned filenames in order.

set mypathext=!pathext!
:loop1
    :: Stop if found or out of extensions.

    if "x!mypathext!"=="x" goto :loop1end

    :: Get the next extension and try it.

    for /f "delims=;" %%j in ("!mypathext!") do set myext=%%j
    call :find_it %1!myext!

:: Remove the extension (not overly efficient but it works).

:loop2
    if not "x!myext!"=="x" (
        set myext=!myext:~1!
        set mypathext=!mypathext:~1!
        goto :loop2
    )
    if not "x!mypathext!"=="x" set mypathext=!mypathext:~1!

    goto :loop1
:loop1end

:end
endlocal
goto :eof

:: Function to find and print a file in the path.

:find_it
    for %%i in (%1) do set fullspec=%%~$PATH:i
    if not "x!fullspec!"=="x" @echo.   !fullspec!
    goto :eof

It actually returns all possibilities but you can tweak it quite easily for specific search rules.

7

  • 8

    Hey, I wish I had learned that! Too bad it doesn’t work with MS-DOS or Win9x (that is, with command.com). (Raymond Chen has a more “elaborate” version you can turn into a batch file: blogs.msdn.com/oldnewthing/archive/2005/01/20/357225.aspx )

    Jan 1, 2009 at 3:27

  • 126

    @Michael, if you’re still using DOS or Win95, finding executables on the path are the least of your problems 🙂

    – paxdiablo

    Apr 9, 2009 at 5:41

  • windows recognizes more than .exe as executable. Last time I coded a which back in W95/DOS days amdittedly, the search order was – current dir, then each path dir, for cmd.com, then cmd.exe, then cmd.bat So, even cmd.bat in current dir is executed befroe cmd.exe soemwhere in path

    Mar 26, 2010 at 0:46

  • 3

    @mawg, the original was for where you know the extension since it mirrors which under UNIX (where that extension-adding trickery doesn’t occur). I’ve now added one which can do what you wish but it’s no longer a simple command so much as a script. It first tries the unadorned command then each of the extension ones. Hope that helps. You can tweak it to your needs as you see fit (if you want the same search order as with Windows for example – this one shows all possibilities).

    – paxdiablo

    Mar 26, 2010 at 1:34

  • 2

    To turn this into a batch script, create a file called “which.bat”: @echo off for %%i in (%1) do @echo. %%~$PATH:%i To add it to an alias.bat script that you load everytime you run cmd.exe (put the above script in a new directory called C:\usr\aliases): DOSKEY which=C:\usr\aliases\which.bat $* Then you can make a script to launch cmd.exe with the alias.bat file: cmd.exe /K E:\usr\aliases\alias.bat

    – Brad T.

    Apr 25, 2014 at 20:42


215

Under PowerShell, Get-Command will find executables anywhere in $Env:PATH.

$ Get-Command eventvwr

CommandType   Name          Definition
-----------   ----          ----------
Application   eventvwr.exe  c:\windows\system32\eventvwr.exe
Application   eventvwr.msc  c:\windows\system32\eventvwr.msc

And since powershell let’s you define aliases, which can be defined like so.

$ sal which gcm   # short form of `Set-Alias which Get-Command`
$ which foo
...

PowerShell commands are not just executable files (.exe, .ps1, etc). They can also be cmdlets, functions, aliases, custom executable suffixes set in $Env:PATHEXT, etc. Get-Command is able to find and list all of these commands (quite akin to Bash’s type -a foo). This alone makes it better than where.exe, which.exe, etc which are typically limited to finding just executables.

Finding executables using only part of the name

$ gcm *disk*

CommandType     Name                             Version    Source
-----------     ----                             -------    ------
Alias           Disable-PhysicalDiskIndication   2.0.0.0    Storage
Alias           Enable-PhysicalDiskIndication    2.0.0.0    Storage
Function        Add-PhysicalDisk                 2.0.0.0    Storage
Function        Add-VirtualDiskToMaskingSet      2.0.0.0    Storage
Function        Clear-Disk                       2.0.0.0    Storage
Cmdlet          Get-PmemDisk                     1.0.0.0    PersistentMemory
Cmdlet          New-PmemDisk                     1.0.0.0    PersistentMemory
Cmdlet          Remove-PmemDisk                  1.0.0.0    PersistentMemory
Application     diskmgmt.msc                     0.0.0.0    C:\WINDOWS\system32\diskmgmt.msc
Application     diskpart.exe                     10.0.17... C:\WINDOWS\system32\diskpart.exe
Application     diskperf.exe                     10.0.17... C:\WINDOWS\system32\diskperf.exe
Application     diskraid.exe                     10.0.17... C:\WINDOWS\system32\diskraid.exe
...

Finding custom executables

Unlike UNIX, where executables are files with the executable (+x) bit set, executables on windows are files present in one of the directories specified in the $PATH env. variable whose filename suffixes are named in the $PATHEXT env. variable (defaults to .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL).

As Get-Command also honours this env. variable, it can be extended to list custom executables. e.g.

$ $Env:PATHEXT="$Env:PATHEXT;.dll;.ps1;.psm1;.py"     # temporary assignment, only for this shell's process

$ gcm user32,kernel32,*WASM*,*http*py

CommandType     Name                        Version    Source
-----------     ----                        -------    ------
ExternalScript  Invoke-WASMProfiler.ps1                C:\WINDOWS\System32\WindowsPowerShell\v1.0\Invoke-WASMProfiler.ps1
Application     http-server.py              0.0.0.0    C:\Users\ME\AppData\Local\Microsoft\WindowsApps\http-server.py
Application     kernel32.dll                10.0.17... C:\WINDOWS\system32\kernel32.dll
Application     user32.dll                  10.0.17... C:\WINDOWS\system32\user32.dll

See Get-Command for more options and examples.

3

  • 2

    It finds much more than just executables. It also catches command files

    Nov 30, 2018 at 21:43


  • 2

    @TheIncorrigible1 – if you mean command files such as batch files (.BAT, .CMD, etc), they are considered executable because their extensions are named in the PATHEXT variable (which by default is PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL). Other executable types (e.g. .py, .rb, etc) can be added by adding the file extension in and creating an executable association with assoc/ftype – e.g. docs.python.org/3.3/using/…

    – shalomb

    Jan 6, 2019 at 21:19


  • 1

    This should honestly be selected as the best answer now that it is 2020, since the original answer was posted back in 2008. Times have changed. PowerShell is the way, especially being that this answer is now cross-platform for wherever PowerShell exists.

    Jun 16, 2020 at 19:29