Reputation: 88
I am writing a batch script that installs some applications from MSI files from the same folder.
When I write those commands in command prompt window, all is fine and all the commands work properly.
But when I write them into the batch script, suddenly most of the commands such as XCOPY
, msiexec
, DISM
result in an error message like:
'XCOPY' is not recognized as an internal or external command, operable program or batch file.
After googling it for a while, I saw a lot of comments related to the environment variable PATH
which should contain C:\Windows\system32
and I made sure its included in the PATH
. Also found a lot of answers about writing the full path which I already tried and it didn't work.
I'm working on Windows server 2012.
This is the code of my batch file:
@echo off
set path=C:\ rem default path
rem get the path as parameter to the script:
set argC=0
for %%x in (%*) do Set /A argC+=1
if %argC% gtr 0 (set path=%1%)
IF %ERRORLEVEL% NEQ 0 (
echo %me%: something went wrong with input directory
)
echo Destenation: %path%
SETLOCAL ENABLEEXTENSIONS
SET me=%~n0
SET parent=%~dp0
echo %me%: starting installation of Python 2.7 64bit and Apache 64 bit
REM install .net 3.5
DISM /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:installationMediaDrive:\sources\sxs
msiexec /i ".\py\python-2.7.amd64.msi" TARGETDIR=%path%/Python27 /passive /norestart ADDLOCAL=ALL
mkdir %path%\Apache24
XCOPY /e /Q ".\Apache24" %path%\Apache24
Upvotes: 0
Views: 11862
Reputation: 49086
It looks like the batch file should support an optionally specified path to installation directory as first parameter. The code used to check for existence of this optional folder path is very confusing. There are definitely easier methods to check for an optional parameter as it can be seen below.
The main problem is redefining environment variable PATH
which results in standard console applications of Windows stored in directory %SystemRoot\System32
and other standard Windows directories are not found anymore by command interpreter cmd.exe
on execution of the batch file.
In general it is required to specify an application to execute with full path, file name and file extension enclosed in double quotes in case of this complete file specification string contains a space character or one of these characters &()[]{}^=;!'+,`~
as explained in last paragraph on last output help page on running in a command prompt window cmd /?
.
But mainly for making it easier for human users to execute manually applications and scripts from within a command prompt window, the Windows command interpreter can also find the application or script to run by itself if specified without path and without file extension.
So if a user enters just xcopy
or a batch file contains just xcopy
, the Windows command interpreter searches for a file matching the pattern xcopy.*
which has a file extension as defined in semicolon separated list of environment variable PATHEXT
first in current directory and if no suitable file found next in all directories in semicolon separated list of environment variable PATH
.
There are 3 environment variables PATH
:
The system PATH
as stored in Windows registry under:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
The folder paths in system PATH
are used by default for all processes independent on used account.
The user PATH
as stored in Windows registry under:
HKEY_LOCAL_MACHINE\Environment
The folder paths in user PATH
are used by default only for all processes running using the account on which the user PATH
was set.
The local PATH
just hold in memory in currently active environment of running process.
The system and the user PATH
are concatenated by Windows to a single local PATH
for processes.
Every time a process starts a new process like Windows Explorer starting Windows command interpreter for execution of a batch file, a copy of the environment table of currently running process is created by Windows for the new process. So whatever a process changes on its own local copy of environment variables has no effect on all other already running processes. The local changes on the environment variables are effective only on own process and all processes started by the process modifying its variables.
On starting the batch file the variables PATH
and PATHEXT
have the values as displayed on running in a command prompt window opened under same user account as used on starting the batch file the command set PATH
listing all variables starting with PATH
case-insensitive in name.
Now let us look on the second line of the batch file:
set path=C:\ rem default path
This line redefines the local PATH
environment variable. Therefore the environment variable PATH
being effective for the command process executing the batch file and all applications started by this batch file does not contain anymore C:\Windows\System32;C:\Windows;...
, but contains now just this very strange single folder path.
C:\ rem default path
rem
is an internal command of cmd.exe
and must be written on a separate line. There is no line comment possible in batch code like //
in C++ or JavaScript. For help on this command run in a command prompt window rem /?
.
On running the batch file without an installation folder path as first argument, the result is that Windows command interpreter searches for dism.*
, msiexec.*
and xcopy.*
just in current directory as there is surely no directory with name rem default path
with lots of spaces/tabs at beginning in root of drive C:
.
Conclusion: It is no good idea to use path
as variable name for the installation folder path.
Another mistake in batch code is using %1%
to specify the first argument of the batch file. This is wrong as the arguments of the batch file are referenced with %1
, %2
, ... Run in a command prompt window call /?
for help on referencing arguments of a batch file and which possibilities exist like %~dp0
used below to get drive and path of argument 0 which is the batch file name, i.e. the path of the folder containing the currently running batch file.
I suggest using this batch code:
@echo off
setlocal EnableExtensions
set "SourcePath=%~dp0"
set "BatchName=%~n0"
if "%~1" == "" (
echo %BatchName% started without an installation folder path.
set "InstallPath=C:\"
goto StartInstalls
)
rem Get installation folder path from first argument
rem of batch file without surrounding double quotes.
set "InstallPath=%~1"
rem Replace all forward slashes by backslashes in case of installation
rem path was passed to the batch file with wrong directory separator.
set "InstallPath=%InstallPath:/=\%"
rem Append a backslash on installation path
rem if not already ending with a backslash.
if not "%InstallPath:~-1%" == "\" set "InstallPath=%InstallPath%\"
:StartInstalls
echo %BatchName%: Installation folder: %InstallPath%
echo/
echo %BatchName%: Installing .NET 3.5 ...
DISM.exe /Online /Enable-Feature /FeatureName:NetFx3 /All /LimitAccess /Source:installationMediaDrive:\sources\sxs
echo/
echo %BatchName%: Installing Python 2.7 64-bit ...
%SystemRoot%\System32\msiexec.exe /i "%SourcePath%py\python-2.7.amd64.msi" TARGETDIR="%InstallPath%Python27" /passive /norestart ADDLOCAL=ALL
echo/
echo %BatchName%: Installing Apache 2.4 64-bit ...
mkdir "%InstallPath%Apache24"
%SystemRoot%\System32\xcopy.exe "%SourcePath%\Apache24" "%InstallPath%Apache24\" /C /E /H /I /K /Q /R /Y >nul
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
... for explanation of %~dp0
, %~n0
and %~1
.dism /?
echo /?
endlocal /?
goto /?
if /?
msiexec /?
rem /?
set /?
setlocal /?
xcopy /?
And read also
setlocal
and endlocal
really work andset "variable=value"
.And last take a look on:
The administrator of a Windows server should twist everything written here and on the referenced pages round one's little finger.
Upvotes: 4