How to store Parent Directory as a variable, Cmd/Bat files - batch-file

Problem
I am writing some .cmd / .bat files on a windows machine that need to work on an sd card with variable parent directories. The sd card will likely change drive names (Drive A, Drive E, etc.) as it moves from device to device and I want to write cmd files that will anticipate that. I would like this to work with my linux steam deck if possible, but if not I understand.
Rom Location
E:\Games\Nintendo\3DS\Games\Animal Crossing New Leaf.3ds
Core Location
E:\Games\RetroArch\cores\citra_libretro.dll
3DS.cmd , currently works at this address
#echo off
echo Keeping Window Active for GOG Time Tracking
cd "E:\Games\RetroArch\"
"retroarch.exe" -L "cores\citra_libretro.dll" %1 -f
Animal Crossing New Leaf.cmd , currently works at this address
#echo off
call "3DS.cmd" "E:\Games\Nintendo\3DS\Games\Animal Crossing New Leaf.3ds"
Question
How would I write the code above as a windows file on any non-specific drive directory where the current Directory is on the Drive named E:\ ?
(Ex: A:\ , or B:, and so on)

There can be used the following lines in the batch file 3DS.cmd if this batch file is stored in root of the SD card and is executed from the SD card mounted as drive with a drive letter:
#echo off
echo Keeping window active for GOG time tracking
cd /D "%~d0\Games\RetroArch"
retroarch.exe -L cores\citra_libretro.dll %1 -f
The usage help of command CALL output on running call /? in a command prompt window explains how to reference the arguments of a batch file. There is always the argument 0 even on batch file is executed without any argument string passed to the batch file by a user or another process.
%0 references the string used to start the execution of the batch file. On double clicking on a batch file stored on an SD card mounted with a drive letter by Windows, %0 expands to the fully qualified file name of the batch file on the SD card enclosed in " because of the Windows File Explorer starts in background:
C:\WINDOWS\system32\cmd.exe /c ""Animal Crossing New Leaf.cmd" "
The usage help of the Windows Command Processor cmd.exe output on running cmd /? explains how the arguments are interpreted by cmd.exe in this case. The first and the last " are removed from the command line. The started cmd.exe executes therefore:
"E:\Animal Crossing New Leaf.cmd"
That string with the double quotes is argument 0 of the executed batch file.
%~d0 can be used in the batch file to reference just the drive letter and the colon of the currently running batch file respectively \\ if the batch file is stored on a network resource executed using its UNC path.
The code above works only for batch file being stored in root of a storage media mounted with a drive letter.
A code for 3DS.cmd working always independent on which storage media the batch file is stored and in which directory and how the batch file is started as long as the directory Games is a subdirectory of the directory containing the batch file is:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
cls
if "%~1" == "" echo ERROR: %~nx0 called without game file name!& pause & exit /B
pushd "%~dp0Games\RetroArch"
echo Keeping window active for GOG time tracking
retroarch.exe -L cores\citra_libretro.dll %1 -f
popd
endlocal
%~dp0 expands to full path of the batch file always ending with a backslash.
See also: What is the reason for batch file path referenced with %~dp0 sometimes changes on changing directory? The bug of cmd.exe does not matter here because of %~dp0 is used before changing the current directory the first time with the command PUSHD.
The batch file Animal Crossing New Leaf.cmd stored in same directory as 3DS.cmd should contain only the single command line:
#call "%~dp03DS.cmd" "%~dp0Games\Nintendo\3DS\Games\Animal Crossing New Leaf.3ds"
The two batch files can be used with these improvements also on copying all directories and files on the SD card to a directory of user´s choice like %UserProfile%\RetroGames.
It is also possible to use only one batch file with name Animal Crossing New Leaf.cmd stored in the directory with the subdirectory Games and all the other directories and files with the following lines:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0Games\RetroArch" || (echo ERROR: Missing subdirectory "Games\RetroArch"& pause & exit /B)
echo Keeping window active for GOG time tracking
retroarch.exe -L cores\citra_libretro.dll "%~dp0Games\Nintendo\3DS\Games\Animal Crossing New Leaf.3ds" -f
popd
endlocal
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
call /?
cd /?
echo /?
endlocal /?
exit /?
if /?
pause /?
popd /?
pushd /?
setlocal /?

I used Chat GPT, it gave me this result that is now working.
3ds.cmd
#echo off
echo Keeping Window Active for GOG Time Tracking
set sd_dir=%cd:~0,1%
cd "%sd_dir%:\Games\RetroArch\"
"retroarch.exe" -L "cores\citra_libretro.dll" %1 -f
Animal Crossing New Leaf.cmd
#echo off
set sd_dir=%cd:~0,1%
call "3DS.cmd" "%sd_dir%:\Games\Nintendo\3DS\Games\Animal Crossing New Leaf.3ds"

Related

The system cannot find the path specified - batch to exe

Good morning. I have written a batch file that updates the group policy via the audit.csv file. Previously I was changing the policy via auditpol but those changes didn't persist so I came up with this solution.
:: Write the correct audit settings to audit.csv
set "auditFile="C:\Windows\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit\audit.csv""
echo Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting,Setting Value > %auditFile%
echo ,System,Audit Credential Validation,{0cce923f-69ae-11d9-bed3-505054503030},Success and Failure,,3 >> %auditFile%
…
It does some other stuff, but that's where I'm getting the error.
Yesterday, running this just as a regular batch script file worked fine. Now I'm getting the The system cannot find the path specified. error. I have seen a few posts with the same problem and the solution was to run cmd /c file.bat which isn't working for me right now. When creating the post, I wasn't expecting to have this problem running the batch file. When I tested yesterday, the batch file worked fine, but when I converted to an exe (both with PowerArchiver and iexpress) is when I got the error. So I don't know why it's not working in the .bat version, but I guess if I can fix this it should fix the converted exe.
My main question is why am I getting that error? Is it because of the echo command? Is it giving me the error because of the file I'm trying to access? Is it a permissions thing?
The batch file is executed by 64-bit cmd.exe stored in %SystemRoot%\System32 on double clicking on the batch file with Windows File Explorer. The directory %SystemRoot%\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit exists most likely in this case (not on my Windows computers).
But after packing the batch file into a 32-bit executable file which extracts it on execution into %TEMP% or a temporarily created subdirectory in %TEMP% and next runs Windows command processor for execution of the temporarily extracted batch file, the 32-bit cmd.exe stored in %SystemRoot%\SysWOW64 is executed because of Windows File System Redirector.
The file system redirector active in execution environment of x86 applications redirects the write access to file %SystemRoot%\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit\audit.csv now to %SystemRoot%\SysWOW64\GroupPolicy\Machine\Microsoft\Windows NT\Audit\audit.csv and most likely the entire directory tree for file audit.csv does not exist in this case.
A solution would be using this code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define Windows system folder path and make sure the right path is used
rem if this batch file is executed on 64-bit Windows in 32-bit environment.
set "SystemFolder=%SystemRoot%\System32"
if not "%ProgramFiles(x86)%" == "" if exist %SystemRoot%\Sysnative\cmd.exe set "SystemFolder=%SystemRoot%\Sysnative"
set "AuditFilePath=%SystemFolder%\GroupPolicy\Machine\Microsoft\Windows NT\Audit"
rem Create the directory with suppressing the error message on missing
rem permissions to create this directory or on directory existing already.
md "%AuditFilePath%" 2>nul
if not exist "%AuditFilePath%\" (
echo ERROR: Failed to creeate the directory:
echo %SystemRoot%\System32\GroupPolicy\Machine\Microsoft\Windows NT\Audit
echo The batch file "%~nx0" must be run as administrator.
goto EndBatch
)
rem Write the correct audit settings to file audit.csv.
set "FullAuditFileName=%AuditFilePath%\audit.csv"
(
echo Machine Name,Policy Target,Subcategory,Subcategory GUID,Inclusion Setting,Exclusion Setting,Setting Value
echo ,System,Audit Credential Validation,{0cce923f-69ae-11d9-bed3-505054503030},Success and Failure,,3
) >"%FullAuditFileName%"
rem More commands to execute.
:EndBatch
endlocal
This batch file also creates the file audit.csv with the two CSV lines without a trailing space at end of both lines.
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 /? ... explains %~nx0 ... name + extension of batch file
echo /?
endlocal /?
goto /?
if /?
md /?
rem /?
set /?
setlocal /?
See also:
Microsoft documentation about WOW64 Implementation Details
Microsoft documentation about Using command redirection operators

Batch file launcher (in batch) does not evaluate the path correctly

Task
I'm trying to make a launcher (in batch) for my (almost) all batch program in the Program Files (x86) folder. I also need it to be compatible with any one's Windows 10 machine.
Problem
The cd command does not evaluate the path correctly. It just says The directory name is invalid.
Code
#echo off
color 02
cls
cd "%~dp0batchfile.bat"
start /max /realtime %cd%
exit
Debug
I've moved the file around, adjusted the code, and even put the raw path and it all worked! But it still gives the error and causes the program to malfunction. I'm worried it can cause damage to someone's computer and to others' as well. (It's pretty overcomplicated for batch lol) I've also tried to echo the cd before, the path it's supposed to be set to, and the cd after. The cd before and what it's to be set to is fine, but it still says The directory name is invalid. And "doesn't" get set. Here is the code I tried:
#echo off
color 02
cls
cd "%~dp0batchfile.bat"
rem Debug:
echo %cd%
pause
rem real code:
start /max /realtime %cd%
exit
And it's fine. It gives the error, yet it works without interruption and causes less lag and glitches. I haven't a clue why because for my smol phatt brain this shouldn't even be possible. Bless you. Maybe it's just a bug that Microsoft needs to fix, but whatever it is, it is so annoying and it ruins the cleanliness of my (almost) all batch program.
Conclusion (That you made)
You think: This imbecile doesn't even know where to START when asking questions on StackOverflow.
Me reading your thoughts: This is the first question I ask on StackOverflow. So yes, I mean no, no yes, wait wait no, I don't know where to start. What? Bless you. Oop Bless you again.
cd "%~dp0batchfile.bat"
Why are you trying to cd into a batch file in the same directory as your script? That's obviously not going to work, as per the transcript you'll see idf you let cmd echo the commands before executing them (by commenting out the echo off, along with other stuff not needed for debugging):
rem #echo off
rem color 2
rem cls
cd "%~dp0batchfile.bat"
rem start /max /realtime %cd%
rem exit
If you run that, you'll see:
C:\Users\Allan>rem #echo off
C:\Users\Allan>rem color 02
C:\Users\Allan>rem cls
C:\Users\Allan>cd "C:\Users\Allan\batchfile.bat"
The system cannot find the path specified.
C:\Users\Allan>rem start /max /realtime C:\Users\Allan
C:\Users\Allan>rem exit
In other words, you probably should just be using %~dp0 in the cd command.
batchfile.bat is a FILE and not a directory. So it is not possible to change current directory to file batchfile.bat.
One solution is cd /D "%~dp0" to change the current directory to directory containing the currently executed batch file. This works as long as the batch file is stored on a storage media with a drive letter assigned. So the code would be:
#echo off
cd /D "%~dp0"
color 02
cls
start "Window Title" /MAX "FileName.exe"
color
But a batch file could be stored also on a network resource started with using UNC path. Windows command processor cmd.exe does not allow by default that a network resource path is set as current directory. The following code would be necessary for such use cases.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0" || goto :EOF
color 02
cls
start "Window Title" /MAX "FileName.exe"
color
popd
But a launcher batch file should not make the directory of itself the current directory, but the directory of the batch file to launch of which file name is passed to the launcher batch file as first argument. So a launcher batch file for other batch files could be:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" (
color 02
cls
echo INFO: "%~nx0" must be started with a batch file name.
echo/
pause
color
) else start "%~n1" /MAX %SystemRoot%\System32\cmd.exe /C "pushd "%~dp1" && (color 02 & cls & "%~nx1" & popd)"
endlocal
Do not use command exit to exit cmd.exe independent on calling hierarchy. That is not necessary here and makes it only more difficult to debug the batch file on executing it from within a command prompt window.
Do not use option /REALTIME of command START because this process priority class is mainly for drivers and should never be used for other executables and definitely not for a batch file processed by cmd.exe.
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 /? explaining:
%~dp0 ... drive and path of argument 0, the full batch file path always ending with a backslash,
%~1 ... first argument with surrounding double quotes removed,
%~n1 ... file name of first argument,
%~dp1 ... drive and path of first argument,
%~nx1 ... file name and extension of first argument.
cd /?
cls /?
cmd /?
color /?
echo /?
endlocal /?
goto /?
if /?
pause /?
popd /?
pushd /?
setlocal /?
start /?
See also single line with multiple commands using Windows batch file.

Test IF file exist, del this local file

This question is related to Test IF file exist, ELSE xcopy these two files.
Background: On occasion I choose to run aGallery-dl.bat in a given folder (just one in each of 100's of folders). It first deletes Folder.jpg then renames Folder2.jpg to Folder.jpg. This has the effect of a red X being replaced by a yellow ! when viewing the folder with parent folder selected in File Explorer. Secondly, it calls gallery-dl.exe. I use going from red X to yellow ! to let me know I've run aGallery-dl.bat at least once. If aGallery-dl.bat completes successfully, it finally deletes the Folder.jpg (currently yellow !), and now the representative contents of the folder (usually DeviantArt .jpg's) are visible. All is well.
rem #echo off
del .\Folder.jpg
ren .\Folder2.jpg Folder.jpg
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
"C:\Program Files (x86)\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive ".\aGDB.sqlite3" "https://www.deviantart.com/"%FOLDER%"/gallery/all"
del .\Folder.jpg
Problem: Restating, Gallery-dl.bat is in each of 100's of folders. On occasion, I run one of these from within it's local folder. Line 5, if the call to the web site is successful, gallery-dl.exe creates zzzGDB.sqlite3 within the local folder.
In the previous code, when aGallery-dl.bat completed, it would just delete the Folder.jpg. This assumes the call to the web page was successful. On rare occasion, the call to the web page will fail for any number of reasons, though at close (due to that final del .\Folder.jpg), it will still delete folder.jpg.
If zzzGDB.sqlite3 was not created/not present, I need the Folder.jpg (yellow !) to remain.
So, in the below code (line 6, now blank), I've lopped off the final del .\Folder.jpg and am trying to plug-in the provided code beginning at line 7, inserting a test for zzzGDB.sqlite. If found, del .\Folder.jpg. If not found, no action is taken against folder.jpg (it remains).
(The rem statement at the very bottom is just acting as a placeholder for my own knowledge.)
rem #echo off
del .\Folder.jpg
ren .\Folder2.jpg Folder.jpg
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
"C:\Program Files (x86)\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive ".\zzzGDB.sqlite3" "https://www.deviantart.com/"%FOLDER%"/gallery/all"
setlocal EnableExtensions DisableDelayedExpansion
for /D %%I in ("U:\11Web\gallery-dl\deviantart\*") do (
if exist "%%I\zzzGDB.sqlite3" (
del "%%I\Folder.jpg"
)
rem
)
endlocal
Note: Currently, the modified code goes back through every single folder within U:\11Web\gallery-dl\deviantart\*. This action should be reserved only to the local folder. I'm guessing the below is the issue.
for /D %%I in ("U:\11Web\gallery-dl\deviantart\*")
I don't know how to remove it and still implement everything after do?
do (
if exist ".\zzzGDB.sqlite3" (
del ".\Folder.jpg"
)
rem
)
I suggest to use following lines for aGallery-dl.bat.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0" || exit /B
move /Y "Folder2.jpg" "Folder.jpg"
for %%I in (.) do set "FOLDER=%%~nxI"
"%ProgramFiles(x86)%\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive "%~dp0zzzGDB.sqlite3" "https://www.deviantart.com/%FOLDER%/gallery/all"
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
popd
endlocal
The first two lines define the execution environment for the batch file.
The third line with command PUSHD pushes the current directory path on stack and sets the directory of the executed batch file as current directory. This works even on batch file being stored on a network resource accessed using a UNC path, except there is a network problem on execution of that command line.
The command exit /B is executed in case of an error to immediately exit processing of the batch file on batch file directory could not be set as current directory. The Windows command processor runs implicitly the command ENDLOCAL in this case.
See Single line with multiple commands using Windows batch file for an explanation of operator || which results in conditionally executing exit /B only if pushd exited with a non-zero exit code indicating an error.
The fourth command line with MOVE does not really move the data of file Folder2.jpg to file with name Folder.jpg. In real it just updates the file system in this case as done also by the two commands del .\Folder.jpg and ren .\Folder2.jpg Folder.jpg in your batch file. This is just a very little bit faster method to replace one file by another file with the advantage that Folder.jpg must not exist at all for success without displaying an error message as done by command DEL on file Folder.jpg not existing.
The FOR command line determines the name of the current folder without path and assigns it to environment variable FOLDER. This is a much faster and safer solution then using the command line:
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
The command line above results in starting in background one more command process with %ComSpec% /c and the command line between ' appended as additional arguments. So there is executed in background with Windows installed to C:\Windows:
C:\Windows\System32\cmd.exe /c cd
The started cmd.exe executes internal command cd which outputs the full qualified folder name of current directory to handle STDOUT of background command process. This output is captured by cmd.exe processing the batch file and is processed by for after started cmd.exe closed itself after finishing execution of command CD.
The command FOR would split up the folder path into substrings (tokens) using normal space and horizontal tab as string delimiters, would look next if the first space/tab delimited string starts with a semicolon in which case the captured line would be ignored for further processing, and would assign otherwise just the first space/tab delimited string to loop variable i. So if the full qualified folder name of current directory would contain a space, this command line would fail to determine the folder name of current directory without path.
There is the dynamic variable CD of which value can be referenced with %CD%. The value is the full qualified folder name of current directory not ending with a backslash, except the root directory of a drive is the current directory. That would be identical to %~dp0 for batch file aGallery-dl.bat with the difference that %~dp0 expands to full qualified name of batch file folder always with a backslash at end.
However, neither dynamic variable CD nor %~dp0 nor execution of command CD in a separate command process in background are really useful to get name of current directory (= batch file directory) without path. The best method is using:
for %%I in (.) do set "FOLDER=%%~nxI"
This simple FOR does nothing else than getting name of current folder without path with a very fast executed file system query and assigning it to environment variable FOLDER.
Note: for %%I in ("%~dp0.") do set "FOLDER=%%~nxI" could be also used to get folder name without path of folder containing currently executed batch file if the current directory would not be the batch file directory.
The sixth command line executes gallery-dl.exe with various parameters (arguments).
Please note that "https://www.deviantart.com/"%FOLDER%"/gallery/all" is in real an invalid argument string. It is not valid to have " inside a URL. The character " is never valid inside an argument string which references a file or folder. This syntax error is detected and automatically fixed which is the reason why the command line in your batch file works at all. The correct argument string is "https://www.deviantart.com/%FOLDER%/gallery/all" with one " at beginning and one " at end and no double quote inside the argument string enclosed in double quotes.
There is standard for console applications to exit with value 0 on success and a greater value like 1 on an error. I don't know if this is true also for gallery-dl.exe, but I assume that with the command line:
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
if not errorlevel 1 checks if exit code of gallery-dl.exe assigned to dynamic variable errorlevel is NOT greater or equal 1 which means less than 1 which means equal 0 (on executable never exiting with a negative value which is not recommended to do by a program on any operating system) which means no error occurred during execution of gallery-dl.exe. Please read the documentation of gallery-dl.exe regarding to exit codes of this program or find it out with several executions in a command prompt window and using echo Exit code is: %errorlevel% after each execution of gallery-dl.exe with success or an error (like a wrong URL).
That condition should be already enough. But there is used one more condition to check for existence of the file zzzGDB.sqlite3 in current directory only before deleting the file Folder.jpg in the current directory which is the batch file directory.
Please read issue 2 in this answer for the reason writing in batch file
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
instead of
if not errorlevel 1 (
if exist "zzzGDB.sqlite3" (
del "Folder.jpg"
)
)
The code above works also, but requires more CPU cycles for being processed by Windows command processor than the single line with two IF commands and one DEL command on one command line.
The last but one line pops the full qualified folder name of initial current directory from stack and sets it again as current directory and the last line restores initial execution environment on starting the batch file.
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 /?... explains %~dp0 ... drive and path of argument 0 ... full batch file path.
del /?
echo /?
endlocal /?
exit /?
for /?
move /?
popd /?
pushd /?
set /?
setlocal /?

How to change the code of a batch file so that it can be executed from a network resource instead of root of a drive?

I need that code to run directly from the computer (shared network folder) and not from a USB drive which is mandatory as it can be seen in the code.
set pathToScript=%~d0
set pathToRessources=%~d0\Resources
set pathToGPO=%~d0\TemplateGPO
cscript //B "%windir%\system32\slmgr.vbs" /ato
mkdir "%WINDIR%\display"
How to change the code of this batch file so that it can be executed from a directory on a network resource instead of root of a drive?
The batch file must be run from root of a drive because of the command lines:
set pathToScript=%~d0
set pathToRessources=%~d0\Resources
set pathToGPO=%~d0\TemplateGP
Those three lines should be changed to:
set "pathToScript=%~dp0"
set "pathToRessources=%~dp0Resources"
set "pathToGPO=%~dp0TemplateGPO"
Then the batch files can be successfully executed from any directory of a local drive. But the batch file would still fail to execute successfully from a directory of a network resource accessed using a UNC path because of the command line:
cd /d "%pathToScript%"
Windows prevents by default that a directory on a network resource accessed with a UNC path is set as current directory for compatibility reasons for executables not supporting that the current directory is a directory of which path does not start with a drive letter and a colon. The solution is using pushd and popd instead of cd.
The modified batch file which can be executed from really any directory with local administrative privileges:
#echo off
rem RUN AS ADMIN
setlocal EnableExtensions DisableDelayedExpansion
set "pathToScript=%~dp0"
set "pathToRessources=%~dp0Resources"
set "pathToGPO=%~dp0TemplateGPO"
%SystemRoot%\System32\cscript.exe //B "%SystemRoot%\System32\slmgr.vbs" /ato
mkdir "%SystemRoot%\display"
copy /y "%pathToRessources%\Teneris-Background-Bilingual.jpg" "%PUBLIC%\Pictures\"
copy /y "%pathToRessources%\ssText3d.scr" "%PUBLIC%\Pictures\"
copy /y "%pathToRessources%\Teneris-Lock-Bilingual.jpg" "%SystemRoot%\display"
pushd "%pathToScript%"
lgpo.exe /g "%pathToGPO%\{A213BE3C-CA6C-4F72-9235-FC52719EB79F}"
popd
endlocal
%SystemRoot%\System32\shutdown.exe /r /t 15 /c "post config shutdown in less than 30 sec"
The three lines
pushd "%pathToScript%"
lgpo.exe /g "%pathToGPO%\{A213BE3C-CA6C-4F72-9235-FC52719EB79F}"
popd
can be perhaps changed to just
"%pathToScript%lgpo.exe" /g "%pathToGPO%\{A213BE3C-CA6C-4F72-9235-FC52719EB79F}"
if the executable lgpo.exe can be executed also from a directory different to its storage location which would make the batch file faster and would be also better if the batch file is executed using a group policy or a scheduled task.
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 /? ... explains %~d0 which references the drive of argument 0, i.e. the drive on which batch file is stored respectively the network resource on starting the batch file using a UNC path and %~dp0 which references drive and path of argument 0 which is the full qualified path of the batch file always ending with a backslash.
cscript /?
echo /?
endlocal /?
mkdir /?
popd /?
pushd /?
rem /?
set /?
setlocal /?
shutdown /?
I don't know if lgpo.exe supports also executing it with /? as parameter to get displayed the help of this application.

Why are commands in batch script "not recognized" which are executed manually fine?

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
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
the Microsoft TechNet article Using command redirection operators,
the Microsoft support article Testing for a Specific Error Level in Batch Files,
the answer on change directory command cd ..not working in batch file after npm install and the answers referenced there for understanding how setlocal and endlocal really work and
the answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? for understanding why using set "variable=value".
And last take a look on:
SS64.com - A-Z index of the Windows CMD command line
Microsoft's command-line reference
Windows Environment Variables (Wikipedia article)
The administrator of a Windows server should twist everything written here and on the referenced pages round one's little finger.

Resources