Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

VFP9 to run external command as admin and capture exit code, WScript, ShellExecute 1

USMA99

Programmer
Oct 12, 2000
85
US
Hello Foxpro Friends,

I'm looking to build a robocopy command, run it from VFP9, and pick up the exit code to be sure it completed successfully. I'm a local administrator on my box, and the source and destination directories are on the same local drive, but nevertheless, the command will fail with the message:
You do not have the Backup and Restore Files user rights.
This error is because windows loses the admin privileges when running the robocopy command and then can no longer run a backup function on the destination. This also happens when I manually create and run a batch file, or if I run the robocopy command directly from the windows command line. (I found many others online with this issue working outside of a foxpro context.)

To get around this, I created a shortcut to a batchfile, checked Run As Administrator, and then ran that with ShellExecute. While not ideal, this runs successfully when run by double clicking the shortcut, or even from Shellexecute in VFP. Eventually I found a relatively new parameter "runas" which allows me to call the batch file directly from VFP, and successfully execute the batch file with elevated privileges. So far, so good.

The problem is that I'm using ShellExecute and I can find no way to pick up the exit code. That ShellExecute cannot do this was confirmed in thread 1791486. From that I've attempted to use Wscript instead. While I can get Wscript to run the batch file, and return an exit code, it is again unfortunately losing admin rights and unable to execute the robocopy command.

This successfully builds the batch file:

Code:
cCMD = "robocopy D:\TEMP\ D:\TEST_CMD\TEMP\ /E /mir /R:5 /W:15 /MT:16 /COPYALL /ZB /COPY:DAT /log+:D:\TEST_CMD\CMD_Log.txt /NP /NFL /NDL /FP /XD 0RETREIVED"
STRTOFILE(cCmd,"TEST.BAT")



This successfully executes the robocopy batch file (but cannot provide an exit code):

Code:
objShell = CreateObject("Shell.Application")
    objShell.ShellExecute("D:\TEST_CMD\Test.bat", "", "", "runas", 0)


This also runs the robocopy batch file, but only after losing administrative priviliges, and so the robocopy command fails. It does, however, provide a return code (though I cannot yet confirm it is correct):


Code:
LOCAL oShell, lErrCode
oShell = CREATEOBJECT("wscript.Shell")
pCmd =  '"D:\TEST_CMD\Test.bat", "", "", "runas", 0'
lErrCode = oShell.Run(pCmd, 1, .T.)
oShell = null
RELEASE oShell
MESSAGEBOX(lErrCode)


On another forum I did see someone renaming a copy of wscript.exe inside of System32 and then setting that to run with elevated privileges. This seems like a plausible way to get the second approach to work, though I wasn't able to pull it off personally.

It would seem that these two semi-working objects I have could be combined somehow, but I'm just too far out of my depth. Is there a way to combine these two approaches or otherwise achieve my end-goal?

Thanks in Advance
 
I am not sure of the technicalities, but I *think* the result in the errorcode is 'private' to the scope of the batch file, so you can't
read it in the shellexecute. You need to make a semaphore of some kind that the calling program can read. Drop the errorcode
into a simple file that the vfp code can read?
 
Code:
MkDir c:\testdir
Cd c:\testdir
StrToFile("world","hello.txt")
Cd..
MkDir c:\testdircopy
cCMD = "Robocopy c:\testdir c:\testdircopy"
Cd GetEnv("TEMP")
STRTOFILE(cCmd,"test.cmd")

oWSH = CreateObject("Wscript.Shell")
oExec = oWSH.Exec(GetEnv("TEMP")+"\test.cmd")
? oExec.StdOut.ReadAll()
? "------ ^^^ stdout output ^^^ ------ vvv stdErr output vvv ------"
? oExec.StdErr.ReadAll()
? "------ vvv Exitcode vvv ------"
? oExec.ExitCode

If you get problems in robocopy, they usually show up in stdout, so Exitcode 0 may not mean no problems. But trying to copy from a non existing directory the exitcode is 16, for example. For sake of problem analysis it might still be a good idea to store the stdout output on top of stderr and exitcode.
 
The only reply that ShellExecute() returns to the calling program is a code that indicates an error in ShellExecute() itself, such as passing it an invalid filename or an invalid action parameter. If there is no error, it returns the handle of the main window of the called application.

What ShellExecute() does not return is any reply from the called application. One reason for that is that the process is modeless. After the call to ShellExecute(), the calling program continues to run, so that is no opportunity for it to communicate with the called application.

Better to use some other method for your robocopy.

Mike
 
I am not sure of the technicalities, but I *think* the result in the errorcode is 'private' to the scope of the batch file, so you can't
read it in the shellexecute. You need to make a semaphore of some kind that the calling program can read. Drop the errorcode
into a simple file that the vfp code can read?
Yes, thanks, I could redirect the errorlevel variable to a file and read that back in to see how it went.
 
Code:
MkDir c:\testdir
Cd c:\testdir
StrToFile("world","hello.txt")
Cd..
MkDir c:\testdircopy
cCMD = "Robocopy c:\testdir c:\testdircopy"
Cd GetEnv("TEMP")
STRTOFILE(cCmd,"test.cmd")

oWSH = CreateObject("Wscript.Shell")
oExec = oWSH.Exec(GetEnv("TEMP")+"\test.cmd")
? oExec.StdOut.ReadAll()
? "------ ^^^ stdout output ^^^ ------ vvv stdErr output vvv ------"
? oExec.StdErr.ReadAll()
? "------ vvv Exitcode vvv ------"
? oExec.ExitCode

If you get problems in robocopy, they usually show up in stdout, so Exitcode 0 may not mean no problems. But trying to copy from a non existing directory the exitcode is 16, for example. For sake of problem analysis it might still be a good idea to store the stdout output on top of stderr and exitcode.
Very good, this does the trick, many thanks
 

Part and Inventory Search

Sponsor

Back
Top