PowerShell copy fails without warning PowerShell copy fails without warning powershell powershell

PowerShell copy fails without warning


Anytime you're having problems trying to figure out why a parameter doesn't bind correctly in PowerShell, use Trace-Command like so:

Trace-Command -Name ParameterBinding -expr { copy-item $f foo.cat.bak } -PSHost

In this case, it works for me. Perhaps this is a "feature" of PowerShell 2.0 but you can see it attempt to bind several different times before it hits on:

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]

The way this normally works when the FileInfo objects are passed via the pipeline, they bind by "PropertyName" to the LiteralPath parameter. I know, you're probably wondering, uh didn't think System.IO.FileInfo had a LiteralPath property. Heheh, it doesn't. Those tricky PowerShell folks snuck a PSPath alias onto the LiteralPath parameter and PowerShell "adapts" each the FileInfo object to add a number of PS* properties including PSPath. So if you wanted to "literally" match the pipelining behavior you would use:

Copy-Item -LiteralPath $f.PSPath $targetDir -force

Note that you don't have to quote $targetDir in this case (as a parameter argument).


The reason why copy-item doesn't work is that you pass System.IO.FileInfo as parameter -path.There are two possibilities how to do it correctly:

  1. copy-item -literal $f.Fullname -destination ...
  2. $f | copy-item -destination ...

Note that I use parameter -literalPath because files in the temp folder have usually [ and ] inside the name which acts as wildcards characters.

If you wonder why case #2 works, have a look at 'help Copy-Item -Parameter Path`, you will see Accept pipeline input? true (ByValue, ByPropertyName). For more info what it means look at Keith's ebook Effective Windows PowerShell.

Why you version doesn't work? Because paramerer -path (which is at position 1) takes input of type [string[]] and not FileInfo. So PowerShell tried to convert it to [string] (and then to the array) but it probably used only Name property. You can try it like this:

[string[]] (gci | select -first 1)