We help IT Professionals succeed at work.

Script to copy a file to every sub-sub folder in this directory

Medium Priority
550 Views
Last Modified: 2012-05-12
Hi,

I have the following folder structure on a server:

c:\Users\**username**\databases\

There are several hundred users, so there are several hundred 'username' folders, for example:
c:\users\johndoe\databases\
c:\users\marysmith\databases\
c:\users\jamesdean\databases\

I need to copy a file to the databases folder of each user.  I would assume the path would look something like:

C:\Users\*\databases\

but i'm no good at scripting at all.

Could someone write something for me please?
MUCH appreciated!
Comment
Watch Question

Test your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016
Commented:
Fairly straight forward, form a DOS command line you can do this single line:

for /D %A in ("c:\users\*") do copy "c:\temp\template.txt" "%~A\databases"

Open in new window

or in a BAT file the syntax changes slightly to:

for /D %%A in ("c:\users\*") do copy "c:\temp\template.txt" "%%~A\databases"

Open in new window

~bp
if your file is named FILE.TXT then you can do this in a batch file:
@echo off
for /d %%a in ("c:\users\*") do copy /y FILE.TXT "%%a\databases\"

Open in new window

or this as a command in DOS:
for /d %a in ("c:\users\*") do @copy /y FILE.TXT "%a\databases\"

Open in new window

If you don't want output to the screen add '>nul' to the end of the line like this:
@echo off
for /d %%a in ("c:\users\*") do copy /y FILE.TXT "%%a\databases\" >nul

Open in new window

Or like this:
for /d %a in ("c:\users\*") do @copy /y FILE.TXT "%a\databases\" >nul

Open in new window

billprew

Insomnia??
billprew

The best cure for insomnia is to get lots of sleep !!

:)
Bill PrewTest your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016

Commented:
Early yet...

~bp
What's your timezone? Mine's GMT London.
Bill PrewTest your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016

Commented:
US EDT (GMT-4 during daylight savings, GMT-5 in a couple of days)

~bp

Author

Commented:
billprew -
thanks!  one question though; if the file in one of the folders is in use (locked or whatever), will the script just come to a halt?  How do i make it log which folder it failed at?  It's going to be going through hundreds of them, and i don't want it to stop if it just fails on one
Steve KnightIT Consultancy
CERTIFIED EXPERT

Commented:
listening... in case Bill not around will add you an errorlevel check in.  Is this like the request I saw last night mystical_ice?
Use this to continue copying if errors are likely to occur...
@echo off

echo %date% %time% >>logfile.txt

for /d %%a in ("c:\users\*") do xcopy FILE.TXT "%%a\databases\" /c /f /r /y >>logfile.txt 2>&1

echo See results in LOGFILE.TXT

Open in new window

Bill PrewTest your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016

Commented:
I believe it will continue copying.

~bp
billprew

Incontinence?
billprew

The best cure for incontinence is to get lots of sleep !!

Author

Commented:
Excellent! Thanks!

Author

Commented:
Excellent, thanks!
Steve KnightIT Consultancy
CERTIFIED EXPERT

Commented:
Billprews' original comment http:#37086506 IMO would do as you asked.  If you want it logged then just add > log.txt 2>&1 to the end of the line, i.e.

@echo off
(for /D %%A in ("c:\users\*") do copy "c:\temp\template.txt" "%%~A\databases") > log.txt 2>&1

If you want an actual log of error dir. names rather than going through above log would need some errorlevel checks in the individual parts of the do loop.

Steve
Bill PrewTest your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016

Commented:
I did confirm, the script will continue to run even if one of the copies throws an error on afile.

~bp
Just checked prew's code and I can also confirm it will continue copying where 'Access is denied' on one or more files.
Steve KnightIT Consultancy
CERTIFIED EXPERT

Commented:
Another example of a quick errorlevel check on the code you already have from billprew might be something like this.  If an error occurs it is redirected into the log file, and then the name of the offending directory too.

Steve
@echo off
del log.txt 2>NUL
for /D %%A in ("c:\users\*") do (copy "c:\temp\template.txt" "%%~A\databases")>> log.txt 2>&1 || echo   ** Error with %%A -- see previous line for error ** >>log.txt

Open in new window

It's lengthy, but well worth it.

NOTE: Change the following line:

   set source=filespec

to point to your source file/s, for example:

   set source=c:\folder\file.txt  or  set source=c:\folder\*.txt  etc...

before running the batch file.





@echo off
setlocal enabledelayedexpansion

rem Reset system error code to '0'
cmd /c exit 0

rem %source% = folder or file/s you're copying ie, c:\temp\file.tmp
rem %destination% = base location of users; folders ie, c:\users
rem %subfolder% = usres; subfolder ie, databases
rem %%a = user's folder ie, %destination%\paul - see FOR-loop below
rem Copy "%source%" "%%a\%subfolder%\" = copy "c:\temp\file.tmp" "c:\users\paul\"
rem Do not include trailing backslashes
set source=filespec
set destination=c:\users
set subfolder=databases

rem Logfile = filespec of logfile ie, c:\logs\logfile.txt
rem Tempfile = filespec of temporary file ie, %temp%\BATCHNAME.tmp
rem Where BATCHNAME is the filename of this batch file
set logfile=logfile.txt
set tempfile=%temp%\%~n0.tmp

rem Errcount = number of errors
rem Count = number of users
set errcount=0
set count=0

rem Log date and time
echo %date% %time% >>"%logfile%"

rem Check source folder or file/s exists
rem If it doesn't, set system error code '1'
if not exist "%source%" (
  set errcount+=1
  echo Cannot find %source%. Batch process aborted. >>"%logfile%"
  cmd /c exit 1
)

rem If there's no error, continue
if %errorlevel%==0 (
  rem Check destination base folder exists
  rem If it doesn't, set system error code '1'
  if not exist "%destination%\." (
    set errcount+=1
    echo Cannot find %destination% folder. Batch process aborted. >>"%logfile%"
    cmd /c exit 1
  )
)

rem If there's no error, continue
if %errorlevel%==0 (
  rem For each user...
  for /d %%a in ("%destination%\*") do (
    rem Reset system error code '0'
    rem Count user
    cmd /c exit 0
    set /a count+=1

    rem Check user has target subfolder
    rem If not, create it - hide system error msg
    if not exist "%%a\%subfolder%\." (
      md "%%a\%subfolder%\" 2>nul
     
      rem If unable to create user's target subfolder, log it
      rem Example: User Paul has no DATABASES folder.
      rem System error code uneffected
      if not !errorlevel!==0 (
        set /a errcount+=1
        echo User %%a has no %subfolder% folder. >>"%logfile%"
      )
    )

    rem If user's target subfolder exists, copy file/s
    rem Save system error msg, if any, for later use...
    if !errorlevel!==0 (
      copy /y "%source%" "%%a\%subfolder%\" 1>nul 2>"%tempfile%"
     
      rem If copy unsuccessful, retrieve system error msg and log it
      rem Example: Access denied... c:\users\paul
      if not !errorlevel!==0 (
        set /a errcount+=1
        set /p errmsg=<"%tempfile%"
        echo !errmsg!.. %%a >>"%logfile%"
      )
    )
  )
  echo Batch copy complete.
)

rem If all successful, report it
rem Example: File successfully copied to 25 users
if %errcount%==0 (
  echo File^(s^) successfully copied to %count% user^(s^).
  pause
) else (
  rem Otherwise, if errors occured, report it
  rem Example: 6 errors occured while copying files to 25 users.
  rem Prompt user to display errors.
  rem Example: Press any key to view errors
  rem Open log file in Notepad
  echo %errcount% error^(s^) occured while copying file^(s^) to %count% user^(s^).
  set /p .=Press any key to view errors<nul
  pause >nul
  start /wait notepad "%logfile%"
)

rem Delete temporary file if it exists
rem Exit - remove the '/b' to close the DOS session upon exiting Notepad
del "%tempfile%" 2>nul
exit /b %errcount%
Steve KnightIT Consultancy
CERTIFIED EXPERT

Commented:
Wow, Paul your surpass yourself... 100 lines  (no I haven't counted, it's a guess) to add error checking to a one line command....
Oh no... not the one-line-thing again...

let's see which way the hammer swings - i will say though, i don't feel optimistic!

a great solution can be found at http:#37087454
Bill PrewTest your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016
Commented:
@Mystical_Ice

Since you added the logging to this request after the question was posted, here's an updated version of my first solution to address that.  It logs all output of the copy command to a log file, and also logs just the failures to a different file for easy quick check for any failures.

@echo off
REM Define folders and files involved
set BaseDir=C:\Users
set DestDir=Databases
set CopyFile=C:\Temp\Template.txt
set LogFile=C:\Temp\Log.txt
set FailFile=C:\Temp\Failed.txt

REM Remove any old log files
if exists "%LogFile%" del "%LogFile%"
if exists "%FailFile%" del "%FailFile%"

REM Loop through all folders in the base folder (users)
for /D %%A in ("%BaseDir%\*") do (

  REM Log this user being processed
  echo Processing user "%%~A">>"%LogFile%"

  REM Make sure database folder exists
  if not exist "%%~A\%DestDir%\" md "%%~A\%DestDir%\"

  REM Try to copy file to each database folder, log any failures
  copy /Y "%CopyFile%" "%%~A\%DestDir%">>"%LogFile%" 2>>&1 || (
    echo %%~A\%DestDir% - Copy failed, see log file>>"%FailFile%"
  )
)

Open in new window

~bp
Just spotted two small errors in my code above (http:#37091887).

Two lines need editing. The dots need to be removed:

   if not exist "%destination%\." (

should be:

   if not exist "%destination%\" (



   if not exist "%%a\%subfolder%\." (

should be:

   if not exist "%%a\%subfolder%\" (

because they won't correctly test for the existence of folders if the dots are not removed.
Steve KnightIT Consultancy
CERTIFIED EXPERT

Commented:
Ironic.
billprew...

Looking at your code (http:#37093523). On the subject of validation, line 20:

   if not exist "%%~A\%DestDir%\" md "%%~A\%DestDir%\"

could fail and is no more a certainty as:

   md "%%~A\%DestDir%\" 2>nul

by itself.


Given the above is true, then both lines 23 and 24:

   copy /Y "%CopyFile%" "%%~A\%DestDir%">>"%LogFile%" 2>>&1 || (
      echo %%~A\%DestDir% - Copy failed, see log file>>"%FailFile%"
   )

could also fail.

Just an observation and most probably unlikely to be of any real concern (here) - unless of course it was written for a mission-critical process such as air-traffic control systems, long-range missile guidance systems or nuclear core reaction control systems (under which case, one of Steve's one-liners would definitely not be appropriate even under the most austere measures).
Bill PrewTest your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016

Commented:
@paultomasi

It's my training I guess, I typically avoid coding in such a manner that allows for errors as "acceptable".  To me that's what this approach involves:

   md "%%~A\%DestDir%\" 2>nul

Essentially it says try the MD and if errors are thrown, it's okay.  And the errors or lost forever.

I prefer the more explicit approach which only executes the MD if it is needed.   In this manner, if an error is thrown, we want to know about it (permission, bad path, etc).

This is why I typically do this:

   if exist log.txt del log.txt

rather than just:

   del log.txt>nul 2>nul

For me it's more obvious what the code is doing to the next person reading it, and it at least allows for an error message to be displayed or trapped (if the whole output of the BAT file were redirected for example).

I agree that AFTER either MD it would be best practice to check for the existence of the directory (or trap errors from the MD command) and potentially not continue if they occur.  Most BAT files I see proposed (and accepted) here though aren't looking for this type of error checking, but are rather looking for quick and easy solutions to small problems.

Hope that makes sense, let me know if it didn't.

~bp
Steve KnightIT Consultancy
CERTIFIED EXPERT

Commented:
<<air-traffic control systems, long-range missile guidance systems or nuclear core reaction control systems >>

@Paultomasi:  Agreed.  I would hope such systems aren't written by taking snippets of batch files from free answers on Experts Exchange :-)

An yes I am quite aware of how to make bullet prooof, error checked, debugged code when needed!

I also know when it is appropriate to write a one line command, or short batch file it when it is needed.  You may want to stand back and look at http:#37093523 or  http:#37086506, or indeed your own http:#37086521 and compare with the amount of code to maintain and debug in http:#37091887

Steve

Author

Commented:
Thanks so much for the help.  billprew, since you answered my original question, i have to give by far the majority of points to you.

paul, i appreciate your help as well.  just chill a little bit :)
Bill PrewTest your restores, not your backups...
CERTIFIED EXPERT
Expert of the Year 2019
Top Expert 2016

Commented:
@Mystical_Ice

Glad that turned out to be useful, thanks for the feedback.

~bp

Explore More ContentExplore courses, solutions, and other research materials related to this topic.