2

I'm looking for help in creating a script that can rename all of the files contained in a directory to a table referenced in a csv file. For example, I have a folder with random file names and I also have a csv file with the current file names in column A, and what the actual file name should be changed to in column B.

I thought about using something along the lines of:

get-childitem *pdf -force | foreach { rename-item $_ $_.Name.Replace((Import-Csv -path .\List.csv).filename, (Import-Csv -Path .\List.csv).newfilename) }

Note that filename & newfilename refer to column A and B respectively.

Nothing really happens when I run this script. I'm a novice with powershell so I've come to the limits of my knowledge of how to accomplish this task. Any and all help will be greatly appreciated!

Thank you all!

Ric.Mart
  • 31
  • 1
  • 4
  • Does the CSV file contain full paths of the files or just the file names? – AdminOfThings Dec 30 '19 at 15:23
  • @AdminOfThings just the file names, but I could modify the spreadsheet to contain the file paths (for both current and new names) as well. – Ric.Mart Dec 30 '19 at 15:29
  • Does this answer your question? [Powershell - find file by 'file name' and rename based on CSV](https://stackoverflow.com/questions/34287924/powershell-find-file-by-file-name-and-rename-based-on-csv) – Theo Dec 30 '19 at 16:19
  • @Theo Not really, I went through that post and the answers didn't really do much for my current scenario – Ric.Mart Jan 02 '20 at 23:15

3 Answers3

3

You can do the following if you are in the directory that contains the target files and the CSV file. This assumes you have headers in your CSV named filename and newfilename.

$TargetDir = Resolve-Path -Path .
Import-Csv -Path .\List.csv | Foreach-Object {
    $Src = Join-Path -Path $TargetDir -ChildPath $_.filename
    $Dst = Join-Path -Path $TargetDir -ChildPath $_.newfilename
    Rename-Item -Path $Src -NewName $Dst
}

If the target directory is another location, you can simply modify the Join-Path statements to use -Path.

$TargetDir = 'c:\folder'
Import-Csv -Path .\List.csv | Foreach-Object {
    $Src = Join-Path -Path $TargetDir -ChildPath $_.filename
    $Dst = Join-Path -Path $TargetDir -ChildPath $_.newfilename
    Rename-Item -Path $Src -NewName $Dst
}

Note: If the CSV file does not contain headers, you will need to either utilize the -Header switch in Import-Csv like in Glenn's helpful answer or add the column headers to the CSV.

AdminOfThings
  • 23,946
  • 4
  • 17
  • 27
  • Better answer than mine. – Glenn Dec 30 '19 at 15:35
  • There are elements to both answers that are useful. – AdminOfThings Dec 30 '19 at 15:37
  • Sorry gentlemen, there must be something I'm doing wrong or have different in the spreadsheet. I ran this script and got the following error message: Rename-Item : Cannot rename the item at 'C:\Users\ZZZZZZ\Desktop\Name Testing' because it is in use. At line:4 char:5 + Rename-Item -Path $Src -NewName $Dst – Ric.Mart Dec 30 '19 at 15:54
  • @Ric.Mart I made some code edits to make the experience more similar in the two approaches. – AdminOfThings Dec 30 '19 at 19:18
0

Assuming there's no header in the .csv and it only contains the file names, this might work for you:

# Only import the CSV once
$csvData = Import-Csv .\List.csv -Header "Old","New"

# Remove the -WhatIf after testing
Get-ChildItem | ForEach-Object { 
    $file = $_
    $csvData | Where-Object { 
        $_.Old -eq $file.Name 
    } | ForEach-Object { 
        Rename-Item -Path $file -NewName $_.New -WhatIf 
    } 
}

Or a more concise implementation:

$csvData = Import-Csv .\List.csv -Header "Old","New"
dir | %{ $file = $_; $csvData | ?{ $_.Old -eq $file.Name } | %{ Rename-Item -Path $file -NewName $_.New -WhatIf } }
Glenn
  • 1,687
  • 15
  • 21
  • I ran the script with and without the -whatif parameter and it doesn't look like anything happened. Should I include headers like "Old" and "New"? – Ric.Mart Dec 30 '19 at 15:50
  • there was a mistake in my last edit (had `%{ $_.Old -eq $file.Name }` instead of `?{ $_.Old -eq $file.Name }`). If you still don't see any output, it may not be finding a match for the filenames. – Glenn Dec 30 '19 at 16:54
  • Here's a screenshot of example with some test data I threw together: https://i.imgur.com/6nvOBjc.png – Glenn Dec 30 '19 at 16:56
0

================ NEW ANSWER WITH A SIMPLE SCRIPT ================

Tested on MacOS:

Just create a file named map.csv and format it like this:

old_file1.txt,new_file1.txt
old_file2.txt,new_file2.txt
old_file3.txt,new_file3.txt

create a shell script rename.sh and change the variables folder_path, csv_file and file_extension:

#!/bin/bash

folder_path="path/to/your/files/"
csv_file="path/to/map/file/map.csv"
file_extension=".jpg"

while IFS=',' read -r old_file new_file
do
  mv "${folder_path}/${old_file}${file_extension}" "${folder_path}/${new_file}${file_extension}"
  echo "File ${old_file}${file_extension} renamed to ${new_file}${file_extension}."
done < "$csv_file"

start the script with sh rename.sh

and enjoy the magic ;-)

krupar
  • 349
  • 3
  • 5