Hi SAS Users,
I read a lot differently on the topic "how to hide SAS macro source code". Examples can be found here, or here. Every article recommends using the SECURE clause. However, I can still show the source code by doing the following:
%MACRO COMPMAC1(PARAMETER) / STORE SECURE;
DATA TEST;
VAR="&PARAMETER ";
RUN;
PROC PRINT DATA=TEST;
RUN;
%MEND;
OPTIONS MPRINT ;
DATA _NULL_;
MACRO='%COMPMAC1(AMADEUS);';
CALL EXECUTE(MACRO);
RUN;
I checked the log and found it:
So my question is how to effectively hide SAS macro source code?
Great Idea. Use PROC PRINTTO to suppress print code.
%macro secure(val)/secure; filename x DUMMY; proc printto log=x new;run; data T; X="&val"; putlog "This data step was generated from a secure macro with value &val.."; run; proc print data=sashelp.class;run; proc printto;run; %mend secure; options MPRINT MLOGIC SYMBOLGEN SOURCE SOURCE2; data _null_; call execute('%secure(Q)'); run;
What your log is showing is NOT the macro code. It is the SAS code that the macro generated. Two different things.
To stop SAS from showing the code that a macro is generating turn off the MPRINT option.
But the real question is WHY would you want to hide your source code? What problem does that solve? I cannot think of any. But it does introduce a lot of potential problems because now no one can tell if what the macro is doing is what they actually need or want to happen.
Simple, You can find the answer here:
There are, however, a number of macros that are unique to the company, which required many hours to create and perfect so that they can run either
for a number of situations/studies or are built for a very specific process. These macros are held close to the chest and generally are not shared with all clients
Have you considered using compiled macros and just distributing the compiled version? You can distribute the compiled macro without source code.
I suspect you will need to be very careful to ensure your macro only contains dynamic macro variable values that get resolved only at run time and not at compile time.
@ThaoLinh wrote:
Simple, You can find the answer here:
There are, however, a number of macros that are unique to the company, which required many hours to create and perfect so that they can run either
for a number of situations/studies or are built for a very specific process. These macros are held close to the chest and generally are not shared with all clients
I would make sure you run any process you apply this idea to with your CONTRACTS people for each client. The wording of your contract with the client might very well prohibit such obfuscation.
Catalogs are "host specific", your catalog created under Windows OS won't run under Lunux.
To hide SAS code, add
options nomprint; as the first line.
Don't forget to restore to option to its previous status at the end.
Compiling macros into the mstore as secure will prevent anyone to access your macro source code or get any macro execution information written to the SAS log (mprint, symbolgen, mlogic). It doesn't prevent users from seeing the SAS code the macro generates.
Option NOSOURCE would prevent SAS to write the generated SAS code to the SAS Log BUT.... when using the macro with call execute() then the SAS code first gets generated and only executed when the data step ended - and for this reason option nosource set within the macro executes too late (timing).
I could think about ways to obfuscate things a bit further (adding complexity though) but I can't think about a real solution.
It's may-be worth to contact SAS Tech Support asking if there is a way (I doubt it but who knows).
Also, I changed your thread title as your misunderstanding what option SECURE does is not the same as the option being useless.
Hello @ThaoLinh
If your code involves data steps only you can consider using compiled data step programs. Further details can be had here https://documentation.sas.com/doc/en/pgmsascdc/v_014/engsas7bdat/n1h8ok8rj6uzqkn18tpnp1lb4lp9.htm
@Ksharp The challenge is that the the OP would provide your macro X precompiled and doesn't want the user to be able to see the SAS code it generates.
The OP has no control over option settings outside of the macro ....and if the user uses the macro via call execute() then any option set within the macro come "too late".
The OP doesn't mention call execute, but good call @Patrick .
Here's a (not very satisfactory) few lines to add at the top of the secure macro to avoid anything being shown in the log.
%macro secure(val)/secure;
%local opt;
%let opt=%sysfunc(getoption(mprint)) %sysfunc(getoption(mlogic)) %sysfunc(getoption(symbolgen)) %sysfunc(getoption(source)) %sysfunc(getoption(source2));
%if &opt ne NOMPRINT NOMLOGIC NOSYMBOLGEN NOSOURCE NOSOURCE2 %then %do;
options nomprint nomlogic nosymbolgen nosource nosource2;
%secure(&val)
%return;
%end;
data T;
X="&val";
putlog "This data step was generated from a secure macro with value &val..";
run;
options &opt. ;
%mend secure;
options mprint mlogic symbolgen source source2;
%secure(A)
options mprint mlogic symbolgen source source2;
data _null_;
call execute('%nrstr(%secure(B))');
run;
with this displayed in the log:
44 %secure(A) This data step was generated from a secure macro with value A. NOTE: The data set WORK.T has 1 observations and 1 variables. NOTE: DATA statement used (Total process time): real time 0.01 seconds user cpu time 0.00 seconds 47 data _null_; 48 call execute('%nrstr(%secure(B))'); 49 run; NOTE: DATA statement used (Total process time): real time 0.00 seconds user cpu time 0.00 seconds NOTE: CALL EXECUTE generated line. 1 + %secure(B) This data step was generated from a secure macro with value B. NOTE: The data set WORK.T has 1 observations and 1 variables. NOTE: DATA statement used (Total process time): real time 0.01 seconds user cpu time 0.00 seconds
I am sure there is a lot of room to improve this.
I've never been in the business of hiding macro code (or SAS code), but depending on what the macro is doing, I guess DOSUBL might help.
Within a DOSUBL block, you can use PROC PRINTTO to turn off the log in the side session, and that should prevent any code or messages from being shown.
Not advocating this, as I'm a big fan of automated log scanning so the idea of turning off the log chills me to the core of my bones.
But it's a helpful benefit of DOSUBL that the timing works out, even when called by CALL EXECUTE. Depending on the level of code hiding needed, you might not need to completely turn off the log.
%macro secure(val)/secure;
%let rc=%sysfunc(dosubl(%nrstr(
proc printto log="NUL" ;
run ;
data T;
X="&val";
putlog "This data step was generated from a secure macro with value &val..";
run;
))) ;
%mend secure;
data _null_;
call execute('%secure(Q)');
run;
Save $250 on SAS Innovate and get a free advance copy of the new SAS For Dummies book! Use the code "SASforDummies" to register. Don't miss out, May 6-9, in Orlando, Florida.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.