diff --git a/base/mp_copyfolder.sas b/base/mp_copyfolder.sas
new file mode 100644
index 0000000..dfbed16
--- /dev/null
+++ b/base/mp_copyfolder.sas
@@ -0,0 +1,78 @@
+/**
+ @file
+ @brief A macro to recursively copy a directory
+ @details Performs a recursive directory listing then works from top to bottom
+ copying files and creating subdirectories.
+
+ Usage:
+
+ %let rootdir=%sysfunc(pathname(work))/demo;
+ %let copydir=%sysfunc(pathname(work))/demo_copy;
+ %mf_mkdir(&rootdir)
+ %mf_mkdir(&rootdir/subdir)
+ %mf_mkdir(&rootdir/subdir/subsubdir)
+ data "&rootdir/subdir/example.sas7bdat";
+ run;
+
+ %mp_copyfolder(&rootdir,©dir)
+
+ @param source Unquoted path to the folder to copy from.
+ @param target Unquoted path to the folder to copy to.
+
+
SAS Macros
+ @li mf_getuniquename.sas
+ @li mf_isdir.sas
+ @li mf_mkdir.sas
+ @li mp_abort.sas
+ @li mp_dirlist.sas
+
+ Related Macros
+ @li mp_copyfolder.test.sas
+
+**/
+
+%macro mp_copyfolder(source,target);
+
+ %mp_abort(iftrue=(%mf_isdir(&source)=0)
+ ,mac=&sysmacroname
+ ,msg=%str(Source dir does not exist (&source))
+ )
+
+ %mf_mkdir(&target)
+
+ %mp_abort(iftrue=(%mf_isdir(&target)=0)
+ ,mac=&sysmacroname
+ ,msg=%str(Target dir could not be created (&target))
+ )
+
+ /* prep temp table */
+ %local tempds;
+ %let tempds=%mf_getuniquename();
+
+ /* recursive directory listing */
+ %mp_dirlist(path=&source,outds=work.&tempds, maxdepth=MAX)
+
+ /* create folders and copy content */
+ data _null_;
+ set work.&tempds;
+ filepath2="&target/"!!substr(filepath,%length(&source)+2);
+ if file_or_folder='folder' then call execute('%mf_mkdir('!!filepath2!!')');
+ else do;
+ length fref1 fref2 $8;
+ rc1=filename(fref1,filepath,'disk','recfm=n');
+ rc2=filename(fref2,filepath2,'disk','recfm=n');
+ if fcopy(fref1,fref2) ne 0 then do;
+ sysmsg=sysmsg();
+ putlog "%str(ERR)OR: Unable to copy " filepath " to " filepath2;
+ putlog sysmg=;
+ end;
+ end;
+ rc=filename(fref1);
+ rc=filename(fref2);
+ run;
+
+ /* tidy up */
+ proc sql;
+ drop table work.&tempds;
+
+%mend mp_copyfolder;
\ No newline at end of file
diff --git a/base/mp_dirlist.sas b/base/mp_dirlist.sas
index 504ec36..371ddbf 100644
--- a/base/mp_dirlist.sas
+++ b/base/mp_dirlist.sas
@@ -202,6 +202,7 @@ run;
data _null_;
set &out_ds;
where file_or_folder='folder';
+ length code $10000;
code=cats('%nrstr(%mp_dirlist(path=',filepath,",outds=&outds"
,",getattrs=&getattrs,level=%eval(&level+1),maxdepth=&maxdepth))");
put code=;
diff --git a/tests/crossplatform/mp_copyfolder.test.sas b/tests/crossplatform/mp_copyfolder.test.sas
new file mode 100644
index 0000000..4594b6f
--- /dev/null
+++ b/tests/crossplatform/mp_copyfolder.test.sas
@@ -0,0 +1,52 @@
+/**
+ @file
+ @brief Testing mp_copyfolder.sas macro
+
+ SAS Macros
+ @li mp_copyfolder.sas
+ @li mf_mkdir.sas
+ @li mf_nobs.sas
+ @li mp_assert.sas
+ @li mp_dirlist.sas
+
+**/
+
+/**
+ * make a directory structure
+ */
+
+%let root=%sysfunc(pathname(work))/top;
+%mf_mkdir(&root)
+%mf_mkdir(&root/a)
+%mf_mkdir(&root/b)
+%mf_mkdir(&root/a/d)
+%mf_mkdir(&root/a/e)
+%mf_mkdir(&root/a/e/f)
+data "&root/a/e/f/ds1.sas7bdat";x=1;
+data "&root/a/e/ds2.sas7bdat";x=1;
+data "&root/a/ds3.sas7bdat";x=1;
+run;
+
+%mp_dirlist(path=&root, outds=myTable, maxdepth=MAX)
+
+%mp_assert(
+ iftrue=(%mf_nobs(work.mytable)=8),
+ desc=Temp data successfully created,
+ outds=work.test_results
+)
+
+/**
+ * copy it
+ */
+%let newfolder=%sysfunc(pathname(work))/new;
+%mp_copyfolder(&root,&newfolder)
+
+%mp_dirlist(path=&newfolder, outds=work.myTable2, maxdepth=MAX)
+
+%mp_assert(
+ iftrue=(%mf_nobs(work.mytable2)=8),
+ desc=Folder successfully copied,
+ outds=work.test_results
+)
+
+