I am currently facing the issue that I want to implement a PHP script that starts a batch file on a remote server.
After hours of ideas the nearest I came to the solution was a batch file on a local server which could be started by the PHP script. However, the batch file somehow does not start the remote batch file when started via PHP script.
If the batch file c:directoryappssubclassesactionstest.bat
is started locally with a double click, the remote batch file c:directorysubtest.bat
is executed without a problem by PsExec
.
The permissions are granted as needed.
I am using the following code in PHP to start the first batch file:
$cmd = '"c:\directoryapps\sub\classes\actions\test.bat"'; exec('cmd /c '.$cmd.' &');
The code of that batch file is as followed:
"C:/Windows/System32/SysinternalsSuite/PsExec.exe" \server -i -u **** -p **** c:\directory\sub\test.bat
How do I implement a working version of this?
I have also tried to run the first batch file code from within PHP script with even less success.
Advertisement
Answer
The main problem is the decision to install the Sysinternals Suite into a subdirectory of %SystemRoot%System32
. That was no good decision and cause the issue here.
The directory %SystemRoot%System32
is for 64-bit applications executed in 64-bit environment on 64-bit Windows.
The usage of %SystemRoot%System32
, which is usually expanded to C:WindowsSystem32
, in 32-bit environment results in a redirection by Windows File System Redirector to %SystemRoot%SysWOW64
respectively expanded C:WindowsSysWOW64
.
%SystemRoot%SysWOW64
contains the 32-bit system executables, but not the directory SysinternalsSuite
with file PsExec.exe
.
python.exe
is a 32-bit executable. For that reason is started with just cmd
in the Python script %SystemRoot%SysWOW64cmd.exe
which is the 32-bit version of Windows command processor. 32-bit cmd
fails to find C:WindowsSysWOW64SysinternalsSuitePsExec.exe
and so psexec.exe
is not executed at all.
Well, starting cmd.exe
to run a batch file which contains only one command line to run psexec.exe
with wrong path for 32-bit environment is not needed at all.
It would be enough to use in Python script:
$args = '\\server -i -u "****" -p "****" "C:\directory\sub\test.bat"'; exec('C:\Windows\Sysnative\SysinternalsSuite\PsExec.exe '.$args.);
32-bit python.exe
runs with this code the 32-bit executable PsExec.exe
in subdirectory SysinternalsSuite
of 64-bit Windows system directory with the appropriate arguments.
The special redirecting Sysnative
exists only for 32-bit applications executed in 32-bit environment. Please note that Sysnative
is neither a directory nor a symbolic link or hard link. The file system does not contain an entry Sysnative
in directory C:Windows
. For that reason it is not possible to use in a batch file if exist %SystemRoot%Sysnative
or if exist %SystemRoot%Sysnative
as both conditions evaluate always to false. But if exist %SystemRoot%Sysnativecmd.exe
can be used in a batch file to find out if the batch file is processed by 32-bit Windows command processor on a 64-bit Windows because of the condition evaluates to true in this use case.
I recommend reading also the Microsoft documentation pages WOW64 Implementation Details and Registry Keys Affected by WOW64 to get knowledge on how 32-bit Windows emulation works on 64-bit Windows.
A minor issue is appending &
at end of the Windows command line. An ampersand at end of a shell script line is interpreted only by Unix/Linux/Mac shell script interpreters as instruction to run the executable detached in background. So the shell script interpreter does not wait for termination of the started executable before continuation of the script or before the user can enter the next command to execute.
Windows command processor cmd.exe
interprets an ampersand outside a double quoted argument string as AND operator usually used to specify multiple commands on one command line, see single line with multiple commands using Windows batch file. If there is after &
nothing on a command line interpreted by cmd.exe
, the Windows command processor ignores the AND operator.
Therefore do not append &
on a Windows command line.
There are two more minor issues in the batch file on command line:
"C:/Windows/System32/SysinternalsSuite/PsExec.exe" \server -i -u **** -p **** c:\directory\sub\test.bat
The directory separator on Windows is and not
/
as explained by Microsoft on documentation page Naming Files, Paths, and Namespaces. The Windows kernel replaces by default all /
by in a file/folder string before passing the string to the appropriate file system function. But the usage of Linux/Mac directory separator
/
can nevertheless result in unexpected behavior.
Example:
Run in a Windows command prompt window:
for %I in (C:/Windows/*.exe) do @echo %I
The found executables in Windows directory are output with C:
and the file name without path. So assigned to loop variable I
is a string which references an executable file in current directory of drive C:
. But the current directory on drive C:
on execution of this command line is most likely not C:Windows
which would cause issues on really processing the file name assigned to loop variable I
instead of just printing it to console window.
Run in same command prompt window now:
for %I in (C:Windows*.exe) do @echo %I
The same file names are output as before, but this time with full path.
Conclusion: Do not use /
in file/folder strings on Windows and depend on automatic correction of Windows kernel. /
is used on Windows mainly for beginning of an option.
The usage of \
in a batch file between two directory names and between a directory name and a file name is also always wrong and must be corrected by Windows kernel before passing the file/folder name string to the file system by removing one backslash. \
is valid only at beginning of a UNC path.