BookmarkSubscribeRSS Feed
Billybob73
Quartz | Level 8

Hi,

Has SAS developed a method in the meantime to zip files from the SAS server with encryption ? (password).

I'm not looking for methods such as intalling winzip command line on the SAS server. I mean a home grown SAS method.

Thanks !

Rgds

B

4 REPLIES 4
jimbarbour
Meteorite | Level 14

There may well be a way; hopefully someone will comment if so.

 

However, if you launch a WinZip (or whatever Zip tool is on your system) using SYSTASK, you can do it completely from within SAS, no exiting and manually using the command line.

 

Jim

kirankp
Fluorite | Level 6
Can you please provide the SYATASK code to include zip file password in SAS V9.3

Code:


data _null_;
call symput('date',(put(date(),yymmddn8.)));
run;

/* ods begin */
ods package(ProdOutput) open nopf;
ods package(ProdOutput)
add file= "&directory\DONKEY_XX_Conc_HHHH_%sysfunc(today(),YYMMDDN8.).csv";

ods package(ProdOutput)
publish archive
properties
(archive_name= "DONKEY_XX_%trim(&date.).zip"
archive_path="&directory");
ods package(ProdOutput) close;
/* ods end */
jimbarbour
Meteorite | Level 14

@kirankp, I wrote a macro to do the zipping for me.  We have WinZip.exe on our server.  You might have different software on your server.  I'll put the macro down below.  The macro calls some other macros, but don't get too worried about that.  Look at what the macro is doing in terms of the actual zipping, and perhaps you can use this as something of a template.

 

Jim

 

/*-------------------------------------------------------------------------------*/
/*	Macro:	Archive_Data
/*  Author: Jim Barbour 
/*	Date:	26 February 2020
/*	Info:	This macro calls WinZip to create a Zip archive of whatever file is
/*			passed in as an arugument to the macro call.  Input parameters are
/*			first.  Output parameters (pertaining to the zip file) are second.
/*
/*			If you are archiving a SAS data set and that SAS data set has an 
/*			index, you must archive both the SAS data set and the corresponding
/*			index data set or SAS will consider the data corrupted.
/*
/*			Filename Pre_Zip will verify the existence of a file prior to running
/*			the Zip commands.
/*-------------------------------------------------------------------------------*/
/*									CHANGE LOG
/*-------------------------------------------------------------------------------*/
/*	Name:	Jim Barbour				Date:	26 February 2020
/*	Info:	Original implementation.
/*-------------------------------------------------------------------------------*/

&Null	%MACRO	Archive_Data(File_Path, File_Name, Zip_Path, Zip_Name, 
							ZipPgmPath=, Width=115, Xmin=XMIN, Xwait=XWAIT, 
							Run_Mode=PROD, Debug=NO, Trace=NO);
	%LOCAL	Zip_File;
	%LOCAL	Full_File;
	%LOCAL	ZipPgmPath;
	%LOCAL	Cmnt;
	%LOCAL	MacroName;
	%LOCAL	Save_Xwait;

	OPTION	&Xmin;

	%LET	MacroName								=	&SysMacroName;
	%Start_Mac(&MacroName, Trace=&Trace)

	%IF	%QUPCASE(&Debug)							=	YES			%THEN
		%DO;
			%LET	Cmnt							=	;
			%PUT	&Nte1  Debug is on in macro &Sysmacroname;
		%END;
	%ELSE
		%DO;
			%LET	Cmnt							=	*;
		%END;

	%&Cmnt.PUT	&Nte2  Initial Xwait option is 			%SYSFUNC(GETOPTION(XWAIT));
	%LET	Save_Xwait								=	%SYSFUNC(GETOPTION(XWAIT));
	%&Cmnt.PUT	&Nte2  Saved Xwait option is   			&Save_Xwait;

	OPTION	&Xwait;
	%&Cmnt.PUT	&Nte2  Current Xwait option is  		%SYSFUNC(GETOPTION(XWAIT));

	%IF	%SYMEXIST(Data_Path)										AND
		%BQUOTE(&File_Path)							=	%STR()		%THEN
		%DO;
			%&Cmnt.PUT	&Nte2  Setting File_Path to Global variable Data_Path which is equal to &Data_Path;
			%LET	File_Path						=	&Data_Path;
		%END;
	%ELSE
		%DO;
			%&Cmnt.PUT	&Nte2  File_Path was supplied as &File_Path;
		%END;

	%IF	%SYMEXIST(Arch_Path)										AND
		%BQUOTE(&Zip_Path)							=	%STR()		%THEN
		%DO;			
			%&Cmnt.PUT	&Nte2  Setting Zip_Path to Global variable Arch_Path which is equal to &Arch_Path;
			%LET	Zip_Path						=	&Arch_Path;
		%END;
	%ELSE
		%DO;
			%&Cmnt.PUT	&Nte2  Zip_Path was supplied as &Zip_Path;
		%END;

	%IF	%BQUOTE(&ZipPgmPath)						=	%STR()		%THEN
		%DO;
			%LET	ZipPgmPath						=	E:\%STR("")Program Files%STR("")\WinZip\wzzip.exe;
			%&Cmnt.PUT	&Nte2  Setting ZipPgmPath to default value of &ZipPgmPath;
		%END;
	%ELSE
		%DO;
			%&Cmnt.PUT	&Nte2  ZipPgmPath was supplied as |&ZipPgmPath|;
		%END;

	%IF	%BQUOTE(%SYSFUNC(LENGTHN(&File_Path)))		>	0			AND
		%BQUOTE(%SYSFUNC(SUBSTR(&File_Path,	%SYSFUNC(LENGTH(&File_Path)), 1)))	^=	%STR(\)	%THEN
		%DO;
			%&Cmnt.PUT	&Nte2  Length of &File_Path	=	%BQUOTE(%SYSFUNC(LENGTHN(&File_Path)));
			%&Cmnt.PUT	&Nte2  Last char &File_Path	=	%BQUOTE(%SYSFUNC(SUBSTR(&File_Path,	%SYSFUNC(LENGTH(&File_Path)), 1)));
			%LET	File_Path						=	&File_Path%STR(\);
			%&Cmnt.PUT	&Nte2  Added a back slash to File_Path:  &File_Path;
		%END;
	%ELSE
		%DO;
			%&Cmnt.PUT	&Nte2  Length of &File_Path	=	%BQUOTE(%SYSFUNC(LENGTHN(&File_Path)));
			%&Cmnt.PUT	&Nte2  Last char &File_Path	=	%BQUOTE(%SYSFUNC(SUBSTR(&File_Path,	%SYSFUNC(LENGTH(&File_Path)), 1)));
			%&Cmnt.PUT	&Nte2  Did NOT add a new back slash to File_Path:  &File_Path;
		%END;

	%IF	%BQUOTE(%SYSFUNC(LENGTHN(&Zip_Path)))		>	0			AND
		%BQUOTE(%SYSFUNC(SUBSTR(&Zip_Path,	%SYSFUNC(LENGTH(&Zip_Path)), 1)))	^=	%STR(\)	%THEN
		%DO;
			%&Cmnt.PUT	&Nte2  Length of &Zip_Path	=	%BQUOTE(%SYSFUNC(LENGTHN(&Zip_Path)));
			%&Cmnt.PUT	&Nte2  Last char &Zip_Path	=	%BQUOTE(%SYSFUNC(SUBSTR(&Zip_Path,	%SYSFUNC(LENGTH(&Zip_Path)), 1)));
			%LET	Zip_Path						=	&Zip_Path%STR(\);
			%&Cmnt.PUT	&Nte2  Added a back slash to Zip_Path:  &Zip_Path;
		%END;
	%ELSE
		%DO;
			%&Cmnt.PUT	&Nte2  Length of &Zip_Path	=	%BQUOTE(%SYSFUNC(LENGTHN(&Zip_Path)));
			%&Cmnt.PUT	&Nte2  Last char &Zip_Path	=	%BQUOTE(%SYSFUNC(SUBSTR(&Zip_Path,	%SYSFUNC(LENGTH(&Zip_Path)), 1)));
			%&Cmnt.PUT	&Nte2  Did NOT add a new back slash to Zip_Path:  &Zip_Path;
		%END;

	%LET		Full_File							=	%SYSFUNC(CATS(&File_Path., 	&File_Name.));
	%LET		Zip_File							=	%SYSFUNC(CATS(&Zip_Path., 	&Zip_Name., .zip));

	%&Cmnt.PUT	&Nte2  &=Full_file;
	%&Cmnt.PUT	&Nte2  &=Zip_file;

	FILENAME	Pre_Zip				"&Full_File";

	DATA	_NULL_;
		LENGTH	_RC				4.;
		LENGTH	_Line			$255;

		INFILE	Pre_Zip;

		_RC											=	INPUT(SYMGET('SYSCC'), 4.);;
		IF	0	<	_RC								<	8			THEN
			DO;
				PUTLOG	"&Err2  %Format_Dashes(&Width)";
				_Line								=	RESOLVE(CAT('&Err1  %Format_Line(Pre-Zip failed check failed for &File_Name..  SYSCC = ', STRIP(PUT(_RC, 4.)), '., &Width)'));
				PUTLOG	_Line;
				PUTLOG	"&Err2  %Format_Dashes(&Width)";
				PUTLOG	"&Err2  ";
			   	CALL	SYMPUTX('SYSCC',	8, 	'G');
			END;
		ELSE
			DO;
				&Cmnt	PUTLOG	"&Nte2 Pre-Zip file check successful";
			END;
	RUN;

	%&Cmnt.List_RC(Dashes=YES);

	%IF	&SYSCC										=	0			%THEN
		%DO;
			%&Cmnt.PUT	&Nte2  SYSCC is 0.  Starting Zip Archive creation process;

			%cd(&Zip_Path);

			%**-----------------------------------------------------------------------------**;
			%**								ORIGINAL VERSION								**;
			%**	The following file name works but only with files less than about 14 Gb.  	**;
			%**	For some reason, larger files "hang" and neither succeed nor fail.  	 	**;
			%**	Workaround #1 is to write to an intermediate STDOUT text file.				**;
			%**-----------------------------------------------------------------------------**;
			%*FILENAME	WinOpSys	PIPE		"&ZipPgmPath. -a ""&Zip_File."" ""&Full_File.""";

			%**-----------------------------------------------------------------------------**;
			%**								WORKAROUND #1									**;
			%**	The following file name is for Workaround #1.  The original file name is  	**;
			%**	split into 1) an independent (no PIPE) "X" command that writes to an   	 	**;
			%**	intermediate STDOUT text file and 2) a Filename that reads that STDOUT.		**;
			%**-----------------------------------------------------------------------------**;
			%*X	"del WinZip_STDOUT_Temp.txt & &ZipPgmPath. -a ""&Zip_File."" ""&Full_File.""	>	WinZip_STDOUT_Temp.txt";
			%*FILENAME	WinOpSys	"WinZip_STDOUT_Temp.txt";

			%**-----------------------------------------------------------------------------**;
			%**								WORKAROUND #2									**;
			%**	The following file name is for Workaround #2.  STDOUT is piped directly  	**;
			%**	into the DATA step but STDERR ("2") is redirected to a STDERR text file.	**;
			%**	Apparently, when both STDOUT and STDERR are piped directly into the DATA	**;
			%**	step, some buffer gets full, and the entire process freezes.  The downside	**;
			%**	of redirecting STDERR to an external text file is that STDERR is then no 	**;
			%**	longer available inside the DATA step.  If there is a problem, the external **;
			%**	text file must be examined manually or in a subsequent DATA step.			**;
			%**-----------------------------------------------------------------------------**;
			FILENAME	WinOpSys	PIPE		"&ZipPgmPath. -a ""&Zip_File."" ""&Full_File.""	2>	WinZip_STDERR_Temp.txt";

			DATA	_NULL_;
				LENGTH	_Curr_DateTime	$23;
				LENGTH	_Line			$255;
				LENGTH	_RC				4.;
				LENGTH	_First_Time		3.;
				LENGTH	_Total_Bytes	3.;

				RETAIN	_First_Time		1;
				RETAIN	_Total_Bytes	0;

				**------------------------------------------------------------------------------**;
				**	The "Start Zip at" log message is inaccurate when an intermediate text file	**;
				**	is used and, in such a case (Workaround #1), should be commented out.		**;
				**	For Workaround #2, the "Start Zip at" works fine and may be uncommented.	**;
				**------------------------------------------------------------------------------**;
				IF	_First_Time										THEN
					DO;
						_First_Time					=	0;
						PUTLOG	"&Nte2  %Format_Dashes(&Width)";
						_Curr_DateTime				=	TRANWRD(PUT(DATETIME(), E8601DT23.2), 'T', ' ');
						_Line						=	RESOLVE(CAT('&Nte1  %Format_Line(Start Zip at ', STRIP(_Curr_DateTime), '., &Width)'));
						PUTLOG	_Line;
					END;

				**------------------------------------------------------------------------------**;
				**	As with a FILENAME with a PIPE, the following "filenameless" INFILE works  	**;
				**	but only with files less than about 14 Gb.	Using an intermediate text   	**;
				**	file is the Workaround #1 for this odd bug.  Workaround #2 is to redirect	**;
				**	STDERR to an external text file.  See examples, above.						**;
				**------------------------------------------------------------------------------**;
*				INFILE	"&ZipPgmPath. -a ""&Zip_File."" ""&Full_File."""	PIPE
*									TRUNCOVER
*									END				=	_Zip_Process_Complete
*									LENGTH			=	_SAS_Length
*									;

				INFILE	WinOpSys	TRUNCOVER
									END				=	_Zip_Process_Complete
									LENGTH			=	_SAS_Length
									;

				INPUT	_WinZip_Msg	$VARYING32766.		_SAS_Length;

				_Line								=	RESOLVE(CAT('&Nte2  %Format_Line(%STR(', STRIP(_WinZip_Msg), '), &Width)'));
				PUTLOG	_Line;

				IF	INDEX(_WinZip_Msg, 'Total bytes=')				THEN
					DO;
						&Cmnt	PUTLOG	"&Nte2  | 'Total bytes=' has been found";
						_Total_Bytes				=	1;
					END;

				IF	_Zip_Process_Complete							THEN
					DO;
						IF	NOT	_Total_Bytes						THEN
							DO;
								PUTLOG	"&Warn2  %Format_Dashes(&Width)";
								_Line				=	RESOLVE(CAT('&Warn1  %Format_Line(&sQuote.Total bytes=&sQuote. not returned by WinZip, &Width)'));
								PUTLOG	_Line;
								_Line				=	RESOLVE(CAT('&Warn2  %Format_Line(Results are suspect.  Check zip archive., &Width)'));
								PUTLOG	_Line;
								PUTLOG	"&Warn2  %Format_Dashes(&Width)";
								_RC					=	INPUT(SYMGET('SysRC'), 4.);
								IF	_RC				<	4			THEN
									DO;
										&Cmnt	PUTLOG	"&Nte2  Setting SYSCC and SYSRC to 4";
										CALL	SYMPUTX('SYSCC', '4', 'G');
										CALL	SYMPUTX('SYSRC', '4', 'G');
									END;
							END;
						_Curr_DateTime				=	TRANWRD(PUT(DATETIME(), E8601DT23.2), 'T', ' ');
						_Line						=	RESOLVE(CAT('&Nte2  %Format_Line(End Zip at ', STRIP(_Curr_DateTime), '., &Width)'));
						PUTLOG	_Line;

						_RC							=	INPUT(SYMGET('SysRC'), 4.);

						IF	_RC						=	0			THEN
							DO;
								PUTLOG	"&Nte2  %Format_Line(Return code from zipping &File_Name = 0., &Width)";
								PUTLOG	"&Nte2  %Format_Dashes(&Width)";
								PUTLOG	"&Nte2  ";
							END;
						ELSE
							DO;
								PUTLOG	"&Err2  %Format_Dashes(&Width)";
								_Line				=	RESOLVE(CAT('&Err1  %Format_Line(Return code from zipping &File_Name = ', STRIP(PUT(_RC, 4.)), '., &Width)'));
								PUTLOG	_Line;
								PUTLOG	"&Err2  %Format_Dashes(&Width)";
								PUTLOG	"&Err2  ";
							END;
					END;
			RUN;
		%END;
	%ELSE
		%DO;
			%PUT	&Warn2  ;
			%PUT	&Warn2  %Format_Dashes(&Width);
			%PUT	&Warn1  %Format_Line(SYSCC%STR(=)&SYSCC after Pre-Zip file check.  Skipping Zip archive creation., &Width);
			%PUT	&Warn2  %Format_Line(Make sure to run %NRSTR(%Reset_RC) or %NRSTR(%Reset_All) before re-running., &Width);
			%PUT	&Warn2  %Format_Dashes(&Width);
		%END;

	%IF	%QUPCASE(&Run_Mode)							=	TEST		%THEN
		%DO;
			%List_RC(Dashes=YES);
			%PUT	_LOCAL_;
		%END;

	OPTION	&Save_Xwait;
	%&Cmnt.PUT	&Nte2  Final Xwait option is %SYSFUNC(GETOPTION(XWAIT));

	%LET	MacroName	=	&SysMacroName;  %End_Mac(&MacroName, Trace=&Trace)
%MEND	Archive_Data;

%**-----------------------------------------------------------------------------**;

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!

Submit your idea!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 4 replies
  • 5140 views
  • 1 like
  • 4 in conversation