SAS Error Handling in Windows Batch - sas

I have a scheduled SAS program in Windows, e.g.
sas.exe -nosplash -icon -sysin "myprogram.sas"
This process will hang if there's an "Out of Resources" error (e.g. no disk space), prompting for user input (Retry, Cancel, etc.). As it's a batch job, there is no user to give that input.
Is there a SAS system option which prevents the prompt for user input so it can be dealt with in the code itself?

How about -noterminal?
Extract from documentation:
If NOTERMINAL is specified, dialog boxes are not displayed.

Trying using the option
-batch
Since you are running in batch mode, also consider using the option
-errorabend
The best option is
-get_more_resources ;)
If the program is the cause to the resource error you have another question to ask!

Related

Start .exe file and automatically "press enter for "Save"" in SAS

I have a SAS program I would like to schedule, so we don't have to run it manually.
In the program we call an excecutable (reg.exe), like this:
X CALL "K:\reg.exe";
The executable opens a standard windows save-dialog and all we need to do is press save, which will save an xml-file. The save-dialog already opens in the correct directory.
What I would like is to somehow pass the instruction on, using code, to "press save", so the program can move on and work with the saved xml-file.
Is this possible somehow?
Thanks for your help!
Thomas:
There are numerous Windows utilities for scripted control of an interactive program. For example: AutoIt (my favorite), MouseRobot and AutoHotKey to name a few.
The statement
options xmin noxwait noxsync;
will cause the external program to run, not wait for the command session to exit, and not wait for the command to complete.
If your SAS programs needs to wait for the side effects of the scripting use of reg.exe to occur before occurring, use:
options xmin noxwait xsync;
These settings affect other operating system interfacing features, such as:
X command
CALL SYSTEM routine
%SYSEXEC statement
The use of your reg.exe might require your login to have admin rights.
The SYSTASK statement can also run external commands.
If you find that you are unable to run external commands, it is probably because the system setting NOXCMD is active. This setting is on by default in SAS server environments.

How to print SAS program log to console when running in batch mode

I am running my SAS program in batch mode through windows command prompt.
Start /WAIT "SAS_job" "C:\Program Files\SASHome\SASFoundation\9.4\sas.exe" -sysin D:\MySAS_Test.sas -nosplash -nologo -noicon
Can I display the SAS output or log on command prompt instead of writing to a file? Or print log as SAS program is running to track progress.
I think this is possible in Unix, but I'm not so sure about Windows.
You can write to STDOUT in Unix as mentioned in the documentation. But I don't see any such similar thing in Windows.
The most similar thing is unnamed pipes, which lets you interact with the console - but it's unclear if this is potentially helpful for you or not.
Unfortunately, I suspect SAS is generally not considering Windows a server type environment, and mostly supporting it to allow for desktop use; while it does support Windows servers certainly, most SAS server usage is Linux/Unix.
Your better bet is probably to go in the direction of another program that reads from the log file already produced and writes it out to the console, something analagous to tail in Unix. Or as mentioned in comments open the log in a text editor (you can even 'push' this from SAS if you have option xcmd enabled) and let it auto-refresh periodically.
One common use case in fact is to use, for example, UltraEdit to edit your SAS programs; it can even run them in batch directly, and then retrieve the log in that program.

Terminate whole process flow instead of single program

Is there a way to stop the process if certain criteria in any of the programs in this process is met?
I have a process consist of 5 SAS programs. This process is scheduled to run at 8am every morning. However, sometimes the database is not refreshed and this process will send out weird figures.
I need to have "exception control".. In 2nd program I check the database with some criteria. If no error, then keep running the rest of the code. Otherwise, send out an notification email and STOP running the 2nd program and all the subsequent programs.
I try %abort cancel but it only terminate the current program. The subsequent programs are not affected.. I can do checking in every single program but that make the code redundant...
I also try google "terminate SAS process" but most of them refer to abort statements which doesn't help...
If you're using Enterprise Guide, this is built into the program via logic gates.
First, in the program that determines whether the database file passed/failed ("gate program"), assign a macro variable a value based on that test. Presumably this program will do only things you're happy for it to do even if it fails.
On the process flow page, you right click on the program that determines if the database file passed/failed, and select 'Condition -> Add'.
Then add a condition based on a Macro Variable, and use 'equals' and the value you're looking for (or 'greater than' or whatever makes sense). Then select the next task after "Then run this task"; and put the other option after Else run this task.
Then, whichever of the two is forward-moving, should then have links to the rest of the programs you want run; the one that's not should end the process.
SAS gives an example of how to do that in KB Sample 39995 including a sample project you can download.
Second, you can set OBS=0 if you reach the error condition. This will let SAS continue working, but it in most cases won't be able to do anything (since OBS=0, then it can only affect 0 records of any dataset). I'm not sure that's a guarantee that it won't do anything, but in everything I've done that's been sufficient. I also have used OPTIONS ERRORABEND which works fine if you do all of your processing with external libnames which won't automatically reconnect when SAS is reconnected.
My understanding is that this is a batch process. You don't specify Operating System you are running your process on. Let's suppose you are running it on UNIX/Linux (I am hoping it is similar on Windows). Let's assume that your 5-programm process is run by the following shell script:
sas /program1.sas
sas /program2.sas
sas /program3.sas
sas /program4.sas
sas /program5.sas
If you want to stop your remaining process after program2.sas completes with ERRORs or WARNINGs you can modify your script to be
sas /program1.sas
sas /program2.sas
if [ $? -ne 0 ]
then
exit
fi
sas /program3.sas
sas /program4.sas
sas /program5.sas
In this script code a special shell script variable $? status code is passed from the previous command from SAS (0 means successful completion). If it is not 0 then the whole script stops due to the exit command.
For more information and code examples see How to conditionally terminate a SAS batch flow process in UNIX/Linux SAS blog post.

Using the console in a GUI app in windows, only if its run from a console

My application is a GUI app that has helpful (though optional) information through the terminal (via cout).
In Windows I either have a console appear (by compiling as a console app, or allocating it dynamically) or I don't.
My intention is to make use of the console IF it is being run from the console, but ignore the console completely if it was not. (Essentially what happens in Linux and OS X).
I do not wish to redirect to a file (and in the case of using cin, this is not a viable solution anyway).
Is there a way to attach a GUI app in Windows to the console it is run from, if and only if it is run from a console?
and in the case of using cin, this is not a viable solution anyway
This is the killer detail in your question. It is simple on paper, just first call AttachConsole(ATTACH_PARENT_PROCESS) to try to attach to an existing console. That will fail when your program got started from a GUI program like Explorer or a desktop shortcut. So if it returns FALSE then call AllocConsole() to create your own console.
Using cin is a problem however. The command processor pays attention to your EXE and checks if it is console mode app or a GUI app. It will detect a GUI app in your case and then doesn't wait for the process to complete. It displays the prompt again and waits for input. You will then also wait for input but you'll lose, the command processor got there first. Your output is also intermingled with the command prompt, the easy problem to solve.
There's a simple workaround for that, your user should start your program with start /wait yourapp to tell the command processor to wait for the process to complete. Problem is: nobody ever uses that. And the user will not realize what happens when they type input, intending it to go into your program but it is actually interpreted by the command processor. Producing a mystifying error message or formatting the hard drive.
Only two good ways to solve this unsolvable problem. Either build your program as a console mode app and call FreeConsole() when you find out you want to display a GUI. Or always call AllocConsole(). These are not great alternatives. The first approach is the one used by the Java JVM on Windows. One of the oldest bugs filed against the JVM and driving Java programmers completely batty from the flashing console window.
The third alternative is the only decent one, and the one you don't want, create another EXE that will always use the console. Like Java does, javaw.exe vs java.exe.
A trick is possible, you can rename that file from "yourapp2.exe" to "yourapp.com". It will be picked first when the user types "yourapp" at the command line prompt, a desktop shortcut can still point to "yourapp.exe". Visual Studio uses this trick, devenv.com vs devenv.exe.
You can check CONSOLE_SCREEN_BUFFER_INFO (via GetConsoleScreenBufferInfo) on startup to determine if you've been run from within an existing console. If the buffer's position is 0,0, you were run from outside of the console. For details, see this Microsoft Knowledgebase Article which describes the process.
In order for this to work, you need to compile your application as a console application (using /SUBSYSTEM:CONSOLE), and then detach yourself from the console if the application started a new console (buffer at 0,0). This will cause the program to properly "attach" to the calling console when launched from a command line.
As others have pointed out you have to create a console app and a window app. So, you'd end up with console.exe and app.exe. To make it less obvious at the command-line, you can take advantage of the PATHEXT trick like devenv does. cmd.exe treats a file as a command if its extension is in the PATHEXT environment variable. COM is there by default so you could rename console.exe as app.com, allowing the command app to start the console app attached to the current console.
Note: Of course, a console app can show a GUI if desired.
The difference in the build between app.com and app.exe depends on your build system but it could just be the one attribute that sets the output type. With msbuild (for .vcxproj files), it's just a matter of another build configuration.
you can create an application in console that get a line using argc and prints it;
////
int main(int argc, char *argv[])
{
//here print argv....using cout or printf
}
save the file as console.exe in the folder of your app.
now in your app if you want to see any line in console you can call the command
system("console.exe this is the line i want to print and see in console");

I want to hide system commands issued from system()

Writing a program in c++ and I want to issue a system command from the system() function but I don't want the user to see the command (because the command includes a pwd) in the executable window. I need to copy a file from the user's directory onto the server without allowing user access to the server or displaying the pwd. Figured having a .exe that does this is the easiest way.
Ex:
system("FILETRANSFER_SW.exe -pw helloWORLD11!# C:/temp.txt F:/tempfolder/")
But the executable window is showing this command, hence defeating the purpose of trying to hide the password.
I tried issuing
system("#echo OFF")
at the beginning of the program but that does not suppress the following commands, they still show up in the executable window.
Any suggestions?
Thanks...
The command line of running processes is considered public information in most operating systems.
Therefore it is a very bad idea to pass passwords on the command line.
There are two common workarounds to this problem, both of which require the support of the executable being called:
instead of passing the username/password on the command line, pass the name of a file containing the username/password
re-set the command line of the running process from within the called executable.
The first solution is easy and universally possible, the second one has a race condition and is harder to implement, because there's no cross-platform way to do it (on some OSes, changing argv will help).
I'm assuming from your command line that you're using Windows. If it doesn't need to be portable I would suggest you use the CreateProcess() API instead of calling system().
The CreateProcess() API can take a command-line and you can set up the STARTUP_INFORMATION parameter to hide the new process window (wShowWindow = SW_HIDE).
The command line will be hidden from the casual user, but as others have pointed out, it's not that hard to retrieve. Since you are creating a new process, I would suggest writing the sensitive data to that process' standard input. That way the process can just read it and proceed normally.
Using CreateProcess() API will hide the sensitive data from a user, but a power user can easily get the command line associated with the process using a free utilty, e.g. Process Explorer
Another solution is to send the password between your programs, encrypted with something like 3DES, or AES.
You could use a pipe to comunicate between both programs, and don't use the command line at all.
But any of this schemes is not really secure they can be circumvent rather easily. If you want more security you should use some kind of challenge-response protocol with the server.