Running Windows 7, when I copy a file to an external disk, during a routine file backup, I use Powershell v2 (run from a batch file) to re-create on the copy file all the timestamps of the original file.
The following code works successfully in most cases, but not always:-
SET file=%1
SET dest=E:\
COPY /V /Y %file% "%dest%"
SetLocal EnableDelayedExpansion
FOR /F "usebackq delims==" %%A IN ('%file%') DO (
SET fpath=%%~dpA
SET fname=%%~nxA
)
PowerShell.exe (Get-Item \"%dest%\%fname%\").CreationTime=$(Get-Item \"%fpath%%fname%\" ^| Select-Object -ExpandProperty CreationTime ^| Get-Date -f \"MM-dd-yyyy HH:mm:ss\")
The above code copies the file, then sets the creation date/time on the copy (destination) file to that of the source file, when I drag-and-drop the source file onto my batch file.
But there are some cases where the code fails. If the filename contains a 'poison' character, such as (for example) square brackets [...], it gives the error "Property 'CreationTime' cannot be found on this object". Parsing of the filename clearly fails at the 'poison' character.
The code does not give an error with symbols such as &.
I have tried a whole load of variations of escaping the Powershell command using both single and double quotes, but without success. Please can someone tell me how to escape those characters which Powershell objects to.
This is only a small section of a much longer batch routine, on which I rely in doing regular system backups. I don't have an option to switch to a .ps1 file instead, so I need a solution which works within a batch file, not in a .ps1 file.
Thanks for all suggestions.
ADDENDUM: I found a solution, by adopting one suggestion kindly supplied by mklement0. My problem with square brackets was overcome by substituting the following command for my original Powershell command -
PowerShell.exe (Get-Item -LiteralPath \"%dest%\%fname%\").CreationTime=$(Get-Item -LiteralPath \"%fpath%%fname%\" ^| Select-Object -ExpandProperty CreationTime ^| Get-Date -f \"MM-dd-yyyy HH:mm:ss\")
For future reference, please note that (on Windows 7):
The use of this revised command succeeds in preserving any extra whitespace characters. It is not necessary to include an extra pair of double-quote characters to achieve that.
- Editor's note: It's an edge case, but worth pointing out: without extra enclosing double quotes, any runs of more than one space are folded into one space; e.g.,
powershell.exe -command echo \"a b\"yieldsa b.
Enclosing the entire command in"..."helps in principle -
powershell.exe -command "echo \"a b\""- but sincecmd.exethen doesn't recognize the overall string as a single, double-quoted string, metacharacters can break the command; e.g.,
powershell.exe -command "echo \"a & b\""
- Editor's note: It's an edge case, but worth pointing out: without extra enclosing double quotes, any runs of more than one space are folded into one space; e.g.,
It is not possible for the file path to include any " (double quote) character, so no code is required to escape that character. The double quote character is an illegal character in the FAT and NTFS filesystems, so can never be encountered in a file's path.
It is bad in principle to use ' (single quote) in the Powershell command, because that character is NOT illegal in the NTFS file system, so could be found in an actual path to a file. Use of double-quotes must be preferred, because the double-quote character, being illegal, can NEVER be encountered in an actual NTFS path.
With ROBOCOPY, the following wildcard solution succeeds even with most poison characters - all except ! (i.e. it can cope with = & ` ^). This command is pretty robust EVEN if there is more than one poison character (though not foolproof):
ROBOCOPY "%fpath% " "%dest%" "*%name%*%ext%*" /B /COPY:DAT /XJ /SL /R:0 /W:0 /Va. The whitespace in "%fpath% " is ESSENTIAL, it is NOT an error.
b. The only poison character fatal in all circumstances is the EXCLAMATION MARK (!).
c. Poison characters only seem to be a problem in the FILENAME, not in the Path.