Home > OS >  Renaming several files using CSV in Powershell
Renaming several files using CSV in Powershell

Time:04-15

I have a special need and I feel stuck on that.. Some user will put some file in a directory with several different name, and I need to rename them regarding a special pattern for those files to be consume by another app.

Example:

In directory -> Target

file1-dd-mm-yyyy -> file1

file2 -> thisfile2

flie45224 -> file123

So as you can see this can be some variables, dates, ID etc.. The target will always be the same but the file in source can be different because of date for example.

So first I had 2 files, so I write the script in plain text "If test-path blabla do this else go out" but it seems that now I will have 37 different files with all differents name. So I thought about using an excel sheet(CSV?), but I can't really find any help on this need.

The goal is to have a sheet as "pattern" like if you found file like in 'A1' then rename as in 'A2' etc... Do you guys have an idea ?

Thanks by advance :)

CodePudding user response:

I understand you need a csv with the following columns:

  • A1: regex/pattern to match
  • A2: transform rule which should be dynamic

The trick is to use scriptblock if you want to use variables like the file name.

Basically, your csv will be:

A1;A2
"^file1-\d\d-\d\d-\d\d\d\d$";"file1"
"^file2$";"this$($file.Name)"
"^flie*";"file123"

And the code would be:

$myRules = Import-Csv "C:\xxx\test.csv" -Delimiter ";"

$files = gci C:\temp\

foreach ($file in $files) {
    foreach ($rule in $myRules) {
        if ($file.Name -match $rule.A1) {
            Write-host "$($file.Name) is matching pattern ""$($rule.A1)"". Applying rename to ""$($rule.A2)"""
            $NewScriptBlock = [scriptblock]::Create("rename-item -Path $($file.FullName) -NewName ""$($rule.A2)""")
            $NewScriptBlock.Invoke()
        }
    }
}

Which gives before:

file1-01-02-0344
file2           
flie45224

Output during the execution:

file1-01-02-0344 is matching pattern "^file1-\d\d-\d\d-\d\d\d\d$". Applying rename to "file1"
file2 is matching pattern "^file2$". Applying rename to "this$($file.Name)"
flie45224 is matching pattern "^flie*". Applying rename to "file123"

And after:

file1          
thisfile2
file123        

Explanations

The first foreach is parsing the files. Then for each of those files, we are checking if one of the rule is matching thanks to the -match $rule.A1.

With the first example, you can use regexp (\d to match digits). For the other cases, I kept it simple as you didn't clarify the rules but this will be your homework :)

Then in the transform rules, you can use the filename variable as shown in the second transform rule: this$($file.Name)

NB: it could be a good idea to add a flag to leave the loop for the current file once it has been renamed to avoid unecessary check and to display a message if the file hasn't match any pattern.

CodePudding user response:

Seems a bit odd, I suspect you should be able to use a regex pattern instead but can't say without seeing the csv contents. Otherwise try this. Assumes the CSV has a column headers called First and Second, First matches the basename (no extension) of the file and Second contains the basename you want it changed to.

$csv = Import-Csv -Path c:\filenames.csv
Get-ChildItem -Path c:\temp | %{if($csv.First -contains $_.BaseName){Rename-Item -Path $_.FullName -NewName "$($csv.Second[$csv.First.IndexOf($_.BaseName)] $_.Extension)"}}
  • Related