Search code examples
powershellcsvcopy-item

Copying files to specific folder declared in a CSV file using Powershell Script


i am quite new to powershell and i am trying to make a script that copy files to certain folders that are declared in a CSV file. But till now i am getting errors from everywhere and can't find nothing to resolve this issue.

I have this folders and .txt files created in the same folder as the script.

Till now i could only do this:

$files = Import-Csv .\files.csv 
$files
 foreach ($file in $files) {
    $name = $file.name
    $final = $file.destination
    Copy-Item $name -Destination $final   
  }

This is my CSV

name;destination
file1.txt;folderX
file2.txt;folderY
file3.txt;folderZ


Solution

  • As the comments indicate, if you are not using default system delimiters, you should make sure to specify them.

    I also recommend typically to use quotes for your csv to ensure no problems with accidentally including an entry that includes the delimiter in the name.

    @"
    "taco1.txt";"C:\temp\taco2;.txt"
    "@ | ConvertFrom-CSV -Delimiter ';' -Header @('file','destination')
    

    will output

    file      destination
    ----      -----------
    taco1.txt C:\temp\taco2;.txt
    

    The quotes make sure the values are correctly interpreted. And yes... you can name a file foobar;test..txt. Never underestimate what users might do. 😁

    If you take the command Get-ChildItem | Select-Object BaseName,Directory | ConvertTo-CSV -NoTypeInformation and review the output, you should see it quoted like this.

    Sourcing Your File List

    One last tip. Most of the time I've come across a CSV for file input lists a CSV hasn't been needed. Consider looking at grabbing the files you in your script itself.

    For example, if you have a folder and need to filter the list down, you can do this on the fly very easily in PowerShell by using Get-ChildItem.

    For example:

    $Directory = 'C:\temp'
    $Destination = $ENV:TEMP
    Get-ChildItem -Path $Directory -Filter *.txt -Recurse | Copy-Item -Destination $Destination
    

    If you need to have more granular matching control, consider using the Where-Object cmdlet and doing something like this:

    Get-ChildItem -Path $Directory -Filter *.txt -Recurse | Where-Object Name -match '(taco)|(burrito)' | Copy-Item -Destination $Destination
    

    Often you'll find that you can easily use this type of filtering to keep CSV and input files out of the solution.

    example

    Using techniques like this, you might be able to get files from 2 directories, filter the match, and copy all in a short statement like this:

    Get-ChildItem -Path 'C:\temp' -Filter '*.xlsx' -Recurse | Where-Object Name -match 'taco' | Copy-Item -Destination $ENV:TEMP -Verbose
    

    Hope that gives you some other ideas! Welcome to Stack Overflow. 👋