Каждый раз, когда у вас возникают проблемы с попыткой выяснить, почему параметр не связывается правильно в PowerShell, используйте Trace-Command следующим образом:
Trace-Command -Name ParameterBinding -expr { copy-item $f foo.cat.bak } -PSHost
В этом случае это работает для меня. Возможно, это «особенность» PowerShell 2.0, но вы можете увидеть, как он пытается связать несколько раз, прежде чем он попадет на:
COERCE arg to [System.String]
Trying to convert argument value from System.Management.Automation.PSObject to System.String
CONVERT arg type to param type using LanguagePrimitives.ConvertTo
CONVERT SUCCESSFUL using LanguagePrimitives.ConvertTo: [C:\Users\Keith\foo.cat]
То, как это обычно работает, когда объекты FileInfo передаются через конвейер, они привязываются посредством «PropertyName» к параметру LiteralPath. Я знаю, вы, вероятно, задаетесь вопросом, вы не думали, что System.IO.FileInfo имеет свойство LiteralPath. Хехех, это не так. Эти хитрые люди PowerShell добавили псевдоним PSPath к параметру LiteralPath, и PowerShell «адаптирует» каждый объект FileInfo для добавления ряда свойств PS *, включая PSPath. Поэтому, если вы хотите «буквально» соответствовать конвейерному поведению, вы должны использовать:
Copy-Item -LiteralPath $f.PSPath $targetDir -force
Обратите внимание, что в этом случае вам не нужно заключать в кавычки $ targetDir (в качестве аргумента параметра).