В Windows 7, когда я копирую файл на внешний диск, во время обычного резервного копирования файла я использую Powershell v2 (запуск из пакетного файла), чтобы воссоздать в файле копии все временные метки исходного файла.
Следующий код успешно работает в большинстве случаев, но не всегда:
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\")
Приведенный выше код копирует файл, а затем устанавливает дату/время создания копии (целевого) файла в исходный файл, когда я перетаскиваю исходный файл в свой пакетный файл.
Но бывают случаи, когда код не работает. Если имя файла содержит «ядовитый» символ, такой как (например) квадратные скобки [...], возникает ошибка «Свойство «CreationTime» не может быть найдено в этом объекте< /эм>". Синтаксический анализ имени файла явно не работает на символе «яд».
Код не выдает ошибку с такими символами, как &.
Я пробовал целую кучу вариантов экранирования команды Powershell, используя как одинарные, так и двойные кавычки, но безуспешно. Пожалуйста, может кто-нибудь сказать мне, как избежать тех символов, против которых возражает Powershell.
Это лишь небольшая часть гораздо более длинной пакетной процедуры, на которую я полагаюсь при регулярном резервном копировании системы. Вместо этого у меня нет возможности переключиться на файл .ps1, поэтому мне нужно решение, которое работает в пакетном файле, а не в файле .ps1.
Спасибо за все предложения.
ДОПОЛНЕНИЕ: я нашел решение, приняв одно предложение, любезно предоставленное mklement0. Моя проблема с квадратными скобками была решена путем замены моей исходной команды Powershell следующей командой:
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\")
Для справки в будущем обратите внимание на следующее (в Windows 7):
Использование этой измененной команды позволяет сохранить любые лишние пробельные символы. Для этого нет необходимости включать дополнительную пару символов двойных кавычек.
- 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.exe
then 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.,
Невозможно, чтобы путь к файлу содержал какой-либо символ " (двойная кавычка), поэтому код для экранирования этого символа не требуется. Символ двойной кавычки является недопустимым символом в файловых системах FAT и NTFS, поэтому никогда не может встречаться в пути к файлу.
В принципе, плохо использовать ' (одинарную кавычку) в команде Powershell, потому что этот символ НЕ является недопустимым в файловой системе NTFS, поэтому его можно найти в фактическом пути к файлу. Использование двойных кавычек должно быть предпочтительным, потому что символ двойных кавычек, будучи недопустимым, НИКОГДА не может быть обнаружен в фактическом пути NTFS.
С ROBOCOPY следующее решение с подстановочными знаками успешно работает даже с большинством подозрительных символов — со всеми, кроме ! (т. е. оно может справиться с = & ` ^). Эта команда довольно надежна, ДАЖЕ если имеется больше символа отравления (хотя и не надежная):
ROBOCOPY "%fpath% " "%dest%" "*%name%*%ext%*" /B /COPY:DAT /XJ /SL /R:0 /W:0 /V
а. Пробел в "%fpath%" НЕОБХОДИМ, это НЕ ошибка.
б. Единственный символ яда, смертельный при любых обстоятельствах, — это ВОСКРЕСИТЕЛЬНЫЙ ЗНАК (!).
в. Ядовитые символы кажутся проблемой только в ИМЯ ФАЙЛА, а не в пути.
"%path% "
: проблема в том, чтоrobocopy
обрабатывает\"
в конце аргумента как экранированный"
, что прерывает команду. Строго говоря, правильное решение состоит в том, чтобы удвоить конечный\
(например,"E:\\"
), но вы можете обойтись без добавления пробела, потому что любой конечный пробел в путях < я>проигнорировано. Таким образом, простой способ сделать такие вызовы надежными — всегда использовать"%var% "
(конечный пробел перед закрывающей двойной кавычкой) при передаче путей к папкам. Я обновил свой ответ соответственно. - person mklement0   schedule 18.08.2017robocopy
поддерживает подстановочные знаки только в аргументахfile
(имя файла), но не вsource
иdestination
(папка) аргументы; пути к папкам всегда обрабатываются как литералы. - person mklement0   schedule 18.08.2017!
проблематичен только потому, что вы используетеenabledelayedexpansion
- без него!
будет рассматриваться как литерал. Какие еще метасимволы вызывают проблемы? - person mklement0   schedule 18.08.2017=
внутри командного файла, но нужно ли вам быть осторожным при вызове его со значением, содержащим=
: всегда двойные кавычки такие пути, даже если они не содержат встроенных пробелов или других метасимволов; например,someBatchFile "c:\tmp\foo=bar.txt"
. Без двойных кавычек=
действует как разделитель аргументов, точно так же, как и пробелы, и в итоге вы непреднамеренно передаете 2 аргумента,c:\tmp\foo
иbar.txt
. Это также применимо, когда вы передаете значение через переменную: используйтеsomeBatchFile "%file%"
. - person mklement0   schedule 19.08.2017