Copy Files Based on CSV input file (Import-CSV, Copy-Item)

Copper Contributor

I am admittedly unskilled in Powershell, I hail from the old DOS copy *.* era. I have a number of hours into this but struggling.

 

I have a mapped drive with a deep file explorer hierarchy from which I wish to retrieve PDF files to a local folder, modify in batch and return, overwriting the original.

 

The structure looks similar to this:  Y:\Company\Clients\A-D\[client]\[YYYY]\Folder\*organizer.pdf

YYYY is a year

 

I already have a CSV file which contains the folder path and file name in separate columns.

 

I will have about 500 lines and will expect to perform this task annually. Some manipulation to the CSV is acceptable (concatenate, etc) if this simplifies the process.

 

I have been able to Copy-Item "path\file' -Destination "path\file" for a single line.

 

I seem to be able to import the CSV (Import-CSV) and can (Format-Table) to verify the imported fields, though it's truncated in the display (I hope).

 

I am failing attempting to For-Each my way through the Copy-Item process. I suspect I am missing something in the syntax.

 

 

=========================
Code for FILE and PATH
=========================
#Import the CSV
$CSVData = Import-CSV -Path "D:\Organizer-2023\Organizer2022test2.csv"

#Get the data in Table-like format
$CSVData | Format-Table

# Select specific columns from the pipeline
$SpecificData = $CSVData | Select-Object PATH, FILE

# Display the data in Table format
$SpecificData | Format-Table

# Display the file to the local folder
ForEach ($Row in $CSVData) {
    Copy-Item "($Row.Path)($Row.file)" -Destination "D:\Organizer-2023\($Row.file)"
}

 

 

 

================
RETURNED OUTPUT
================

Copy-Item : Cannot find drive. A drive with the name '(@{File=2022 Individual ALB2047 (Albert, Michael S.)
Organizer.pdf; Path=Y' does not exist.
At line:2 char:5
+     Copy-Item "($Row.Path),($Row.file)" -Destination "D:\Organizer-20 ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: ((@{File=2022 In...zer.pdf; Path=Y:String) [Copy-Item], DriveNotFoundExc
   eption
    + FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
    

 

Thank you!

6 Replies

@RangerZ Does this work?

 

=========================
Code for FILE and PATH
=========================
#Import the CSV
$CSVData = Import-CSV -Path "D:\Organizer-2023\Organizer2022test2.csv"

#Get the data in Table-like format
$CSVData | Format-Table

# Select specific columns from the pipeline
$SpecificData = $CSVData | Select-Object PATH, FILE

# Display the data in Table format
$SpecificData | Format-Table

# Display the file to the local folder
ForEach ($Row in $CSVData) {
    Copy-Item "$($Row.Path)$($Row.file)" -Destination "D:\Organizer-2023\$($Row.file)"
}

@Harm_VeenstraThank you!

 

The code changes work great! 

 

It failed the first time, but highlighted an error in the CSV that I did not see with the original code.  My PATH values did not include a trailing "\".  The path just ended in FOLDER as opposed to FOLDER\, so when joined with the file name the path was not valid.  After clean up, I tried it with the old code and it still failed.  With yours I copied about 530 files in under 5 minutes!!  Thank you!!

 

I have 2 additional questions please. 

 

As noted above, I will reverse the source and destination to restore the modified file to it's original location.  I think I want to append -Force to the end.  I tested this by rerunning the above with -Force expecting to see the Created Time change to a more current time but did not.  So I am unclear if this is correct or not, and is there an easy way to make the process verbose, for example list the file name's as it runs just so I can see it's doing something real. 

 

Can you offer a reference or would you speak to the use of the additional $ in the syntax please.

 

@RangerZ 

 

Hey, Steve.

 

If you're asking about the additional $ in line 18:

 

 

Copy-Item "$($Row.Path)$($Row.file)" -Destination "D:\Organizer-2023\$($Row.file)"

 

 

Then it's to symbolise enclosed code.

 

So, where you had "()", that did not symbolise that the content within the ellipses was to be interpreted as code.

 

Conversely, "$()" says to PowerShell, "treat the stuff within the ellipses as code".

 

This is important as if you look at your original format of:

 

"($Row.Path)"

 

Then what you get is the value of the $Row object with the string literal of ".Path" appended to it, which is not what you had in mind.

 

If you use Harm's format of:

 

"$($Row.Path)"

 

Then what you get is the value of the $Row.Path property within the $Row object, which is what you had intended.

 

On another note, if you're looking to make your "Copy" command more resilient to the presence or omission of leading/trailing backslashes, you can use to the built-in Join-Path commandlet. Taking this approach means you do not have to worry so much about the format of your CSV file.

 

 

Copy-Item -Path (Join-Path -Path $Row.Path -ChildPath $Row.file) -Destination (Join-Path -Path "D:\Organizer-2023\" -ChildPath $Row.file);

 

 

Join-Path examples

LainRobertson_0-1703043465513.png

 

 

Cheers,

Lain

@LainRobertsonThanks for your information and additional code suggestions


The Join-Path component is very interesting.  I have already downloaded my files, but will need to send them back, so I will test this, but probably not until the weekend. 

 

The first thing that jumps out at me is that the expression looses the $() symbol in it's entirety.

 

I have now tested the -Force, and it does appear to work as desired, but I would still be interested to know if I can append some "output" parameter after force that says it created Row.FILE in the PowerShell display, or even the number of records written at the end would be good. 

@RangerZ 

 

Hi, Steven.

 

Using the -Verbose parameter on your Copy-Item is the only parameter of note.

 

If you want more verbosity than that, you'll need to code your own tracking of statistics, errors and so on.

 

Cheers,

Lain

@LainRobertson @Harm_Veenstra 

Thank you both for your input. 

 

I think I now have this working with both -Force and -Verbose, which gives just what I want for feedback.