BookmarkSubscribeRSS Feed
sid_sas
Calcite | Level 5

Hi All,

I am wondering how to loop through all datsets in a sas folder (using LIBREF or any other method) and password protect (write and alter) all the datsets.

The functionality should automatically do this for all  the datasets in the folder WITHOUT having the need to specify individual dataset names.

Any help would be greatly appreiciated !

Thanks,

Sid.

6 REPLIES 6
art297
Opal | Level 21

What kind of operating system are you on and do you just want to apply SAS passwords or do it at the operating system level?

Getting the files is simple using a pipe and the next step will depend upon what level security you wish to apply.

sid_sas
Calcite | Level 5

I am on Windows XP . I just want to apply passwords for now.

Could you breif about the "level of security "?

I am just trying to build a macro/datastep which applies passwords (write and alter) to all the sas datsets in a folder.

Thank in advance!

art297
Opal | Level 21

Do you want separate passwords for each file or just one password for the folder?  That was principally what I was considering in using the descriptive "levels".  As far as I know, read, write and alter are the only three possibilities regardless of whether you use dos or SAS file security.

A brief description of adding passwords in SAS can be found at: http://support.sas.com/documentation/cdl/en/lrcon/62955/HTML/default/viewer.htm#a000995315.htm

ScottBass
Rhodochrosite | Level 12

Below is a %loop macro which executes a sub-macro for each token in a list.  It calls %parmv, which is a parameter validation macro.

Below that is code which does what you want.

I recommend adding %loop and %parmv to your macro autocall library.  I use %loop all the time.

Sorry for the long post. 

HTH...

/*=====================================================================

Program Name            : loop.sas

Purpose                 : A "wrapper" macro to execute code over a

                          list of items

SAS Version             : SAS 8.2

Input Data              : N/A

Output Data             : N/A

Macros Called           : parmv

Originally Written by   : Scott Bass

Date                    : 24APR2006

Program Version #       : 1.0

=======================================================================

Modification History    :

Programmer              : Scott Bass

Date                    : 17JUL2006

Change/reason           : Added DLM parameter

Program Version #       : 1.1

Programmer              : Scott Bass

Date                    : 24DEC2009

Change/reason           : Made changes as suggested by Ian Whitlock,

                          updated header with additional usage cases

Program Version #       : 1.2

Programmer              : Scott Bass

Date                    : 13MAY2011

Change/reason           : Fixed nested macro scoping errors by explicitly

                          declaring the iterator and word as local.

Program Version #       : 1.3

=====================================================================*/

/*---------------------------------------------------------------------

Usage:

%macro code;

   %put &word;

%mend;

%loop(Hello World);

=======================================================================

%let str = Hello,World;

%loop(%bquote(&str),dlm=%bquote(,));

=======================================================================

%macro code();

   %put &word;

%mend;

%loop(Hello World,mname=code());

=======================================================================

%macro mymacro;

   proc print data=&word;

   run;

%mend;

proc datasets kill nowarn nolist;

quit;

data one;x=1;run;

data two;y=2;run;

proc sql noprint;

   select memname into :list separated by '|'

      from dictionary.tables

      where libname = "WORK" and memtype = "DATA"

   ;

quit;

%loop(&list,dlm=|,mname=mymacro);

=======================================================================

Calling a macro with parameters:

%macro mymacro(parm=&word);

   %put &parm;

%mend;

%loop(hello world,mname=mymacro);    * this causes a tokenization error ;

%loop(hello world,mname=mymacro());  * no error ;

%mymacro(parm=hi);

Note that the parm is the literal text '&word' (without quotes of course).

See additional details in Nested calls of %loop use case below.

=======================================================================

Nested calls of %loop:

%macro outer;

   %put &sysmacroname &__iter__ &word;

   %loop(INNER_1 INNER_2 INNER_3,mname=inner)

%mend;

%let iter_global=;

%macro inner;

   %local iter_local;

   %global iter_global;

   %if (&iter_local  eq ) %then %let iter_local=1;

   %if (&iter_global eq ) %then %let iter_global=1;

   %let iter_local=%eval(&iter_local + (&__iter__ * 5));  %* not retained across outer loops ;

   %let iter_global=%eval((&iter_global*2)+(&__iter__));  %* retained across outer loops since it is global ;

   %put &sysmacroname &__iter__ &word iter_local=&iter_local iter_global=&iter_global;

   %* let __iter__=999;  %* if uncommented, this would cause a logic error ;

%mend;

%loop(OUTER_A OUTER_B OUTER_C OUTER_D OUTER_E,mname=outer)

Do NOT reset __iter__ in any inner macro or it will affect the outer macro.

You can *REFERENCE* &__iter__, but do not *CHANGE* its value.

If you need to make logic decisions, copy &__iter__ to a local inner variable.

Also, do NOT use %yourmacro(parameter=&word) syntax in nested calls to

%loop.  For example, this will not work:

options mlogic;

%macro level1(firstvar=&word);

   %put firstvar in Level1:  &firstvar;

   %loop(Variable2, mname=level2())

%mend level1;

%macro level2(secondvar=&word);

   %put secondvar in level2: &secondvar;

   %put INCORRECT: firstvar in Level2: &firstvar;

%mend level2;

%loop(Variable1, mname=level1())

In level1, firstvar is actually assigned the literal text '&word'

(without quotes of course). Inside the level1 macro, this text then

resolves to the value of &word AT THAT TIME. Once the level2 macro

executes, it changes the value of &word, which then changes further

references to &firstvar.

Instead, assign firstvar and secondvar to the value of &word INSIDE

each macro, as described for __iter__ above.

Closely review the mlogic output above for more details.

Instead, code this as follows:

options nomlogic;

%macro level1;

   %local firstvar;

   %let firstvar=&word;

   %put &sysmacroname: firstvar in Level1:  &firstvar;

   %loop(Variable4 Variable5, mname=level2)

%mend level1;

%macro level2;

   %local secondvar;

   %let secondvar=&word;

   %put &sysmacroname: secondvar in level2: &secondvar;

   %put &sysmacroname: CORRECT: firstvar in Level2: &firstvar;

%mend level2;

%loop(Variable1 Variable2 Variable3, mname=level1)

-----------------------------------------------------------------------

Notes:

The nested macro "%code" must be created at run time before calling

this macro.

Use the macro variable "&word" within your %code macro for each token

(word) in the input list.

If your macro has any parameters (named or keyword) (even an empty

list), then specify the macro name with empty parentheses for the mname

parameter or tokenization errors will occur during macro execution. For

example, %loop(hello world,mname=mymacro());.  See examples in the

Usage section above.

If your input list has embedded blanks, specify a different dlm value.

Do not use the prefix __ (two underscores) for any macro variables in

the child macro.  This prefix is reserved for any macro variables in

this looping macro.

To "carry forward" the value of the iterator across loops, assign it

(&__iter__) to a global macro variable in an inner macro.

---------------------------------------------------------------------*/

%macro loop

/*---------------------------------------------------------------------

Invoke the nested macro "%code" over a list of space separated

list of items.

---------------------------------------------------------------------*/

(__LIST__      /* Space or character separated list of items (REQ)   */

,DLM=%str( )   /* Delimiter character (REQ).  Default is a space.    */

,MNAME=code    /* Macro name (Optional).  Default is "%code"         */

);

%local macro parmerr __iter__ word;

%let macro = &sysmacroname;

%* check input parameters ;

%parmv(MNAME,        _req=1,_words=0,_case=N)

%if (&parmerr) %then %goto quit;

%let __iter__ = 1;

%let word = %qscan(%superq(__list__),&__iter__,%superq(dlm));

%do %while (%superq(word) ne %str());

  %let word=%unquote(&word);

%&mname  /* do not indent macro call */

   %let __iter__ = %eval(&__iter__+1);

   %let word = %qscan(%superq(__list__),&__iter__,%superq(dlm));

%end;

%quit:

%mend;

/******* END OF FILE *******/

/*=====================================================================

Program Name            : parmv.sas

Purpose                 : Macro parameter validation utility.

                          Returns parmerr=1 and writes ERROR message

                          to log for parameters with invalid values.

SAS Version             : SAS 8.2

Input Data              : N/A

Output Data             : N/A

Macros Called           : None

Originally Written by   : Tom Hoffman

Date                    : 09SEP1996

Program Version #       : 1.0

=======================================================================

Modification History    :

Programmer              : Tom Hoffman

Date                    : 16MAR1998

Change/reason           : Replaced QTRIM autocall macro with QSYSFUNC

                          and TRIM in order to avoid conflict with the

                          i command line macro.

Program Version #       : 1.1

Programmer              : Tom Hoffman

Date                    : 04OCT1999

Change/reason           : Added _val=NONNEGATIVE. Converted _val=0 1 to

                          map N NO F FALSE OFF --> 0 and Y YES T TRUE

                          ON --> 1. Added _varchk parameter to support

                          variables assumed to be defined before macro

                          invocation.

Program Version #       : 1.2

Programmer              : Tom Hoffman

Date                    : 12APR00

Change/reason           : Changed the word 'parameter' in the message

                          text to 'macro variable' when _varchk=1.

                          Fixed NONNEGATIVE option.

Program Version #       : 1.3

Programmer              : Tom Hoffman

Date                    : 10JUN01

Change/reason           : Added _DEF parameter. Returned S_MSG global

                          macro variable.

Program Version #       : 1.4

=====================================================================*/

/*---------------------------------------------------------------------

Usage:

%macro test;

%local macro parmerr;

%let macro = TEST;

%parmv(INTERVAL,   _req=1,_words=1)

%parmv(IVAR,       _req=1)

%if (%length(&visit) > 7) %then

   %parmv(IVAR,    _msg=SAS name containing 7 or less characters)

;

%parmv(LZERO,      _req=1)

%parmv(UZERO,      _req=1)

%parmv(HIGH,       _req=1,_val=0 1)

%parmv(DAY,        _req=1)

%parmv(PRINT,      _req=1,_val=0 1)

%if (&parmerr) %then %goto quit;

....

%quit:

%mend test;

-----------------------------------------------------------------------

Notes:

=======================================================================

This code was developed by HOFFMAN CONSULTING as part of a FREEWARE

macro tool set.

Note:  I have received permission from Tom Hoffman to use this macro.

Scott Bass

=======================================================================

The calling macro requires two local variables, PARMERR and MACRO,

where MACRO's value equals the name of the calling macro.

Invoke macro %parmv once for each macro parameter. After the last

invocation branch to the macro's end whenever PARMERR equals 1 (e.g.,

%if (&parmerr) %then %goto quit;).

Macro %parmv can be disabled (except for changing case) by setting the

global macro variable S_PARMV to 0.

Macros using the %parmv tool may not have any parameters in common

with parmv parameters.

Use the _MSG parameter to set parmerr to 1 and issue a message based on

validation criteria within the calling program.

Note that for efficiency reasons, parmv does not validate its own

parameters. Only code valid values for the _REQ, _WORDS, _CASE, and

_VARCHK parameters.

For macros that require 'many' non-parameter macro variables that may

not be defined by the programming environment, consider using the

CHKMVARS macro rather than setting _varchk=1. Both methods will work,

but note that DICTIONARY.MACROS is opened each time that parmv is

invoked with _varchk=1.

--------------------------------------------------------------------*/

%macro parmv

/*---------------------------------------------------------------------

Macro parameter validation utility. Returns parmerr=1 and writes

ERROR message to log for parameters with invalid values.

---------------------------------------------------------------------*/

(_PARM     /* Macro parameter name (REQ)                             */

,_VAL=     /* List of valid values or POSITIVE for any positive      */

           /* integer or NONNEGATIVE for any non-negative integer.   */

           /* When _val=0 1, OFF N NO F FALSE and ON Y YES T TRUE    */

           /* (case insensitive) are acceptable aliases for 0 and 1  */

           /* respectively.                                          */

,_REQ=0    /* Value required? 0=No, 1=Yes.                           */

,_WORDS=0  /* Multiple values allowed? 0=No ,1=Yes                   */

,_CASE=U   /* Convert case of parameter value & _val? U=upper,       */

           /* L=lower,N=no conversion.                               */

,_MSG=     /* When specified, set parmerr to 1 and writes _msg as the*/

           /* last error message.                                    */

,_VARCHK=0 /* 0=Assume that variable defined by _parm exists.        */

           /* 1=Check for existence - issue global statement if not  */

           /* defined (and _req=0).                                  */

,_DEF=     /* Default parameter value when not assigned by calling   */

           /* macro.                                                 */

);

%local _word _n _vl _pl _ml _error _parm_mv;

%global s_parmv s_msg;  /* in case not in global environment */

%*---------------------------------------------------------------------

Initialize error flags, and valid (vl) flag.

----------------------------------------------------------------------;

%if (&parmerr = ) %then %do;

   %let parmerr = 0;

   %let s_msg = ;

%end;

%let _error = 0;

%*---------------------------------------------------------------------

Support undefined values of the _PARM macro variable.

----------------------------------------------------------------------;

%if (&_varchk) %then %do;

   %let _parm_mv = macro variable;

   %if ^%symexist(&_parm) %then %do;

      %if (&_req) %then

         %local &_parm

      ;

      %else

         %global &_parm

      ; ;

   %end;

%end;

%else %let _parm_mv = parameter;

%*---------------------------------------------------------------------

Get lengths of _val, _msg, and _parm to use as numeric switches.

----------------------------------------------------------------------;

%let _vl = %length(&_val);

%let _ml = %length(&_msg);

%if %length(&&&_parm) %then

   %let _pl = %length(%qsysfunc(trim(&&&_parm)));

%else %if %length(&_def) %then %do;

   %let _pl = %length(&_def);

   %let &&_parm = &_def;

%end;

%else %let _pl = 0;

%*---------------------------------------------------------------------

When _MSG is not specified, change case of the parameter and valid

values conditional on the value of the _CASE parameter.

----------------------------------------------------------------------;

%if ^(&_ml) %then %do;

   %let _parm = %upcase(&_parm);

   %let _case = %upcase(&_case);

   %if (&_case = U) %then %do;

      %let &_parm = %qupcase(&&&_parm);

      %let _val = %qupcase(&_val);

   %end;

   %else %if (&_case = L) %then %do;

      %if (&_pl) %then %let &_parm = %qsysfunc(lowcase(&&&_parm));

      %if (&_vl) %then %let _val = %qsysfunc(lowcase(&_val));

   %end;

   %else %let _val = %quote(&_val);

%*---------------------------------------------------------------------

When _val=0 1, map supported aliases into 0 or 1.

----------------------------------------------------------------------;

   %if (&_val = 0 1) %then %do;

      %let _val=%quote(0 (or OFF NO N FALSE F) 1 (or ON YES Y TRUE T));

      %if %index(%str( OFF NO N FALSE F ),%str( &&&_parm )) %then

         %let &_parm = 0;

      %else %if %index(%str( ON YES Y TRUE T ),%str( &&&_parm )) %then

         %let &_parm = 1;

   %end;

%end;

%*---------------------------------------------------------------------

Bail out when no parameter validation is requested

----------------------------------------------------------------------;

%if (&s_parmv = 0) %then %goto quit;

%*---------------------------------------------------------------------

Error processing - parameter value not null

Error 1: Invalid value - not a positive integer

Error 2: Invalid value - not in valid list

Error 3: Single value only

Error 4: Value required.

Error 5: _MSG specified

----------------------------------------------------------------------;

%if (&_ml) %then %let _error = 5;

%*---------------------------------------------------------------------

Macro variable specified by _PARM is not null.

----------------------------------------------------------------------;

%else %if (&_pl) %then %do;

%*---------------------------------------------------------------------

Loop through possible list of words in the _PARM macro variable.

-----------------------------------------------------------------------;

   %if ((&_vl) | ^(&_words)) %then %do;

      %let _n = 1;

      %let _word = %qscan(&&&_parm,1,%str( ));

%*---------------------------------------------------------------------

Check against valid list for each word in macro parameter

----------------------------------------------------------------------;

      %do %while (%length(&_word));

%*---------------------------------------------------------------------

Positive integer check.

----------------------------------------------------------------------;

         %if (&_val = POSITIVE) %then %do;

            %if %sysfunc(verify(&_word,0123456789)) %then

               %let _error = 1;

            %else %if ^(&_word) %then %let _error = 1;

         %end;

%*---------------------------------------------------------------------

Non-negative integer check.

----------------------------------------------------------------------;

         %else %if (&_val = NONNEGATIVE) %then %do;

            %if %sysfunc(verify(&_word,0123456789)) %then

               %let _error = 1;

         %end;

%*---------------------------------------------------------------------

Check against valid list. Note blank padding.

----------------------------------------------------------------------;

         %else %if (&_vl) %then %do;

            %if ^%index(%str( &_val ),%str( &_word )) %then

               %let _error = 2;

         %end;

%*---------------------------------------------------------------------

Get next word from parameter value

-----------------------------------------------------------------------;

         %let _n = %eval(&_n + 1);

         %let _word = %qscan(&&&_parm,&_n,%str( ));

      %end; %* for each word in parameter value;

%*---------------------------------------------------------------------

Check for multiple _words. Set error flag if not allowed.

----------------------------------------------------------------------;

      %if (&_n ^= 2) & ^(&_words) %then %let _error = 3;

   %end; %* valid not null ;

%end; %* parameter value not null ;

%*---------------------------------------------------------------------

Error processing - Parameter value null

Error 4: Value required.

----------------------------------------------------------------------;

%else %if (&_req) %then %let _error = 4;

%*---------------------------------------------------------------------

Write error messages

----------------------------------------------------------------------;

%if (&_error) %then %do;

   %let parmerr = 1;

   %put %str( );

   %put ERROR: Macro %upcase(&macro) user error.;

   %if (&_error = 1) %then %do;

      %put ERROR: &&&_parm is not a valid value for the &_parm &_parm_mv..;

      %put ERROR: Only positive integers are allowed.;

      %let _vl = 0;

   %end;

   %else %if (&_error = 2) %then

      %put ERROR: &&&_parm is not a valid value for the &_parm &_parm_mv..;

   %else %if (&_error = 3) %then %do;

      %put ERROR: &&&_parm is not a valid value for the &_parm &_parm_mv..;

      %put ERROR: The &_parm &_parm_mv may not have multiple values.;

   %end;

   %else %if (&_error = 4) %then

      %put ERROR: A value for the &_parm &_parm_mv is required.;

   %else %if (&_error = 5) %then %do;

      %if (&_parm ^= ) %then

      %put ERROR: &&&_parm is not a valid value for the &_parm &_parm_mv..;

      %put ERROR: &_msg..;

   %end;

   %if (&_vl) %then

      %put ERROR: Allowable values are: &_val..;

   %if %length(&_msg) %then %let s_msg = &_msg;

   %else %let s_msg = Problem with %upcase(&macro) parameter values - see LOG for details.;

%end; %* errors ;

%quit:

%*---------------------------------------------------------------------

Unquote the the parameter value, unless it contains an ampersand or

percent sign.

----------------------------------------------------------------------;

%if ^%sysfunc(indexc(&&&_parm,%str(&%%))) %then

   %let &_parm = %unquote(&&&_parm);

%mend;

/******* END OF FILE *******/

And here is the working code:

options mprint;

* start with a clean slate ;

proc datasets lib=work kill nowarn nolist;

quit;

* create dummy datasets ;

data foo bar blah;

  x=1;

run;

* use the dictionary tables to get a list of datasets in the desired library ;

proc sql noprint;

  select memname into :datasets separated by " "

  from dictionary.tables

  where libname="WORK"

  ;

quit;

* check the results ;

%put &datasets;

* code fragment to create passwords ;

%macro code;

  modify &word (read=rpw write=wpw alter=apw);

  run;

%mend;

* use loop macro to execute code fragment for each "word", in this case dataset name ;

proc datasets lib=work;

  %loop(&datasets)

quit;


Please post your question as a self-contained data step in the form of "have" (source) and "want" (desired results).
I won't contribute to your post if I can't cut-and-paste your syntactically correct code into SAS.
data_null__
Jade | Level 19

You can gen the needed code simply from SASHELP.VMEMBER with a data step and execute it with %INC.

Modify the WHERE statement to point to your LIBNAME and relevant MEMTYPEs.

filename FT56F001 temp;

data _null_;

   file FT56F001;

   set sashelp.vmember(keep=memname libname memtype);

   by libname;

   where memtype eq 'DATA' and libname eq 'SASUSER';

   if first.libname then put 'Proc Datasets lib=' libname ';';

   put +3 'modify ' memname '(read=pw write=pw alter=pw);';

   if last.libname then put +3 'Run; Quit;';

   run;

%inc FT56F001;

sid_sas
Calcite | Level 5

Great! Looks like this is what I was looking for. I will mark it as correct when I test out the code !

Thanks!

Sid.

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 6 replies
  • 2609 views
  • 3 likes
  • 4 in conversation