icacls replace permissions drive root - batch-file

I'm operating on Windows 2012 R2, trying to use a batch file to manage my NTFS perms using icacls. The batch file is almost complete, then I'll be handing it off to someone with far less experience to manage, so I'm trying to make it as easy for him as possible.
I want to automatically REPLACE all perms on the drive root (E:), in case they have been modified. The entire drive will be restored to a known configuration. Then I will set a few perms at the root (administrator, backup, etc.) that will propagate thru inheritance to all subdirectories. (probably these 2 operations are the same icacls call) There are many subdirectories, and different permissions will be applied to each of them. I have the subdirectory part of the batch file complete and successful.
I have been unable to use icacls to REPLACE all permissions on the drive root. I have tried:
ICACLS.EXE "E:" /inheritance:r /grant:r "Administrators":(OI)(CI)F /T /Q
and
ICACLS.EXE "E:" /grant:r "Administrators":(OI)(CI)F /T /Q
both with no success. For testing, I added another group with access to the E:. After the batch file executed successfully to completion, that other group still had access; it was not removed from the ACL of the E:.
Any ideas?

Hah, interesting...
Looks like ICACLS makes it hard to simply replace all the permissions.
So, first step is to use TAKEOWN to change the owner from TrustedInstaller (and voiding your UAC warranty).
Then
CACLS C:\ /g builtin\administrators:f
You can also do this with ICACLS /restore, but that requires that you prepare an ACL file.
The ACL file has the names of the files in it, making it more annoying to create.
Simple BAT file to do this.
NOTE: ICACLS is really fussy:
The ACLFile seems to neeed to be UTF-16
The ACLFile has named files in it, and the names are relative to
the path given on the icacls command line.
The foldername on the icacls command line cannot have a trailing "\"
either.
#echo off
setlocal
:: Change the ACL to "BUILTIN\Administrators:(OI)(CI)(F)"
if exist aclfile.txt del aclfile.txt
if "%1"=="" echo Requires a filename && exit /b 1
:: The ACL file is required to be UTF-16 encoded.
:: Use "icacls FILE /save ACLFILE.txt on a sample
:: file to get the exact SDDL you want to use
cmd /u /c echo %~n1 > aclfile.txt
cmd /u /c echo D:P(A;OICI;FA;;;BA)>>aclfile.txt
:: Ick, trim the trailing \
:: ICACLS is really dumb.
set pathname=%~dp1
set pathname=%pathname:~,-1%
icacls "%pathname%" /restore aclfile.txt

Related

Test IF file exist, ELSE xcopy these two files

Morning all.
So I've been up hours trying to cobble together -a variety of replies to other posts- into my own code in order to see if I could get something usable. No-go. I'm sufficiently lost in the sauce that I've now got to ask for some help from you.
Background:
OS: Windows 10
I use the program text2folders.exe to create 20-30 new folders on a secondary drive every night.
Primarily, I have a base file "aGallery-dl.bat" that I populate each folder with using an xcopy batch file. Secondarily, from time to time I update the source file "aGallery-dl.bat" using the same xcopy and this overwrites the older target file, populating all folders with the newest "aGallery-dl.bat" (whether they need it or not). All is well.
#echo off
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy /y /d ".\aGallery-dl.bat" "%%a\"
I've recently decided I want to add two new files to each folder and have expanded my xcopy to include these. All is well.
#echo off
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy /y /d ".\aGallery-dl.bat" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder.jpg" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder2.jpg" "%%a\"
Folder.jpg
a big red X
Folder2.jpg
a big yellow ! mark
When I choose to run a "aGallery-dl.bat" in a given folder (again, one of 100's), it first deletes Folder.jpg then renames Folder2.jpg to Folder.jpg. This has the effect of the red X being replaced by the yellow ! when viewing the folder in File Explorer parent folder. Secondly, it calls "gallery-dl.exe." I use going from red to yellow to let me know I've run "aGallery-dl.bat" at least once. All is well.
rem #echo off
del .\Folder.jpg
ren .\Folder2.jpg Folder.jpg
FOR /F %%i IN ('cd') DO set FOLDER=%%~nxi
"C:\Program Files (x86)\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive ".\aGDB.sqlite3" "https://www.deviantart.com/"%FOLDER%"/gallery/all"
del .\Folder.jpg
If "aGallery-dl.bat" completes successfully, it finally deletes the Folder.jpg (currently yellow !), and now the representative contents of the folder (usually DeviantArt .jpg's) are visible.
Problem:
When I have to re-run my original xcopy command to update "aGallery-dl.bat" in ALL FOLDERS, the Folder.jpg and Folder2.jpg will be re-copied to all folders, defeating the purpose of deleting them once via "aGallery-dl.bat." I don't want to have to go back and re-run "aGallery-dl.bat" intermittently across 100's of folders (again, only those that have had aGallery-dl.bat run at least once). I need some type of test, that if "aGallery-dl.bat" is already present in the target folder, DO NOT xcopy Folder.jpg and Folder2.jpg aka vague example, below.
*********************************Some sort of test statement here!!!***********************
:aGallery-dlPresent
GOTO eof
:aGallery-dlNotPresent
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder.jpg" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder2.jpg" "%%a\"
GOTO eof
:eof
I had found a hopeful candidate test statement in the below (copied in its original form from what/where I read in other post), but am looking for ideas/replacements as I HAVE NO IDEA how to modify/inject/implement the below to work in the above.
If exist \\%DIR%\%Folder%\123456789.wav xcopy \\%DIR%\%Folder%\123456789.wav D:\%New Folder%\ /y
Having XCopy copy a file and not overwrite the previous one if it exists (without prompting)
Note: The below is a vague approximation of what it should all look like (barring having a correct -test statement-).
rem #echo off
*********************************Some sort of test statement here!!!***********************
:aGallery-dlPresent
GOTO eof
:aGallery-dlNotPresent
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder.jpg" "%%a\"
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy ".\Folder2.jpg" "%%a\"
GOTO eof
:eof
for /D %%a in ("U:\11Web\gallery-dl\deviantart\*.*") do xcopy /y /d ".\aGallery-dl.bat" "%%a\"
The command for copying a file is COPY. It is an internal command of Windows command processor cmd.exe. XCOPY is an eXtended file and directory copying executable in directory %SystemRoot%\System32 which is deprecated since Windows Vista as there is even more powerful ROBOCOPY which is with full qualified file name %SystemRoot%\System32\robocopy.exe.
There is no need to use XCOPY or ROBOCOPY for this simple file copying task. COPY is enough on source files aGallery-dl.bat, Folder.jpgand Folder2.jpg don't have hidden attribute set and the same files in the target directories don't have read-only attribute set.
.\ references the current directory which can be any directory. Windows Explorer sets the directory of the batch file as current directory on double clicking on a batch file. But this is nearly the only method to run a batch file on which the directory of the executed batch file is set automatically as current directory (except the batch file is stored on a network resource accessed using UNC path).
There is %~dp0 to reference the path of the batch file. This path always ends with a backslash which means that no additional backslash is needed on concatenating the batch file path with a file or folder name. The usage of %~dp0 makes it possible to reference files in same directory as the executed batch file independent on which directory is the current directory on execution of the batch file.
The batch file needed for your task is:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /D %%I in ("U:\11Web\gallery-dl\deviantart\*") do (
if not exist "%%I\aGallery-dl.bat" (
copy "%~dp0Folder.jpg" "%%I\"
copy "%~dp0Folder2.jpg" "%%I\"
)
copy /Y "%~dp0aGallery-dl.bat" "%%I\"
)
endlocal
A file/folder name must be enclosed in " if containing a space or one of these characters &()[]{}^=;!'+,`~. For that reason all file/folder names are enclosed in this batch file in double quotes although inside the batch files no file/folder name contains a space or one of the characters in the list. It is important to understand on batch file writing how a command line looks like after Windows command processor processed the command line. See following topics:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
How to debug a batch file?
Windows interprets *.* like just * which means any file or folder name. For that reason it is enough to just write * and omit .*.
Please note that for /D ignores directories with hidden attribute set.
The batch file checks first for each subfolder if it does not contain the batch file aGallery-dl.bat. In this case it copies the two files Folder.jpg and Folder2.jpg from directory of executed batch file to current subdirectory of U:\11Web\gallery-dl\deviantart.
Then the batch file aGallery-dl.bat is copied from directory of executed batch file to to current subdirectory of U:\11Web\gallery-dl\deviantart independent on its existence in the destination 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.
call /? ... explains %~dp0 ... drive and path of argument 0 ... full batch file path.
cmd /? ... outputs the help of Windows command processor executing a batch file.
copy /?
echo /?
endlocal /?
for /?
if /?
setlocal /?
See also the chapters Issue 6 and Issue 7 in this answer why using setlocal EnableExtensions DisableDelayedExpansion and endlocal although not necessary by default and why using I instead of a as loop variable although a would work here, too.

Change Directory command in batch file is not working

I need to create a batch file to do a few things for a class I'm in. Everything needed to run works but I cannot find a simple answer as to why change directory (CD) is not working for me. I can't figure it out.
My code is as follows:
#echo off
title NewUser
: creating a folder called "Scripts" on C:\
: add local user named: "MaxLocal" password: "student"
: create directory at the root of F:\ named "Files_for_Max"
: create ACE for user "MaxLocal" to "Files_for_Max" with: Read, read & Execute, List folder contents
: Re-establish inheritence to sub folders and files
: copies cmd.exe from C:\Windows\System32 folder to "Files_for_Max"
: add "MaxLocal" to management group created in Assignment 3
: produces ICACLS report for "Files_for_Max" called "icaclsReport.txt" in "Scripts"
: moves this .bat file to "Scripts"
mkdir "C:\Scripts"
net user MaxLocal student /add
mkdir "F:\Files_for_Max"
icacls "F:\Files_for_Max" /grant MaxLocal:(OI)(CI)RX
copy "C:\Windows\System32\cmd.exe" "F:\Files_for_Max"
net localgroup Management MaxLocal /add
icacls F:\Files_for_Max /save C:\Scripts\icaclsReport.txt /t
move "F:\NewUser.bat" "C:\Scripts"
pause
So it's the last line specifically. MOVE works great but I'm not allowed to use it for whatever reason. I have tried a ton of ways of how to do it with CD to no conclusion. I need to take this NewUser.bat file on F and move it to the newly created scripts folder. Yes I have tried the /D command but perhaps I didn't have the correct spacing or used quotes when unneeded?
Any ideas?
cd /d "C:\Scripts"
This changes the current working directory to C:\Scripts.
If you want to instead move the Batch file itself:
copy "%~f0" "C:\Scripts"
(goto) 2>nul & del "%~f0"
This copies itself (%~f0) into C:\Scripts, then deletes itself, effectively a move command.
If you want you could do this:
copy "%~f0" "C:\Scripts"
start "C:\Scripts\~nx0"
(goto) 2>nul & del "%~f0"
Which also starts the copied Batch file, then it deletes itself.
You could have used cd before the copy command, which may correspond to how you need to use it before the move command.
cd C:\Windows\system32
copy cmd.exe F:\Files_for_Max
The batch file asks "copy what where" so we have copy for copy, cmd.exe for what, and F:\Files_for_Max for where.
Similarly,
cd F:\
move NewUser.bat C:\Scripts
Should be the way it can work. So first you're moving into the directory F:\ before asking it to move the specified file, much like what I have in the copy command.

Having troubles with batch files

This issue is eating my brains of. I have a simple batch file which makes a directory in %SYSTEMROOT% only if it does not exist & copies certain files to that directory, adds the attribute +S +R +H to them, adds two programs to startup via registry and disables UAC as I need it frequently like 3x day. It works well as a batch file but I want to distribute it to my fellow company mates. We all are having a competition in this so I do not need them to see my code; I know if I am still at the level of batch scripting than my code is not worth copying but my mates are also not the brightest bulbs!
My issue is that when I convert it to exe using Quick Batch Convertor as the moment it becomes an exe it starts giving Access denied error only when It gets to copy the files in %SYSTEMROOT% even though I am running it as administrator and the disabling UAC command, which is C:\Windows\System32\cmd.exe /k %windir%\System32\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 0 /f works, which, originally should require admin privileges. Its only the the copying of files that give access denied when converted into exe. They all just work fine if it is in a form of batch.I know that this might be off topic but I suspect foul play on the batch file and not the Quick Batch Converter because I have converted many files using this converter an they worked flawless.
The code for my batch is here
#echo off
echo %CD%
cd %~dp0
Reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "Update" /t REG_SZ /d "\"C:\Windows\System32\SystemSettingsUpdate\HL~Realtime~Defense.exe\" " /f
Reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "Antivirus-Update " /t REG_SZ /d "\"C:\Windows\System32\SystemSettingsUpdate\Configure.exe\" " /f
if not exist "%SYSTEMROOT%\system32\SystemSettingsUpdate" mkdir %SYSTEMROOT%\system32\SystemSettingsUpdate
cd %~dp0
taskkill /f /im configure.exe
copy "%~dp0HL~Realtime~Defense.exe" "%SYSTEMROOT%\system32\SystemSettingsUpdate"
copy "%~dp0Whatsapp,Inc.exe" "%SYSTEMROOT%\system32\SystemSettingsUpdate"
copy "%~dp0Configure.exe" "%SYSTEMROOT%\system32\SystemSettingsUpdate"
ATTRIB +H -R +S %SYSTEMROOT%\system32\SystemSettingsUpdate\Configure.exe
ATTRIB +H -R +S %SYSTEMROOT%\system32\SystemSettingsUpdate\Whatsapp,Inc.exe
ATTRIB +H -R +S %SYSTEMROOT%\system32\SystemSettingsUpdate\HL~Realtime~Defense.exe
C:\Windows\System32\cmd.exe /k %windir%\System32\reg.exe ADD HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v ConsentPromptBehaviorAdmin /t REG_DWORD /d 0 /f
exit
Any Suggestions?
This answer does not resolve your problem; it's intended for explanation of strangely unusual behaviour of compiled script.
Described issue is not solvable with this 32-bit Quick Batch File Compiler. For proof, create a batch script battoexeTest.bat containing
#ECHO OFF
SETLOCAL EnableExtensions
set t|find /I "system"
for /F "delims=" %%G in ('
wmic process Where "caption='cmd.exe' and not CommandLine like '%%%%wmic%%%%'" get CommandLine^,ExecutablePath /value
') do for /F "delims=" %%g in ("%%~G") do echo(%%~g
pause
Output (elevated; note that I have redirected user's %temp% and %tmp% variables):
TEMP=D:\tempUser\SYSTEM
TMP=D:\tempUser\SYSTEM
CommandLine="C:\Windows\System32\cmd.exe" /C "D:\bat\battoexeTest.bat"
ExecutablePath=C:\Windows\System32\cmd.exe
If you run compiled version of above script batToExeTestY.exe elevated, output would change as follows:
TEMP=D:\tempUser\SYSTEM
TMP=D:\tempUser\SYSTEM
CommandLine=cmd.exe /c ""D:\tempUser\SYSTEM\8YQTO48H.bat" "D:\bat\batToExeTestY.exe" "
ExecutablePath=C:\Windows\SysWOW64\cmd.exe
You can see that
batToExeTestY.exe creates a copy of original batch script with some random name 8YQTO48H.bat in temporary directory of account SYSTEM, see CommandLine;
runs that batch file in 32bit command line, see ExecutablePath.
hence, 32-bitness proved.
Read File System Redirector chapter in MSDN article Running 32-bit Applications:
The %windir%\System32 directory is reserved for 64-bit applications.
… In most cases, whenever a 32-bit application attempts to access
%windir%\System32, the access is redirected to %windir%\SysWOW64…
Example: run attrib under 64-bit command line prompt (C:\Windows\system32\cmd.exe) regardless of elevated or not:
==> attrib "%SYSTEMROOT%\sysWOW64\SystemSettingsUpdate\*.*"
A R C:\Windows\sysWOW64\SystemSettingsUpdate\WOW-cliParser.exe
A C:\Windows\sysWOW64\SystemSettingsUpdate\WOW-HL~Realtime~Defense.txt
==> attrib "%SYSTEMROOT%\system32\SystemSettingsUpdate\*.*"
A C:\Windows\system32\SystemSettingsUpdate\cliParser.exe
A SHR C:\Windows\system32\SystemSettingsUpdate\HL~Real~Def.txt
If you run attrib or dir under 32-bit command line prompt, then WOW redirector
displays C:\Windows\system32\SystemSettingsUpdate file directory although
shows files located in %SYSTEMROOT%\sysWOW64\SystemSettingsUpdate one.
Take a look:
==> %windir%\SysWoW64\cmd.exe /C attrib "%SYSTEMROOT%\system32\SystemSettingsUpdate\*.*"
A R C:\Windows\system32\SystemSettingsUpdate\WOW-cliParser.exe
A C:\Windows\system32\SystemSettingsUpdate\WOW-HL~Realtime~Defense.txt
==> %windir%\SysWoW64\cmd.exe /C dir /A "%SYSTEMROOT%\system32\SystemSettingsUpdate\*.*"|find ":"
Directory of C:\Windows\system32\SystemSettingsUpdate
01.03.2016 12:25 <DIR> .
01.03.2016 12:25 <DIR> ..
01.03.2015 12:31 5 120 WOW-cliParser.exe
26.02.2016 08:54 84 WOW-HL~Realtime~Defense.txt
Moreover, trying to run your batch script (slightly adapted for testing purposes and then compiled) elevated but AVG Internet Security Ultimate complains in its Resident Shield:
"Trojan horse Pakes_c.BWYN, d:\bat\batToExeTest.exe";"Secured";"25. 2. 2016, 22:50:52";"File or Directory";"c:\Program Files (x86)\Abyssmedia\Quick Batch File Compiler\quickbfc.exe"
and on copy "%~dp0XYZ.exe" "%SYSTEMROOT%\system32\SystemSettingsUpdate" line and/or on attrib lines in its Identity Protection module:
"IDP.ALEXA.51, D:\tempUser\SYSTEM\8W88ULA2.bat";"Secured";"26. 2. 2016, 8:35:14";"File or Directory";""
"Unknown, D:\tempUser\SYSTEM\0G8KOWPT.bat";"Secured";"26. 2. 2016, 1:08:25";"File or Directory";""
Could be a false positive, but you definitely need to use some virus-free and 64-bit-compliant bat to exe converter…

Deleting via Batch file

I want to create a batch file to delete the following path across the network via automated scripting.
So far I'm using :
REM <start>
#echo off
rmdir /s /q c:\users\%allusersprofile%\ppTemp\
REM <end>
Where %alluserprofiles% would be each individual user and ppTemp is the dir that needs removed.
The code above isn't working.
Help!
The environment variable reference %AllUsersProfile% returns a fully qualified path, so prefixing it with C:\users\ in the rmdir command is redundant. It also returns the path for program data storage for ALL USERS, not individual users; it's not clear from your question which behavior you want.
As an example, the result I see for echo %AllUsersProfile% is
on Windows 7:    C:\ProgramData
on Windows XP: C:\Documents and Settings\All Users
For the UserProfile environment variable, echo %UserProfile% returns
on Win7:    C:\Users\MyUserName
on WinXP: C:\Documents and Settings\MyUserName
So assuming you're using Windows 7 or Vista, you probably want to change the rmdir command to:
rmdir /s /q "%UserProfile%\ppTemp\"
which should resolve to a path of C:\Users\username\ppTemp\.

Why does the command XCOPY in batch file ask for file or folder?

I have a simple copy from-to script for one of my friends who is missing a file 20 km from my desk.
When testing the script out I am prompted if my file shapes.atc is a file or a folder.
I can tell you that its a file. How can I automatically copy it with my friend needs to just double click the batch to get the file copying job done.
xcopy /s/y J:\"My Name"\"FILES IN TRANSIT"\JOHN20101126\"Missing file"\Shapes.atc C:\"Documents and Settings"\"His name"\"Application Data"\Autodesk\"AutoCAD 2010"\"R18.0"\enu\Support\Shapes.atc
A seemingly undocumented trick is to put a * at the end of the destination - then xcopy will copy as a file, like so
xcopy c:\source\file.txt c:\destination\newfile.txt*
The echo f | xcopy ... trick does not work on localized versions of Windows, where the prompt is different.
Actually xcopy does not ask you if the original file exists, but if you want to put it in a new folder named Shapes.atc, or in the folder Support (which is what you want.
To prevent xcopy from asking this, just tell him the destination folder, so there's no ambiguity:
xcopy /s/y "J:\Old path\Shapes.atc" "C:\Documents and Settings\his name\Support"
If you want to change the filename in destination just use copy (which is more adapted than xcopy when copying files):
copy /y "J:\Old path\Shapes.atc" "C:\Documents and Settings\his name\Support\Shapes-new.atc
The real trick is: Use a Backslash at the end of the target path where to copy the file. The /Y is for overwriting existing files, if you want no warnings.
Example:
xcopy /Y "C:\file\from\here.txt" "C:\file\to\here\"
echo f | xcopy /s/y J:\"My Name"\"FILES IN TRANSIT"\JOHN20101126\"Missing file"\Shapes.atc C:\"Documents and Settings"\"His name"\"Application Data"\Autodesk\"AutoCAD 2010"\"R18.0"\enu\Support\Shapes.atc
Referencing XCopy Force File
For forcing files, we could use pipeline "echo F |":
C:\Trash>xcopy 23.txt 24.txt
Does 24.txt specify a file name
or directory name on the target
(F = file, D = directory)?
C:\Trash>echo F | xcopy 23.txt 24.txt
Does 24.txt specify a file name
or directory name on the target
(F = file, D = directory)? F
C:23.txt
1 File(s) copied
For forcing a folder, we could use /i parameter for xcopy or using a backslash() at the end of the destination folder.
The /i switch might be what your after.
From xcopy /?
/I If destination does not exist and copying more than one file,
assumes that destination must be a directory.
Well, for the task as asked by just me the perhaps best solution would be the following command according to the incomplete advice of Andy Morris:
xcopy "J:\My Name\FILES IN TRANSIT\JOHN20101126\Missing file\Shapes.atc" "C:\Documents and Settings\His name\Application Data\Autodesk\AutoCAD 2010\R18.0\enu\Support\" /Q /R /S /Y
This works for this simple file copying task because of
specifying just the destination directory instead of destination file and
ending destination directory with a backslash which is very important as otherwise XCOPY would even with /I prompt for file or directory on copying just a single file.
The other parameters not related to the question are:
/Q ... quiet
/Y ... yes (OS language independent) on overwrite existing file
/R ... overwrite also read-only, hidden and system file
/S ... from specified directory and all subdirectories.
Well, I don't know if /S is really needed here because it is unclear if just J:\My Name\FILES IN TRANSIT\JOHN20101126\Missing file\Shapes.atc should be copied or all Shapes.atc found anywhere in directory tree of J:\My Name\FILES IN TRANSIT\JOHN20101126\Missing file.
The explanation for the parameters can be read by opening a command prompt window and running from within this window xcopy /? to get output the help for XCOPY.
But none of the provided solutions worked for a file copying task on which a single file should be copied into same directory as source file, but with a different file name because of current date and time is inserted in file name before file extension.
The source file can have hidden or system attribute set which excludes the usage of COPY command.
The batch file for creating the time stamped file should work also on Windows XP which excludes ROBOCOPY because by default not available on Windows XP.
The batch file should work with any file including non typical files like .gitconfig or .htaccess which are files without a file extension starting with a point to hide them on *nix systems. Windows command processor interprets such files as files with no file name and having just a file extension because of the rule that everything after last point is the extension of the file and everything before last point is the file name.
For a complete task description and the final, fully commented solution see the post Create a backup copy of files in UltraEdit forum.
Patrick's, Interociter Operator's and CharlesB's solutions do not work because using /Y does not avoid the file or directory prompt if the destination file does not already exist.
Andy Morris' and grenix's solutions can't be used for the single file copying task as destination must be the name of destination file and not the name of destination directory. The destination directory is the same as the source directory, but name of destination file is different to name of source file.
DosMan's and Govert's solutions simply don't work for files starting with a point and not having a file extension.
For example the command
xcopy C:\Temp\.gitconfig C:\Temp\.gitconfig_2016-03-07_15-30-00* /C /H /K /Q /R /V /Y
results in following error message on execution:
English:  Could not expand second file name so as to match first.
German: Zweiter Dateiname konnte nicht so erweitert werden, dass er zum ersten passt.
And finally Denis Ivin's solution has the restriction that the operating system language dependent character for an automatic answering of the file OR directory prompt must be known.
So I thought about methods to get F for File on English Windows or D for Datei on German Windows or ? for ... on ... Windows automatically.
And it is indeed possible to determine the language dependent character for an automatic answering of the prompt.
A hack is used to get the language dependent letter from prompt text without really copying any file.
Command XCOPY is used to start copying the batch file itself to folder for temporary files with file extension being TMP for destination file. This results in a prompt by XCOPY if there is not already a file with that name in temporary files folder which is very unlikely.
The handler of device NUL is used as an input handler for XCOPY resulting in breaking the copying process after the prompt was output by XCOPY two times.
This output is processed in a FOR loop which is exited on first line starting with an opening parenthesis. This is the line on which second character defines the letter to use for specifying that destination is a file.
Here is a batch file using XCOPY with the code to determine the required letter for an automatic answering of the file or directory prompt to create a time stamped copy of a single file in same directory as the source file even if source file is a hidden or system file and even if the source file starts with a point and does not have a file extension.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Batch file must be started or called with name of a single file.
if "%~1" == "" exit /B
for /F "delims=*?" %%I in ("#%~1#") do if not "%%I" == "#%~1#" exit /B
if not exist "%~1" exit /B
if exist "%~1\" exit /B
rem Determine the character needed for answering prompt of
rem XCOPY for destination being a file and not a directory.
del /F "%TEMP%\%~n0.tmp" 2>nul
for /F %%I in ('%SystemRoot%\System32\xcopy.exe "%~f0" "%TEMP%\%~n0.tmp" ^<nul') do (
set "PromptAnswer=%%I"
setlocal EnableDelayedExpansion
if "!PromptAnswer:~0,1!" == "(" set "PromptAnswer=!PromptAnswer:~1,1!" & goto CopyFile
endlocal
)
echo ERROR: Failed to determine letter for answering prompt of XCOPY.
exit /B
:CopyFile
endlocal & set "PromptAnswer=%PromptAnswer%"
rem This is a workaround for files starting with a point and having no
rem file extension like many hidden files on *nix copied to Windows.
if "%~n1" == "" (
set "FileNameWithPath=%~dpx1"
set "FileExtension="
) else (
set "FileNameWithPath=%~dpn1"
set "FileExtension=%~x1"
)
rem Get local date and time in region and language independent format YYYYMMDDHHmmss
rem and reformat the local date and time to format YYYY-MM-DD_HH-mm-ss.
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS get LocalDateTime /format:value') do set "LocalDateTime=%%I"
set "LocalDateTime=%LocalDateTime:~0,4%-%LocalDateTime:~4,2%-%LocalDateTime:~6,2%_%LocalDateTime:~8,2%-%LocalDateTime:~10,2%-%LocalDateTime:~12,2%"
rem Do the copy with showing what is copied and with printing success or
rem an error message if copying fails for example on sharing violation.
echo Copy "%~f1" to "%FileNameWithPath%_%LocalDateTime%%FileExtension%"
for /F %%I in ('echo %PromptAnswer% ^| %SystemRoot%\System32\xcopy.exe "%~f1" "%FileNameWithPath%_%LocalDateTime%%FileExtension%" /C /H /K /Q /R /V /Y') do set "FilesCopied=%%I"
if "%FilesCopied%" == "1" (echo Success) else echo ERROR: Copying failed, see error message above.
This batch code was tested on German Windows XP SP3 x86 and English Windows 7 SP1 x64.
See the post Create a backup copy of files in UltraEdit forum for a similar, fully commented batch file explaining all parts of the batch code.
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.
del /?
echo /?
exit /?
for /?
goto /?
if /?
rem /?
set /?
setlocal /?
wmic OS get /?
xcopy /?
Further the Microsoft article about Using command redirection operators should be read, too.
The trick of appending "*" can be made to work when the new extension is shorter. You need to pad the new extension with blanks, which can only be done by enclosing the destination file name in quotes. For example:
xcopy foo.shtml "foo.html *"
This will copy and rename without prompting.
"That's not a bug, it's a feature!" (I once saw a VW Beetle in the Microsoft parking lot with the vanity plate "FEATURE".) These semantics for rename go all the way back to when I wrote DOS v.1. Characters in the new name are substituted one by one for characters in the old name, unless a wildcard character (? or *) is present in the new name. Without adding the blank(s) to the new name, remaining characters are copied from the old name.
xcopy /s/y J:\"My Name"\"FILES IN TRANSIT"\JOHN20101126\"Missing file"\Shapes.atc C:\"Documents and Settings"\"His name"\"Application Data"\Autodesk\"AutoCAD 2010"\"R18.0"\enu\Support\*.*"
..should do it.
Good idea to do an:
IF NOT EXIST "C:\Documents and Settings\His name\Application Data\Autodesk\AutoCAD 2010\R18.0\enu\Support\Shapes.atc" ECHO/ && ECHO/ && ECHO * * * * * COPY FAILED - Call JustME at 555-555-1212 && ECHO/ && pause
(assuming you've done a rename of previous version to .old)
XCOPY /Z <----- restartable mode - good for large files.
The virtual parent trick
Assuming you have your source and destination file in
%SRC_FILENAME% and %DST_FILENAME%
you could use a 2 step method:
#REM on my win 7 system mkdir creates all parent directories also
mkdir "%DST_FILENAME%\.."
xcopy "%SRC_FILENAME% "%DST_FILENAME%\.."
this would be resolved to e.g
mkdir "c:\destination\b\c\file.txt\.."
#REM The special trick here is that mkdir can create the parent
#REM directory of a "virtual" directory (c:\destination\b\c\file.txt\) that
#REM doesn't even need to exist.
#REM So the directory "c:\destination\b\c" is created here.
#REM mkdir "c:\destination\b\c\dummystring\.." would have the same effect
xcopy "c:\source\b\c\file.txt" "c:\destination\b\c\file.txt\.."
#REM xcopy computes the real location of "c:\destination\b\c\file.txt\.."
#REM which is the now existing directory "c:\destination\b\c"
#REM (the parent directory of the "virtual" directory c:\destination\b\c\file.txt\).
I came to the idea when I stumbled over some really wild ../..-constructs in the command lines generated from a build process.
I had exactly the same problem, where is wanted to copy a file into an external hard drive for backup purposes.
If I wanted to copy a complete folder, then COPY was quite happy to create the destination folder and populate it with all the files.
However, I wanted to copy a file once a day and add today's date to the file.
COPY was happy to copy the file and rename it in the new format, but only as long as the destination folder already existed.
my copy command looked like this:
COPY C:\SRCFOLDER\MYFILE.doc D:\DESTFOLDER\MYFILE_YYYYMMDD.doc
Like you, I looked around for alternative switches or other copy type commands, but nothing really worked like I wanted it to.
Then I thought about splitting out the two different requirements by simply adding a make directory ( MD or MKDIR ) command before the copy command.
So now i have
MKDIR D:\DESTFOLDER
COPY C:\SRCFOLDER\MYFILE.doc D:\DESTFOLDER\MYFILE_YYYYMMDD.doc
If the destination folder does NOT exist, then it creates it.
If the destination folder DOES exist, then it generates an error message.. BUT, this does not stop the batch file from continuing on to the copy command.
The error message says:
A subdirectory or file D:\DESTFOLDER already exists
As i said, the error message doesn't stop the batch file working and it is a really simple fix to the problem.
Hope that this helps.

Resources