Option Explicit Dim arrFound, arrInt, arrPath, arrPathExt, arrTemp Dim blnAll, blnClipboard, blnExtOnly, blnHasExt, blnQuiet, blnShort, blnVer Dim i, intArgs, j Dim objFile, objFSO, objIE, wshShell Dim strComSpec, strExt, strIntAll, strIntCmd, strIntCom, strPath, strPathExt, strResult, strTime, strVer ' Initialize variables intArgs = 0 strResult = "" With WScript.Arguments ' Check the command line for exactly 1 argument (the file ' name), which should NOT contain wildcard characters If .Unnamed.Count <> 1 Then Syntax If InStr( .Unnamed(0), "*" ) Then Syntax If InStr( .Unnamed(0), "?" ) Then Syntax ' Check the command line switches If .Named.Exists( "A" ) Then blnAll = True intArgs = intArgs + 1 Else blnAll = False End If If .Named.Exists( "C" ) Then blnClipboard = True intArgs = intArgs + 1 Else blnClipboard = False End If If .Named.Exists( "Q" ) Then ' /Q can only be used with /C If blnClipboard Then blnQuiet = True intArgs = intArgs + 1 Else Syntax End If Else blnQuiet = False End If If .Named.Exists( "S" ) Then blnShort = True intArgs = intArgs + 1 Else blnShort = False End If If .Named.Exists( "V" ) Then blnVer = True intArgs = intArgs + 1 Else blnVer = False End If If .Named.Exists( "X" ) Then blnExtOnly = True intArgs = intArgs + 1 Else blnExtOnly = False End If ' Check for remaining invalid command line switches If intArgs <> .Named.Count Then Syntax End With ' Create the required objects Set objFSO = CreateObject( "Scripting.FileSystemObject" ) Set wshShell = CreateObject( "Wscript.Shell" ) ' Define internal command lists strIntAll = "BREAK CALL CD CHCP CHDIR CLS COPY DATE DEL DIR ECHO ERASE " _ & "EXIT FOR GOTO IF MD MKDIR MOVE PATH PAUSE PROMPT RD REM " _ & "REN RENAME RMDIR SET SHIFT TIME TYPE VER VERIFY VOL " strIntCmd = "ASSOC COLOR ENDLOCAL FTYPE POPD PUSHD SETLOCAL START TITLE" strIntCom = "CTTY LFNFOR LH LOADHIGH LOCK TRUENAME UNLOCK" ' Determine the type of command processor ' used: COMMAND.COM or CMD.EXE strComSpec = UCase( wshShell.ExpandEnvironmentStrings( "%COMSPEC%" ) ) If Right( strComSpec, 12 ) = "\COMMAND.COM" Then arrInt = Split( strIntAll & strIntCom ) End If If Right( strComSpec, 8 ) = "\CMD.EXE" Then arrInt = Split( strIntAll & strIntCmd ) End If ' Read the PATH and PATHEXT variables, and store their values in ' arrays; the current directory is prepended to the PATH first strPath = wshShell.CurrentDirectory & ";" _ & wshShell.ExpandEnvironmentStrings( "%PATH%" ) strPathExt = wshShell.ExpandEnvironmentStrings( "%PATHEXT%" ) arrPath = Split( strPath, ";" ) arrPathExt = Split( strPathExt, ";" ) ' Check if the command line argument contains a dot ' which would mean we wouldn't have to use PATHEXT blnHasExt = CBool( InStr( WScript.Arguments.Unnamed(0), "." ) > 0 ) If blnHasExt Then ' If an extension WAS specified, just search the PATH strExt = Mid( WScript.Arguments.Unnamed(0), InStrRev( WScript.Arguments.Unnamed(0), "." ) ) arrPathExt = Array( strExt ) strResult = FindWhich( WScript.Arguments.Unnamed(0) ) Else If IsArray( arrInt ) And Not blnExtOnly Then ' Let's check for INTERNAL commands first, unless of course, the /X switch was used For i = 0 To UBound( arrInt ) If UCase( WScript.Arguments.Unnamed(0) ) = arrInt(i) Then strResult = "[" & wshShell.ExpandEnvironmentStrings( "%COMSPEC%" ) & "]::" & arrInt(i) Exit For End If Next End If If strResult = "" Then strResult = FindWhich( WScript.Arguments.Unnamed(0) ) End If End If ' Copy the result to clipboard if the /C command line switch was used If blnClipboard Then Set objIE = CreateObject( "InternetExplorer.Application" ) objIE.Navigate( "about:blank" ) objIE.Document.ParentWindow.ClipboardData.SetData "text", strResult objIE.Quit Set objIE = Nothing End If ' Display the result, unless the /Q command line switch was used If Not blnQuiet Then WScript.Echo strResult End If ' Return code 1 if not found WScript.Quit -( strResult = "" ) Function FindWhich( myFile ) ' This function searches the directories in the PATH array for the ' specified file name, adding extensions from PATHEXT if required Dim i, j, objFound, strFound, strFullPath, strTestPath strFound = "" For i = 0 To UBound( arrPath ) ' Skip empty directory values, caused by the PATH ' variable being terminated with a semicolon If Trim( arrPath(i) ) <> "" Then ' Iterate through the array with extensions (if an extension was specified, ' the array will only contain the specified extension, otherwise it will ' contain all extensions in PATHEXT) For j = 0 To UBound( arrPathExt ) ' Build a fully qualified path of the file to test for strTestPath = objFSO.BuildPath( arrPath(i), objFSO.GetBaseName( myFile ) & arrPathExt(j) ) ' Check if that file exists If objFSO.FileExists( strTestPath ) Then Set objFound = objFSO.GetFile( strTestPath ) If blnVer Then strVer = objFSO.GetFileVersion( strTestPath ) If strVer = "" Then strVer = objFound.DateLastModified End If End If If blnShort Then ' Get the capitalization right strTestPath = objFSO.GetAbsolutePathName( strTestPath ) ' Return the short full path strFullPath = objFound.ShortPath Else ' Return the full path with proper capitalization strFullPath = objFSO.GetAbsolutePathName( strTestPath ) End If If blnAll Then ' Append the path of the file found strFound = strFound & strFullPath If blnVer Then strFound = strFound & vbTab & strVer strFound = strFound & ";" Else ' Abort when the first file is found strFound = strFullPath If blnVer Then strFound = strFound & vbTab & strVer Exit For End If Set objFound = Nothing ' Unless the /A (All) command line switch was used, abort inner loop after the first file is found If strFound <> "" And Not blnAll Then Exit For End If Next End If ' Unless the /A (All) command line switch was used, abort outer loop after the first file is found If strFound <> "" And Not blnAll Then Exit For Next If strFound <> "" Then arrFound = Split( strFound, ";" ) strFound = Join( arrFound, vbCrLf ) End If FindWhich = strFound End Function Sub Syntax( ) Dim strMsg strMsg = vbCrLf _ & "Which.vbs, Version 1.20" & vbCrLf _ & "Find out which file or internal command is actually executed when you type" _ & vbCrLf _ & "a command without its fully qualified path (like UNIX command, but extended)" _ & vbCrLf & vbCrLf _ & "Usage: WHICH.VBS filename[.ext] [ /A ] [ /C [ /Q ] ] [/S] [/V] [/X]" _ & vbCrLf & vbCrLf _ & "Where: filename[.ext] file name (with optional extension) or internal command" _ & vbCrLf _ & " to search for; wildcards (""*"" and ""?"") are not allowed;" _ & vbCrLf _ & " use the extension to search for .dll, .ocx, .ps1, etc." _ & vbCrLf _ & " /A list All matches, not just the first match" _ & vbCrLf _ & " /C copy result to the Clipboard" _ & vbCrLf _ & " /Q Quiet mode, no screen output (only valid with /C)" _ & vbCrLf _ & " /S return Short path(s) (8.3 notation)" _ & vbCrLf _ & " /V show Version number" _ & vbCrLf _ & " /X eXternal commands only, ignore internal commands" _ & vbCrLf & vbCrLf _ & "Notes: /A and /V switches will be ignored for internal commands" _ & vbCrLf _ & " /V will display file timestamp for non-executables" _ & vbCrLf & vbCrLf _ & "Written by Rob van der Woude" & vbCrLf _ & "http://www.robvanderwoude.com" & vbCrLf WScript.Echo strMsg WScript.Quit 1 End Sub