Good day. I am trying to write my first batch file. I finally got it do to the most basic of tasks, and have read much here that helped including tutorials. I have not yet found an article to help me put what I'm looking for together. My search-fu is weak.
I want my batch file to copy all files every 30 minutes. However, if it comes to a file that has been updated, I want it to copy but not replace the existing in the destination. I'm assuming it would just add the (1) or 'copy' to the file name. I'm not sure if I used the proper switches or need to change them based on what I'm looking for. I think they're good, but I digress.
Here is the batch that I created without the logic:
REM Backup files 30 minutes
#echo off
:start
XCOPY "C:\source directory" "C:\target directory" /d /c /s /r /y /i
TIMEOUT /t 1800 /nobreak
goto start
Normal behaviour is to overwrite the file, or to fail (depending on the action). The (1) or (copy) postfixes are special features of Windows Explorer (the shell). If you want similar behaviour in your script, you'll have to implement it yourself.
The easiest thing (also to prevent a lot of (1), (2) .. (N) files, is to create separate folders. You can create a folder with a timestamp and copy all modified files to it.
To detect which files are modified, you might use the Archive flag of the files. When a file is modified, its Archive flag is set. XCopy has the possibility to copy only those files which have the flag set. Actually the main purpose of this flag is to determine modified files (or at least, files you want to archive).
So my suggestion:
Create a folder with a timestamp in the name. You may want to use the answer to this question for that.
Use XCopy with the /M parameter. /M copies only files with the Archive attribute, and clears the attribute afterwards.
Try to delete the directory using rd or rmdir, but without the /S parameter. It will fail if it contains files, but this way you will prevent a lot of empty directories.
Before implementing this, make sure that the process which modifies the files, also sets the Archive attribute again. It should do that automatically, but it can't hurt to test this.
-edit- Per request an example:
REM Backup files 30 minutes
#echo off
:start
REM generate a timestamp value that can be used as a file name.
setlocal TIMESTAMP=%DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2%-%TIME:~0,2%-%TIME:~3,2%-%TIME:~6,2%
REM Not needed, I think: Creating the directory yourself.
REM md "C:\target directory\%TIMESTAMP%"
REM /S for recursive. /I should create target directory? /M for backup mode.
XCOPY "C:\source directory" "C:\target directory\%TIMESTAMP%" /M /S /I
REM Not needed, I think: Removing the directory (if it's empty).
REM rd "C:\target directory\%TIMESTAMP%"
TIMEOUT /t 1800 /nobreak
goto start
I think /I already solves the other issues. It assumes that target is a directory if it doesn't exist. That makes me assume that it will in fact create that directory if it doesn't exist, and probably only if there is anything to copy. If that is right, you also won't have to remove the directory if it's empty.
Considering cleanup: Remember that this method (using /M) only copies files that have changed. If you cleanup old directories, you should make sure to copy the entire folder first. The timestamped folders will contain only the modified files (incremental backup), so if you clean up old ones, your backup/copy won't be complete anymore!
Related
Bear with me here; I'm super new to coding something like this, and I think I've found a simple way to do it, but I'm running into problems. I also couldn't really find an answer from Googling or looking around here, but if it's already been answered, I apologize!
I'm running the following command in a .bat file:
xcopy D:\SHARENAME \\NAS-IP-ADDRESS\SHARENAME /s /e /d
When I run it once as a .bat file, it does its copy operations, and then closes the terminal window, signaling completion. I can verify that a copy operation occurred, since new files do show up in the Backup directory.
However, once I set this .bat file as a Windows Scheduled Task, it never stops running. The copy still occurs one time, but the task does not end. I want it to run every day at 3AM, which is fine, but it never gets the chance to run after its first time, since it never actually stops. Am I missing something to close out this .bat file in order to stop it properly?
The scheduled task does not end because of XCOPY prompts on copying a file existing already in destination directory if it should be overwritten or not. This prompt is not answered by anybody and so XCOPY waits forever. So cmd.exe never ends the batch file execution and for that reason scheduled task also never ends.
The solution is using the command line:
%SystemRoot%\System32\xcopy.exe "D:\SHARENAME" "\\NAS-IP-ADDRESS\SHARENAME\" /C /E /H /K /Q /R /Y
Most important to fix this issue is the option /Y which avoids the overwrite prompt.
Microsoft's xcopy documentation contains currently the information:
By default, you are prompted to overwrite, unless you run xcopy from within a batch script.
This is a wrong information. XCOPY is an executable in system folder of Windows and does not know if being executed by cmd.exe from within a command prompt window or from within a batch script. /Y must be specified on command line or there is an environment variable COPYCMD containing /Y in value to avoid the overwrite prompt. /Y must not be used on command line on using copy being an internal command of cmd.exe on using COPY in a batch script.
The help of XCOPY output on running in a command prompt window xcopy /? explains all other options used above. At bottom of output help can be read:
The switch /Y may be present in the COPYCMD environment variable.
This may be overridden with /-Y on the command line.
The help of command COPY output on running copy /? ends with:
The switch /Y may be present in the COPYCMD environment variable.
This may be overridden with /-Y on the command line. Default is
to prompt on overwrites unless COPY command is being executed from
within a batch script.
The additional third sentence makes the difference regarding to /Y between XCOPY and COPY on usage from within a batch script.
The help of XCOPY contains also the explanation for /S and /E.
/S Copies directories and subdirectories except empty ones.
/E Copies directories and subdirectories, including empty ones.
Same as /S /E. May be used to modify /T.
Same as /S /E. is a confusing description. Many beginners think it is necessary to specify /S and /E to get entire directory structure with empty directories copied. But this is not true. It is meant that just /E is enough to copy an entire directory structure with including empty directories and /S /E is interpreted like just /E. It is superfluous to specify /S (copy without empty directories) in addition to /E (copy with empty directories) on XCOPY command line.
I recommend reading the SS64 - XCOPY documentation which is currently better than Microsoft's documentation.
Very important on copying one or more files and directories with XCOPY into a specified destination directory is specifying the destination path with a backslash at end. This makes it clear for XCOPY that the destination string specifies a directory and not a file. Otherwise it is necessary to specify additionally /I on copying multiple files or an entire directory tree to inform XCOPY that the destination argument should be interpreted as folder path. But /I does not avoid a prompt if a single file is copied with XCOPY and the destination argument does not end with a backslash, see BATCH file asks for file or folder for details. Therefore it is highly recommended to specify destination folder path always with a backslash at end on copying one or more files to a folder using XCOPY.
I currently use this code to copy shortcuts from a folder on a server to C:\Users\Desktop:
if not exist "%1" md "%1"
copy /y "%~dp0PlaceShortcutsHere\*.*" "%1"
This copies any shortcuts I place in the folder to the desktop.
I now need a way to remove these, baring in mind that the shortcuts in the source folder can and will change over time.
Is there a way to compare the shortcuts in the desktop and on the server and only delete the ones that are present in both folders, and only from the desktop of the computer?
These shortcuts are not all of the shortcuts on the desktop of the machines, there are others as well, hence wanting to only delete the ones present in both locations. I will also need this to be adaptive as the shortcuts present on the server will be added to or removed as needed.
This is to be deployed out through SCCM 2007/12 but I want to test it locally first.
And yes, using a GP would be easier but the GP we use has stopped working so I need a backup way of deploying shortcuts.
Took some time but I've found an answer myself. Posting this if it is useful to anyone in the future.
dir "%~dp0PlaceShortcutsHere\*" /a /b /-p /o:gen>>"%~dp0ShortcutList_%date:~-4,4%%date:~-7,2%%date:~-10,2%.txt"
Pushd \\<Server>\<Share>
for /F "delims=" %%G in (ShortcutList_%date:~-4,4%%date:~-7,2%%date:~-10,2%.txt) DO Del "C:\Users\Public\Desktop\%%G"
del "%~dp0ShortcutList_%date:~-4,4%%date:~-7,2%%date:~-10,2%.txt"
Breaking it down:
dir "%~dp0PlaceShortcutsHere\*" /a /b /-p /o:gen>>"%~dp0ShortcutList_%date:~-4,4%%date:~-7,2%%date:~-10,2%.txt"
The above created a text file with the names of the shortcuts in it for referencing by the next line.
Pushd \\<Server>\<Share>
for /F "delims=" %%G in (ShortcutList_%date:~-4,4%%date:~-7,2%%date:~-10,2%.txt) DO Del "C:\Users\Public\Desktop\%%G"
The above maps the server/share that the files are in temporarily, then uses the "For /F" loop to get the file names and then delete them.
del "%~dp0ShortcutList_%date:~-4,4%%date:~-7,2%%date:~-10,2%.txt"
Finally, this line deleted the text file that was created.
This is useful for when the contents of the folder is always changing, it will create an up to date list of the files and then delete the list afterwards, preventing confusion.
%date:~-4,4%%date:~-7,2%%date:~-10,2%
Lastly, this little line will input the current date into the filename of the text documet, so should the final delete line not work you can see the date on it. At a guess I would also think that putting it in paths will make the script only choose the files from the current day, not any others, but I have not tested this.
Please correct me if I'm wrong on anything.
New to batch scripting..
I want to copy files from one folder(A) to another folder(B) continuously. The other software "moves" files from folder B. My script with Xcopy is continuously copying files from A to B. But When the copied files are moved from B, script is copying again the same files to B. Script should copy files from A to B only once.
You could have shown us the script and made things easier.
From the prompt, execute
xcopy /?
to show xcopy options.
I'd suggest the /d option would do what you need.
Every file has an archive attribute. This attribute was created to determine when a file needs to be copied (well, more or less). By default, files are generated with this attribute set and any change to the file will set it again.
xcopy includes two switches: /a and /m that handle this attribute.
/a tells xcopy to only copy files that have the archive attribute set
/m tells xcopy to only copy files that have the archive attribute set and clear the attribute
You should try something like xcopy /m "c:\sourceA\*" "c:\targetB" This will copy files with the archive attribute set and remove the attribute from the archive.
I'm wondering if it is possible to set up a batch command to perform this action.
Once .bat file is executed, ALL images from folders and sub-folders would be copied to my location on the desktop.
Example:
Original folder is located:
\intranet\file_location\PP Complete Images (in this folder will be loads of other folders and in those folders there will be .jpg images)
Destination file would be based on the desktop.
So I need to extract .jpg images from all folders and sub-folders.
If image already exists in original folder, skip the image or overwrite as script will be executed every morning.
Or should I look for a software to do this for me?
Existing code:
cd c:
cd\
copy "\\intranet\PP Complete Images\Master Image Folder*.jpg" "C:\Users\username\Desktop\Master Image Folder"
copy "\\intranet\PP Complete Images*.jpg"
exit
How do you want it?
It isn't quite clear to me, how the result exactly should be -- should it be flattened or should it be hierarchical as well?
Look at this for example:
source
folder-1
folder-1-1
image1.jpg
folder-1-2
image2.jpg
cheese.jpg
image3.jpg
some_text.txt
folder-2
folder-2-1
image3.jpg
some_music.mp3
cheese.jpg
target
Should the result be basically a copy of the shown hierarchy (without any other file than the jpgs), or should it be a flattened result like this one:
source
... (see above)
target
image1.jpg
image2.jpg
cheese.jpg
image3.jpg
image3.jpg
How can you do it?
Flattened
You can use DOS' for command to walk directories1 and make a custom function2 to handle the files:
#ECHO OFF
for /r %%f in (*.jpg) do call:copyFile %%f
GOTO END
:copyFile
copy /V /-Y %~1 ..\target
GOTO:EOF
:END
Meaning: for every %%f in the listing of *.jpg from the current working dir, execute function copyFile. The /r switch makes the listing recursing (walk through all subdirectories).
In the function, the argument passed to it (now known as %~1) is passed to the copy function: Copy the file to the target directory which is ..\target in this case. /V lets copy verify the result, /-Y lets it ask for permission to overwrite files. See copy /?!
Very big problem: If you have one or more files in different subfolders of your source directory, which have the same name (like the two cheese.jpgs in my example), you will loose data!
So, I wouldn't recommend this approach, as you risk loosing data (digital cameras are not very creative in naming pictures!).
Hierarchical
Just use robocopy:
robocopy /S <sourcedir> <targetdir> *.jpg
/S creates and copys subfolders as well. You can also use /DCOPY:T to make the directories have the same timestamp than the original ones or /L to preview the actions of robocopy.
Small problem: The /E switch handles subfolders as well, even if they are empty. /S handles subfolders as well, but not, if they are empty. But it handles them, if they are not empty, but have no JPG inside -- so, subfolders without JPGs will result in empty folders in the target folder.
Robocopy has loads of parameters, so check out robocopy /?.
Hope this helps! :-)
1Found here: How to traverse folder tree/subtrees in a windows batch file?
2Found here: http://www.dostips.com/DtTutoFunctions.php
Your existing code:
the cd c: is incorrect. To switch the current drive to c: use
c:
The cd \ is redundant. Your remaining code specifies the directories, so the current directory is irrelevant.
Your first copy command has three problems. Master Image Folder*.jpg means all filenames beginning Master Image Folder and ending .jpg. You probably meant Master Image Folder\*.jpg meaning all files ending .jpg in ...\Master Image Folder\
C:\Users\username\Deskto... is probably an error. It is a literal path, so the actual directory would be C:\Users\username\Deskto... You would probably need C:\Users\%username%\Deskto... to substitute-in the current username.
And then the job would stop on a filename-match, so either you'd be pressing A to overwrite all or you'd be pressing y or n for each name-match.
Your final copy command has no specified destination directory.
You can edit-in your actual code by using the edit button under the original text window, cutting-and-pasting your actual code - censoring if necessary, selecting the resultant code block and pressing the {} button above the edit box which indents each line with the effect of formatting and hilighting the code.
The simplest solution is probably to use
xcopy /d /y /s "\\intranet\PP Complete Images\Master Image Folder\*.jpg" "C:\Users\%username%\Desktop\Master Image Folder\"
which will copy updated files (/d) with automatic overwrite (/y) and scanning subdirectories (/s) from-name/mask to-directory.
This would create an identical directory-hierarchy to the original subtree under the destop's Master Image Folder directory.
You could extend this to
for %%a in (
"\\intranet\PP Complete Images\Master Image Folder"
"\\intranet\wherever\somewhere"
) do xcopy /d /y /s "%~a\*.jpg" "C:\Users\%username%\Desktop\Master Image Folder\"
to perform the same action on multiple directory-subtrees; but you need to ensure that the destination directory is not within any subtree selected for inclusion in the list within the parentheses.
I'd advise against "flattening" the output because if you do that, the latest whatever.jpg from each of the subtrees will end up in your destination directory, without notification that there are many possibly different whatever.jpg versions.
I do believe the solution to your problem would be Robocopy.
Robocopy is just plain awesome!
Here is the syntax of robocopy-
robocopy [Source] [Destination] [File] [...] [options]
Source
Specifies the source folder. Where you want to take the files from.
Destination
Destination directory/folder.
File
Here we are! This is what will help you. Here you can specify an extension you want to move. So in your case, your code would look somewhat like this.
robocopy *.jpg c:\destinationdir /S /MAX:1048576
*To execute this .bat every morning go to a program called task scheduler, dont worry, its built into windows. http://windows.microsoft.com/en-US/windows/schedule-task#1TC=windows-7
*Then Click on Create basic task, and set your task to whenever you like!
Thanks guys for your help!!!
I got it solved and there is a code below if someone would ever need something similar:
pushd Z:\intranet\PP Complete Images\
for /r %%a in (*.jpg) do (
XCOPY /Y "%%a" "C:\Users\username\Desktop\Master Image Folder"
)
popd
I have a strange problem with xcopy in Windows XP Professional. I don't know if its a stupid question as I am specifying only a file as the source, so should I even expect any other behavior ? This is it:
I am using xcopy <src> <dest> /s/y.
<src>=C:\sourcefolder\a\b\c\d\something.java and
<dest>=C:\destinationfolder.
Now xcopy copies the file but does not create the directory structure \a\b\c\d\ inside C:\destinationfolder .
what I want is C:\destinationfolder\a\b\c\d\something.java and
what I get is C:\destinationfolder\something.java
I have tried to run it in destination folder C:\destinationfolder by specifying a . for target folder
Tried it without any target in above
There is a script I have which calls xcopy iteratively so I am left with C:\destinationfolder\many java files without any directory structure.
A. Yes I have done xcopy /? to see all options
B. /T also does not create any empty directory structure
C. I can not go to source folder a\b\c\d\ and run xcopy . <dest>
UPDATE
I removed my previous answer on using ROBOCOPY. I believe the following will do what you want using XCOPY.
Assuming your folder structure is like this:
SOURCE = C:\MyJavaStuff\A\B\C\D\something.java
DEST = C:\MyDestination
Run XCOPY like this:
XCOPY C:\MyJavaStuff\something*.java C:\MyDestination /S /E
Note the * in something*.java.
The problem is that you are specifying which file to copy in the source. xcopy won't create the folder structure in this case. However, if you change your call to xcopy to
xcopy *.java C:\myfolder /s/y
it will copy the .java files and the folder structure as well. You need to specify a wildcard for this call to work as you want. If you want only to copy specific files, you will have to adjust the call to xopy, e.g.:
xcopy something.jav* C:\myfolder /s/y
Edit
You say that you get the list of files to copy from another command. If you can output this list of files in a text file, you could do the following:
FOR /F "tokens=* delims=," %F in (d:\test\list.txt) DO xcopy src\%~nxF* .\dest /S /Y
What this command does is read a text file ("d:\test\list.txt" in this case), read every line, and for each file, run xcopy, adding a wildcard at the end of the file name to make sure it creates the folder structure.
I'm assuming here that:
You can get the list of files in a text file, with only the file names (and optinally the paths)
You know the source folder ("C:\sourcefolder" in your example, the folder structure "a\b\c\d" does not need to be known) and can use it in the FOR command.
You can also use the following form:
FOR /F "tokens=* delims=," %F in ('cmd') DO xcopy src\%~nxF* .\dest /S /Y
where cmd needs to be replace with the command you use to generate your list of files to copy.
Note that if you use this FOR command in a batch file, you need to replace %F with %%F (and %~nxF* with %%~nxF*).
I had a look at the xcopy switches and you can copy the directory structure with /T, although that doesn't copy empty directories you can override this with /E. So your command would look like this:
xcopy C:\sourcefolder\a\b\c\d\something.java C:\destinationfolder /T /E /S /Y
Hope this helps!
In order to get C:\destinationfolder\a\b\c\d\something.java XCOPY needs to know how much of C:\sourcefolder\a\b\c\d\something.java to duplicate.
You can use:
C:
cd \sourcefolder
XCOPY something.java* C:\destinationfolder\ /S
Just be aware that this may have the side effect of also copying C:\sourcefolder\oops\something.java to C:\destinationfolder\oops\something.java as well as any other matches for something*.java under C:\sourcefolder\.
It seems to me that xcopy is typically used for copying directory trees, not single files (though it can work). And, xcopy will recreate the directory structure under the source folder in the target folder. If xcopy is given the /i switch, the target folder is assumed to be a directory. It will be created if it does not exist, even if there are multiple parents that need to be created.
You have C:\MyJavaStuff\A\B\C\D\something.java - that is your source. You want to end up with something.java not in C:\destinationfolder, but in C:\destinationfolder\A\B\C\D - so that is your target. You don't even have C:\destinationfolder. That is OK, with /i the entire path will be created.
xcopy /i c:\MyJavaStuff\A\B\C\D\something.java C:\destinationfolder\A\B\C\D
If something.java were the only file under C:\MyJavaStuff, you could also use
xcopy /sei c:\MyJavaStuff C:\destinationfolder
That would recreate the entire tree structure, copying your file. But if there are other files (and folders) under MyJavaStuff they would also be copied.
I have written a very similar batch file using xcopy. Perhaps what I did will help you.
This is the command I used:
xcopy "c:\Data Files\Dave's Data\*.*" "m:\Dave's Data" /R/D /E/H
In this case, Dave's Data on the source contains an entire directory tree containing at least 50,000 files & exceeding 75GB data. It runs perfectly on Windows XP
I found /T was unnecessary as the directory tree is copied. I also found /S was unnecessary as /E copied directories & sub-directories including empty ones. I included /R to copy & overwrite read only files on the destination. /H copied hidden directories. /D copied only newer files. I use this as a daily backup tool for my data.
The only problem I have is while this command will work on Windows 7 the first time, it will not work on subsequent runs when the destination directory tree exists. I suspect this is due to a privilege issue as the xcopy command will work on subsequent runs on Windows 7 within a cmd.exe window.