Batch: How to run tree command from current directory? - batch-file

I may be confusing current directory with working directory but regardless I am trying to make a batch file that runs the tree command from the folder it's currently in.
I have a folder called "Network_Switch_Backup" with a script, some other items and a subfolder called "backups".
This has worked for testing purposes:
tree U:\Desktop\Network_Switch_Backup\backups /f
But as I will be zipping it and sending it to different computers and users clearly this isn't practical since they could put the folder anywhere besides the desktop.
I've looked at other threads and amongst other things I tried, this looked the most promising (but still did not work):
tree %cd%\backups /f
However tree %cd%\downloads /f works perfectly fine when running from cmd so I'm just a bit confused.

It is advisable in batch files to reference executables to run with full qualified file name which means full path + file name + file extension, especially if the storage location of the executable is well known. That makes the batch file independent on the values of the environment variables PATHEXT and PATH. PATH is quite too often not correct defined on many computers running Windows.
The full qualified name of TREE is %SystemRoot%\System32\tree.com.
Environment variable SystemRoot is not defined as system or user environment variable like PATH and PATHEXT, but is nevertheless defined on execution of a batch file. So it is very safe to use this Windows environment variable.
What is the reason for '...' is not recognized as an internal or external command, operable program or batch file? explains very detailed how Windows command processor finds executables and scripts not specified with full qualified file name on command prompt or in a batch file.
There are two directories which need to be taken into account on coding an application or script:
The application/script directory is the directory containing the program or script.
The current directory or working directory is the directory from which the program or script is executed.
For example a batch file is stored in directory "%UserProfile%\Desktop". Windows sets the directory of the batch file as current directory on simply double clicking the batch file on user's desktop. Therefore the script directory is the current directory on execution of the batch file. But if this batch file is executed by right clicking on the batch file and left clicking on context menu option Run as administrator, the batch file stored in "%UserProfile%\Desktop" is usually executed from directory %SystemRoot%\System32 depending on user account permissions and on user account control setting of current user. The reason for making %SystemRoot%\System32 the current directory before executing the batch file is explained in detail by answer on Why does 'Run as administrator' changes (sometimes) batch file's current directory?
The MSDN article Naming Files, Paths, and Namespaces explains in detail how to reference files and folders relative to current directory. The current directory is simply not included in file/folder argument string or alternatively represented by .\.
In case of drive and path of current directory needs to be known, for example to output it on running a batch file, there is the dynamic environment variable CD (short for Current Directory). %CD% or !CD! with delayed expansion enabled expands to full path of current directory which does not end with a backslash, except the current directory is the root directory of a drive. The help output on running in a command prompt window set /? explains dynamic environment variable CD briefly on last help page.
Batch files need to be designed very often to reference files or folders with a path relative to directory of the batch file. In this case it is not advisable to use the current directory because the current directory can be really any directory.
The help output on running call /? in a command prompt window explains how arguments of a batch file can be referenced from within a batch file. Argument 0 is always the batch file itself.
%~dp0 references drive and path of the batch file. This file path ends always with a backslash, but of course can contain a space or one of these characters &()[]{}^=;!'+,`~ which require entire file/folder argument string to be enclosed in double quotes. So %~dp0 must be concatenated in a batch file without an additional backslash after that string and the entire argument string must be enclosed in double quotes to work safely.
So the command line to use to reference the subdirectory Backups in directory of the batch file independent on which directory is the current directory is:
%SystemRoot%\System32\tree.com "%~dp0Backups" /F
A bug of cmd.exe explained in detail on What is the reason for batch file path referenced with %~dp0 sometimes changes on changing directory? should be taken into account on using %~dp0 in a batch file.

Related

Why does my VBScript function differently if it is opened by a batch script rather than a person?

Simply put, I have a VBScript titled "tyrian_soundtest.vbs" that plays an .mp3 that is titled "tyrian_soundtest.mp3"
The VBScript code is below
Set Sound = CreateObject("WMPlayer.OCX.7")
Sound.URL = "tyrian_soundtest.mp3"
Sound.Controls.play
do while Sound.currentmedia.duration = 0
wscript.sleep 1
loop
wscript.sleep (int(Sound.currentmedia.duration)+1)*1000
When opened, it plays the .mp3. Simple enough.
The trouble comes in when I run a batch script titled "tyrian_soundtest.bat". Relative to it, the .vbs and .mp3 are in a folder called sfx. Here is what one iteration of that file contained.
#echo off
start %cd%\sfx\tyrian_soundtest.vbs
exit /b
The result is an error stating that Windows couldn't find the file path, likely due to it containing a space. Other attempts of the .bat were replacing line 2 with
start .\sfx\tyrian_soundtest.vbs
or
start "%cd%\sfx\tyrian_soundtest.vbs"
Any attempt I've made gives one of three results. Option 1: There is no error, but the audio simply never plays. Option 2: An error is thrown about the file directory not being found. Option 3: That file path opens up in a new cmd window, but the .vbs is never run.
Is there any way format the .bat to get the .vbs to run through the without an error being caused?
The main issue is that there is used in batch file and in the VBScript file the current directory path. The current directory on starting %SystemRoot%\System32\cmd.exe to process the batch file can be any directory.
The Windows Explorer sets the directory of the batch file as current directory on double clicking the batch file resulting in starting cmd.exe by explorer.exe to process the double clicked batch file of which full qualified file name is passed to cmd.exe after the option /c as additional argument. But if the batch file is stored on a network resource accessed using UNC path, the Windows command processor changes the current directory from the network resource to %SystemRoot% (the Windows directory) and the batch file fails to start Windows Script Host to process the VBS file. See also: CMD does not support UNC paths as current directories.
A batch file can be also started by right clicking on it and using Run as administrator. This can result in making the directory %SystemRoot%\System32 (the Windows system directory) the current directory. See also: Why does 'Run as administrator' change (sometimes) batch file's current directory?
That are just two of many examples where the current directory is different to the directory containing the batch file. So if a batch file references other files stored in same directory as the batch file itself or a subdirectory of the batch files directory, it is advisable to reference these files with the full path of the batch file instead of using a path relative to current directory.
Example:
The used files are stored in directory C:\Temp\Development & Test as follows:
sfx
tyrian_soundtest.vbs
tyrian_soundtest.mp3
tyrian_soundtest.bat
A user opens a command prompt window which usually results in making the directory referenced with %USERPROFILE% or with %HOMEDRIVE%%HOMEPATH% the current directory. A user executes next in the command prompt window:
"C:\Temp\Development & Test\tyrian_soundtest.bat"
So the current directory is definitely not the directory containing the batch file.
The batch file can be coded as follows to start nevertheless the Windows Script Host for processing the VBS file tyrian_soundtest.vbs and successfully play the MP3 file tyrian_soundtest.mp3.
#start "" /D "%~dp0sfx" %SystemRoot%\System32\wscript.exe //NoLogo "%~dp0sfx\tyrian_soundtest.vbs"
%~dp0 references the drive and path of argument 0 which is the full path of the currently processed batch file. The batch file path referenced with %~dp0 always ends with a backslash. For that reason the concatenation of %~dp0 with a file/folder name or wildcard pattern should be always done without using an additional backslash as that would result in two \ in series in complete argument string and the Windows file management would need to fix that small error by replacing \\ by just \ before passing the argument string to the file system. See also the Microsoft documentation about Naming Files, Paths, and Namespaces which explains which automatic corrections are usually applied on file/folder strings before passing them to the file system.
The internal command START of cmd.exe interprets the first double quoted argument string as title string for the console window as it can be seen on running in a command prompt window start /? and reading the output help. For that reason it is not enough to use just:
#start "%~dp0sfx\tyrian_soundtest.vbs"
That would result in starting one more command process with its own console window with the full qualified file name of the VBS file as title of the console window.
The Windows Script Host processing a VBS file by default on Windows exists in two versions:
%SystemRoot%\System32\cscript.exe is the console version.
%SystemRoot%\System32\wscript.exe is the Windows GUI version.
The usage of the console version cscript.exe results usually in opening a console window by the parent process if the parent process is not itself a console application running already with an opened console window like on execution of a batch file processed by %SystemRoot%\System32\cmd.exe being also a console application.
The usage of the Windows GUI version wscript.exe results in no opening of a window by default at all. The processed script file must contain commands to open a window if that is wanted at all.
The difference can be also seen on running from within a command prompt window cscript /? and next wscript /?. The first command results in printing the help for the command line options of Windows Script Host in already opened command prompt window while the second command results in showing a graphic window by wscript.exe displaying the same usage help.
The usage help of Windows Script Host explains also how each user can define which version of Windows Script Host is the default for executing scripts. So it is not advisable to specify just the VBS file name with full path on the command line with start and let cmd.exe look up in Windows registry which version of Windows Script Host to run to process the VBS file. It is better to explicitly run the version of Windows Script Host most suitable for playing the MP3 file which is in this case the Windows GUI version wscript.exe opening by default no window at all to play the MP3 file in background.
So it would be possible to use:
#start "" %SystemRoot%\System32\wscript.exe //NoLogo "%~dp0sfx\tyrian_soundtest.vbs"
There is an empty title string defined with "" as the started executable wscript.exe is a Windows GUI application for which no console window is opened at all by cmd.exe. So the title string does not really matter and can be an empty string.
But there is left one problem with that command line. The VB script references the MP3 file without path which means with a path relative to current directory. The current directory is %USERPROFILE% and not C:\Temp\Development & Test\sfx which contains the MP3 file tyrian_soundtest.mp3. So the VB script would fail to find the MP3 file to play.
There are two solutions to fix this:
The usage of the following command line in the batch file:
#start "" /D "%~dp0sfx" %SystemRoot%\System32\wscript.exe //NoLogo "%~dp0sfx\tyrian_soundtest.vbs"
The option /D of command START is used to explicitly set the subdirectory sfx of the batch file directory as start in respectively current directory for the process wscript.exe which cmd.exe starts using the Windows kernel library function CreateProcess with an appropriate created structure STARTUPINFO.
The VBS file references the MP3 file tyrian_soundtest.mp3 with its full path which the VB script file determines itself from its own full qualified file name. That can be achieved in the VB script file tyrian_soundtest.vbs by using in the second line:
Sound.URL = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName) + "\tyrian_soundtest.mp3"
Best would be using both possible solutions as in this case the VB script file would work also on being executed by a different process than cmd.exe processing the batch file tyrian_soundtest.bat and deletion of directory %~dp0sfx is not possible as long as started wscript.exe is running because of this directory is the current directory of running Windows Script Host.
So the batch file as well as the VB script file work now both independent on which directory is the current directory as both reference the files with full path determined by the scripts themselves from their full qualified file names.

Calling batch file reports: "The system cannot find the path specified"

I have one batch file that suppose to call another. I read that call command is used in this case. Although error message appears:
The system cannot find the path specified.
The path is not wrong 100% sure. This is the caller run.bat
#echo off
call xslt\projects\asp-bus\implementation\batch\ant-start.bat
pause
and this is the called ant-start.bat
set ant="../../../../infrastucture/apache-ant-1.10.0/bin/ant.bat"
call %ant%
pause
In each batch file, the paths are relative to the working folder you are running the batch file from, not the folder that contains the batch file itself. You either need to use absolute paths (e.g. starting with C:\), or to make sure that when each batch file is run from a working folder where the relative paths make sense.
If you're launching run.bat from a Windows shortcut, you can set the "Start In" folder from the shortcut's Properties dialog. When ant-start.bat is called, it will run from the same folder as run.bat.
To fix the problem, you might need to change ant-start.bat to
set ant="infrastucture/apache-ant-1.10.0/bin/ant.bat"
call %ant%
pause
Alternatively, you could put a cd command in one of the batch files, to force it to use an appropriate working folder.
Bear in mind that if you set the %ant% variable to a relative path as above, using the variable will only work from a folder where that relative path makes sense.

Batch File To Get It's Own Directory Or The Directory Defined In The "Start In" Property Of A Shortcut

I am writing a batch file on my Windows 8.1 machine. In one section of my batch file I need to start a command prompt in the "current working directory".
So far, this is what my batch file looks like:
#echo OFF
set WORKING=%cwd%
start cmd.exe /K pushd %WORKING%
exit
Let's say the batch file is located in the folder C:\Temp\Utilities. If I open an explorer window and double click the batch file to run it everything works great. A new command prompt is created in the directory C:\Temp\Utilities. However, if I right-click the batch file and select Run as administrator the working directory is no longer the location of the batch file, it's C:\Windows\System32.
Similarly, if I create a shortcut to the batch file in a different folder (for example. C:\Temp) and repeat the two steps above the results are the same. If I double click the shortcut and run it as a normal user the working directory is what I would expect. (Note, the working directory for the shortcut it's whatever is set for "Start in" of the shortcut properties, not the location of the batch file.) If I right click the shortcut and run it as administrator I again get a command prompt opened to the folder C:\Windows\System32.
I assume this is a "bug" or "feature" (if you want to call it that) in Windows 8.1 and it probably happens because execution environments for programs run as administrator are forced to run in the System32 folder? (I remember with Windows 7 this did not happen so it must be a new feature to Windows 8.)
I found one way to fix the issue and stop the command prompt from starting in C:\Windows\System32. I did this by modifying the following line in the batch file:
set WORKING=%~dp0
Doing it this way sets the working directory to the location of the batch file. With this change, no matter how I run the batch file or the shortcut (administrator or normal) the working directory ends up being the same, C:\Temp\Utilities.
The problem with this solution is I don't want the working directory to always be the location of the batch file. If the batch file is run directly then it's okay but if I run it from a shortcut I need the working directory to be whatever is set in the "Start in" property of that shortcut. For example, if the batch file is located in the folder D:\Temp\Utilities this is what I need to happen regardless of whether I run as administrator or not:
Shortcut Location Start In Property Command Prompt Working Directory
-------------------- ------------------- ------------------------------------------
C:\Temp <undefined> D:\Temp\Utilities
C:\Data\bin C:\Data\bin C:\Data\bin
C:\Data\bin D:\Temp\Utilities D:\Temp\Utilities
What this means is I can't always use %~dp0 to set the working directory in my batch file. What I need is some way for the batch file to know if it was run either directly or by a shortcut. If the batch file is run directly then the working directory is easy to get, it's just the value of %cwd%. If the batch file is run by using a shortcut, I don't know how to get the "Start in" property inside the batch file.
Does anyone know how I can do these two things inside my batch file:
1. Check whether it was run directly or by a shortcut.
2. If run by a shortcut, get the "Start in" property of the shortcut that started it.
Thank you,
Orangu
UPDATE
I found sort-of a "hackish" way to fix the issue. For the shortcut I edited the "Target" field and changed it to the following:
cmd.exe /k pushd "C:\Temp" && "D:\Temp\Utilities\batchfile.bat"
Now the working directory can be obtained by calling %CD% in the batch file and this works for both administrator and normal users. It does not, however, work for the case when I run the batch file directly. I still need to use %~dp0 in that case.
I don't like this solution, however, because it requires me to manually change all shortcuts I make and it also makes the icon look like a cmd prompt icon rather than a batch file.
Have you already considered to not use shortcuts at all?
You could e.g. create a batchfile_exec.bat containing your call
REM optionally do
REM cd /D working_directory
REM if you want to force a special working directory
D:\Temp\Utilities\batchfile.bat
and replace all the shortcuts with batchfile_exec.bat. If you double-click batchfile_exec.bat, the working directory will be the one containing batchfile_exec.bat.
I personally don't like Windows shortcuts that much, because they are hard to handle within a revision control system. As you also noticed, it is very time consuming if you want to modify a lot of them.
By the way: If batchfile.bat was designed/written to be always run from the direcory where it is located, you might also consider to modify batchfile.bat to force that behaviour:
setlocal
cd /D %0\..
REM your original content
endlocal
In %0 the path to the batchfile is stored.
The trick is to assume that %0 is a directory and then to change one level lower based on that directory. With /D also the drive letter is changed correctly.
The cd command doesn't care if %0 is really a directory. In fact %d doesn't even have to exist (%0\dummy\..\.. would also work).
The setlocal command is to have the working directory being restored when batchfile.bat has finished (this would be good if batchfile.bat was called form another batch file).
I noticed that the endlocal command is not really necessary in this context since it is applied implicitly when batchfile.bat finishes.

.exe file execution from within

If I make a file foo.exe, and it contains the files bar.bat, baz.bat, and qux.bat, can I call baz.bat from within bar.bat? I mean, if bar.bat is the file that is executed upon execution of foo.exe?
I had done something similar using winrar (instead of iexpress) self extracting archive.
The mechanism is like below:
First it will extract everything to specified folder (or in temporary folder %TEMP%/random_name)
Then it will call initial executable/script or "script to run after extraction". In your case, it's bar.bat.
That executable script can in turn call any other script/executable. (baz.bat in your example)
To be sure, change the file bar.bat to contain below script:
#echo off
cd
explorer .
pause
This will print the directory name, where it has extracted & open the directory with explorer.exe. Then you can verify that your baz.bat is in same directory. Give relative path, if required.

Make a batch that detects its own filepath

I need to make a batch file that detects what drive and directory it is in. When I run the the file normally, it is in the correct directory/drive already. But when it is run as admin, it starts in system32. Is there a command that goes to the directory or drive the batch came from?
You could use
Pushd "%~dp0"
This changes the current directory to the path of the batch file.
Quoting the argument makes it safe against special characters in the pathname like "C:\Documents & Settings"
well a workaround is to use \ before the path to give absolute path.
So, if you need to run a file c:\temp\xyz.exe and even if you are in directory c:\winodws\system32 still when you do cd \temp\xyz.exe still the file will run properly

Resources