Can I rename files in subfolders based on.CSV file

2019-07-27 10:29发布

问题:

I want to rename some files based on .csv file, I succeeded to do so using the following code

Import-Csv "C:\Location\rename.csv" | foreach { Rename-Item -Path $_.Oname -NewName $_.NName }

but that renames only the files in the parent folder
I tried to make it includes the files in the sub-folders but in vain

I tried to add

Get-ChildItem

It gets error, probably I don't know how to combine it with the import csv

the .csv file format is

Oname,NName
Name1,NewName1
Name2,Newname2

回答1:

here's one way to do the job. it's a tad more roundabout since the files may be anywhere in the target directory tree. what it does ...

  • fakes reading in a CSV of old/new file names
  • sets the target top directory
  • sets the file type
    if you don't have just one file type, this can be removed here and in the Get-ChildItem line.
  • gets all the files in the target dir tree that match the ONames in the CSV file
  • iterates thru that collection of file items
  • gets the index [position of the item in the array] of the OName that matches the current file item name
  • does a rename on that file
    the -WhatIf on the end of the Rename-Item line is there to show what WOULD happen. [grin] remove it when you are ready to do this for real on your sample data [and later on your real data].

here is the code ...

# fake reading in a CSV file
#    in real life, use Import-CSV
$InStuff = @'
OName, NName
"GWords_2019-02-20.log", "MORE_GWords_2019-02-20.log"
"Two_2019-03-06.log", "Yet another _-_ Two_2019-03-06.log"
"One_GWords_2019-02-27.log", "Slightly different - One_GWords_2019-02-27.log"
'@ | ConvertFrom-Csv

$TargetDir = "$env:TEMP\Testing"
$Filter = '*.log'

$FileList = Get-ChildItem -LiteralPath $TargetDir -Filter $Filter -File -Recurse |
    Where-Object {$_.Name -in $InStuff.OName}

foreach ($FL_Item in $FileList)
    {
    $Index = $InStuff.OName.IndexOf($FL_Item.Name)
    Rename-Item -LiteralPath $FL_Item.FullName -NewName $InStuff[$Index].NName -WhatIf
    }

output [reformatted for readability] ...

What if: Performing the operation "Rename File" on target 
        "Item: C:\Temp\Testing\GWords_2019-02-20.log
    Destination:
        C:\Temp\Testing\MORE_GWords_2019-02-20.log".
What if: Performing the operation "Rename File" on target
        "Item: C:\Temp\Testing\SubOne\One_GWords_2019-02-27.log
    Destination:
        C:\Temp\Testing\SubOne\Slightly different - One_GWords_2019-02-27.log".
What if: Performing the operation "Rename File" on target
        "Item: C:\Temp\Testing\SubTwo\Two_2019-03-06.log
    Destination:
        C:\Temp\Testing\SubTwo\Yet another _-_ Two_2019-03-06.log".


回答2:

I suggest to:

  • read the csv into a variable
  • then build a hash table from the OldName NewName pairs
  • use the .OName property with Get-ChildItem -Include to recursively select files
  • directly pipe to Rename-Item and get the NewName from the hash table

## Q:\Test\2019\03\30\SO_55433812.ps1
$Renames = Import-csv "C:\Location\rename.csv"
$TargetDir = "$env:TEMP\Testing"

$RenHash = @{}
$Renames | ForEach-Object { $RenHash[$_.OName]=$_.NName }

Get-ChildItem -Path $TargetDir -Recurse -Include $Renames.OName | 
    Rename-Item -NewName {$RenHash[$_.Name]} -WhatIf

Sample output from this years test folder (German locale)

WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das 
Ziel "Element: Q:\Test\2019\02\17\test.txt 
         Ziel: Q:\Test\2019\02\17\Example.txt".
WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das 
Ziel "Element: Q:\Test\2019\02\28\file.csv 
         Ziel: Q:\Test\2019\02\28\File.Csv".
WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das 
Ziel "Element: Q:\Test\2019\02\28\test.txt 
         Ziel: Q:\Test\2019\02\28\Example.txt".
WhatIf: Ausführen des Vorgangs "Datei umbenennen" für das 
Ziel "Element: Q:\Test\2019\03\19\sample.csv 
         Ziel: Q:\Test\2019\03\19\Example.csv".

If the ouput looks OK remove the trailing -WhatIf