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.
Related
I'm working in a windows 7 machine and I'm trying to take all of the files matching the names in a list of file paths (I have the list saved as a csv, rda, and can make a txt file if needed). Ie: the list looks like:
Y:/iglgrelkgjkrle/originals/jsfhdjk.xls
Y:/iglgrelkgjkrddsle/ffhej/originals/jsfhdjk.xlsx
Y:/kssrldsse/ffhej/originals/jsfhdjk.xlt
Y:/blahblah/blah/blahhh/blahhhhhh/originals/blahahaha.pdf
...
...
And basically I want all of these files in this list copied to a new folder in a different location. Thanks!
Almost any problem can be solved with a FOR statement in windows command processor. Using for /f we can search a list in a text document and for each item (This case; location) specified, can run a command to copy it to a new location.
For copying the file, xcopy will be very handy as it has many copy option switches we can use such as /i /z /y.
/I - If in doubt always assume the destination is a folder
/Z - Copy files in restartable mode. If the copy is interrupted part way through,
it will restart if possible.
/Y - Suppress prompt to confirm overwriting a file. (Use /-Y for reverse)
In the following commands bellow, C:\list.txt is used as an example. This is where you specify the location of your list file. This can support a wide range of file formats including html. It does not hurt to try your extensions.
For the place to output the copied files - C:\CopyFolder is an example of the location of the folder you wish to send them too. You can also send them to a local server via \\server\folder\.
From command Line:
for /f "delims=" %i in (C:\list.txt) do (xcopy "%i" "C:\CopyFolder" /i /z /y)
From batch file:
for /f "delims=" %%i in (C:\list.txt) do (xcopy "%%i" "C:\CopyFolder" /i /z /y)
If this has solved your issue, please don't forget to mark this response as solved. I will be happy to further explain any questions!
EDIT: To clarify what I'm looking to do is move a few files into a data folder of an application. The application is installed into Program Files but it keeps data inside app data. The folder name looks something like this
76053ADAJSQDUC4975
Problem is that it's unique to every instance of the application installed and for every computer that will be using this batch. So I'm in the directory and it has
1AKDHCI4985HF55GHJKB G5586HJFRUK56885KOQQ
The only way to identify the folders is by a .txt file inside each one called
origin.txt
that shows the file path to the applications installation directory (C:/Program Files(x86)/********) on one line.
I figured I can use a for to loop through, find the the file, and read it. What I don't know how to do, is find the right file, and cd to its directory. The second problem is since this batch file will be used by multiple users, not all of their installation paths are the same. So inside .txt it could be C:/, D:/, Program Files or Program Files(x86) so the only thing useful to me is the last several words. How would I go about being selective like that.
I'm currently traveling so can't answer right away but would appreciate if you guys help me out or point me in the right directions. Thanks
First, if the application is installed with an installer which adds something to Windows registry for knowing itself on next run (update/upgrade/uninstall) which version of the application is already installed and into which directory if installed at all, it is better to evaluate this information in registry instead of searching around in file system. See my answer on Locate if the program exists and set a custom variable in batch windows.
Second, with assuming text file origin.txt can be found anywhere within application data directory of current user containing only once (or last) the string :\ as part of the directory with the program files of the application, the following batch code could be used to get the directory path and make it the current directory.
#echo off
set "ApplicationDirectory="
for /F "delims=" %%I in ('dir /A-D /B /S "%APPDATA%\origin.txt" 2^>nul') do (
for /F "delims=" %%D in ('%SystemRoot%\System32\findstr.exe /C:":\\" "%%~I" 2^>nul' ) do (
if exist "%%~D" (
set "ApplicationDirectory=%%~D"
goto ChangeDirectory
)
)
)
echo Could not determine directory of application.
goto :EOF
:ChangeDirectory
cd /D "%ApplicationDirectory%"
echo Directory is: %ApplicationDirectory%
set "ApplicationDirectory="
The first FOR loop uses command DIR to search in all subdirectories of user related application data directory for the file origin.txt. The inner FOR loop is processed if there is at least one such file found.
The inner FOR loop calls FINDSTR to search in found origin.txt for all lines containing the literal string :\ and processes all found lines.
For each line returned by FINDSTR the inner FOR loop checks if there is a directory (or file) using the entire string of the line containing :\.
Both loops are exited immediately on a positive check on existence of directory (or file) with a jump to label ChangeDirectory with the commands to switch the current directory independent on current drive and echoing the found application directory.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
cd /?
dir /?
findstr /?
for /?
goto /?
if /?
set /?
Note: I strongly recommend to run FINDSTR with a better search string or perhaps even a regular expression than just :\ if file origin.txt could contain multiple paths.
I ended up using
set "ApplicationDirectory="
for /r "%appdata%" %%a in (origin.txt*) do find "thewordsiwaslookingfor" <"%%a" >nul && set "ApplicationDirectory=%%~dpa"
Then I used ApplicationDirectory to be able to move some files into that directory.
Which worked perfectly, for what I was trying to do.
I am absolutely brand new to any kind of development but need a batch job to copy a file from one folder to another.
The problem is that the source folder is dynamically named. The folder name will contain the current date and a suffix number (eg. "TestRun_20141106_13") - so I will never be able to determine the 'latest' version of the folder before running the batch / copy job.
Can anyone help please? I know this will be easy for someone but as I said, I am a complete noob!!
Thanks in advance.
Jamie
Yes, I havent been doing .bat for that long either, but i think i can help!
Here is a code for the movement of the file!
Dealing wiwth dynamically named folder...
#echo off
set /p txtfile=Filename without Path assumes c:\:
echo.%txtfile%
copy %txtfile% z:\testing\dealer.txt
echo Come back to this window when Agent is done with process. The copy file will be deleted.
#pause
copy %txtfile% c:\somefolder\namedsuccess\%txtfile%
del z:\testing\dealer.txt
exit
You will have to place your own variables in there my friend!
For moving of the files!
Easy part!
move /-y "Folder Path that files are in*(Any specific keyword?)*" "(Dest. folder)"
#ECHO OFF
FOR /F "TOKENS=*" %%A IN ('DIR "C:\Example" /s /b /a:d') DO SET CurrentDir=%%A
#ECHO.%CurrentDir%
Replace "C:\Example" with the Path your Folders are in,
save it to a File (.bat/.cmd) and execute.
The last step - Echo will return the most bottom foldername.
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
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!