How to move and rename multiple files using powershell? - powershell

I have a large number of files (>4 million) and need to rename and move them to another folder in small steps.
I am a total beginner in powershell, but I already managed to move them in small packages of 100 files (the powershell script is executed as scheduled task).
But so far I failed with renaming the files. In each file, there are two strings that need to be replaced.
The following codes works fine, except for the renaming part (line 12 and 13):
#Get 'n' number of files
$FileLimit = 100
$PickupDirectory = Get-ChildItem -Path "\\server\path$\ERROR\subfolder\"
$DropDirectory = "\\server\path$\destination\"
$Counter = 0
foreach ($file in $PickupDirectory)
{
if ($Counter -ne $FileLimit)
{
$file | Rename-Item -NewName {$_.name -replace '999999','367'}
$file | Rename-Item -NewName {$_.name -replace 'oldname','newname'}
$Destination = $DropDirectory+$file.Name
Move-Item $file.FullName -destination $Destination
$Counter++
}
}
exit
What is the correct way to rename those files?
Thank you so much for your help!
Best wishes
Philipp
Edit: Sorry, here's the Error Log :
Rename-Item : Cannot rename because item at 'Microsoft.PowerShell.Core\FileSystem::\\server\path$\ERROR\subfolder\1566392#5990762$20180116^999999_2018_01_16_oldname_1566392_Kägi.pdf' does not exist.
At C:\Scripts\mv_Verordnung_für_Physiotherapie.ps1:12 char:28
+ ... pDirectory | Rename-Item -NewName {$_.name -replace '^999999','^367'}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
Edit2: Updated the code with tipps from comments. Error still the same.

You should do the limiting (if necessary at all) earlier with the Get-ChildItem =>
$PickupDirectory = Get-ChildItem -Path "\\server\path$\ERROR\subfolder\" | Select -First $FileLimit
Instead of using the currently iterated item ($file) you use the whole array $PickupDirectory
You can't apply the 2. replace to an already changed value.
instead of rename and move do it in one step.
#Get 'n' number of files
$FileLimit = 100
$PickupDirectory = Get-ChildItem -Path "\\server\path$\ERROR\subfolder\" | Select -First $FileLimit
$DropDirectory = "\\server\path$\destination\"
foreach ($file in $PickupDirectory){
$Destination = Join-Path $DropDirectory ($file.Name -replace '^999999','^367' `
-replace 'oldname','newname')
$file | Move-Item -Destination $Destination
}

You're calling Rename-Item on the $PickupDirectory collection. Instead call it on the $file variable you are using in the foreach loop:
$file | Rename-Item -NewName { $_.name -replace '^999999', '^367' }
$file | Rename-Item -NewName { $_.name -replace 'oldname', 'newname' }

Related

How do I remove a leading or trailing blank space in file name with PowerShell?

I'm basically trying to trim() any filenames that have a leading or trailing space at the end of the name. This is the code I've got so far
$foldersToCheck = "$env:userprofile\documents", "$env:userprofile\pictures", "$env:userprofile\desktop"
foreach ($folder in $foldersToCheck) {
get-childitem -path $folder -recurse | foreach-object {
if ($_.name.startswith(" ") -or $_.name.endswith(" ")) {
$newName = $_.name.trim()
rename-item -path $_ -newName $newname
}
}
}
If I create a test file (c:\users\someusername\desktop\ test.txt), then I receive this error
rename-item : Cannot rename because item at ' test.txt' does not exist.
At line:6 char:13
+ rename-item -path $_ -newName $newname
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
So, it looks like it found the file that needs to be renamed, but then says it doesnt exist.
The problem here is that PowerShell resolves $_ to just the file name when attempting to convert it to a string it can bind to -Path.
Explicitly pass the full path of the file and it'll work:
Rename-Item -Path $_.FullName -NewName $newname
Alternatively, pipe the $_ file object to Rename-Item and PowerShell will automatically figure out that it needs to bind $_.FullName to Rename-Item's -LiteralPath parameter:
$_ |Rename-Item -NewName $newname
You can also turn the whole loop into a single pipeline, and then take advantage of a pipeline-bound expression against -NewName:
$foldersToCheck |Get-ChildItem -Recurse |Rename-Item -NewName { $_.Name.Trim() }
If the existing Name and the -NewName values are the same, Rename-Item will just leave the files alone anyway :)

How to rename files with a conditional statement in PowerShell

I am trying to rename a whole lot of files all located in one folder but in different subfolders. The files should be renamed so that their name consists of the foldername + the original file name. I am wondering if you could add a conditional statements so that the file name doesn't change if the file name already contains the folder name. The code below performs the function of renaming the files but doesn't contain the if statement.
dir -recurse | Rename-Item -NewName {$_.Directory.Name + " - " + $_.Name}
The code below is an example on how I imagine the code would look:
dir -recurse | if($_.Name -contains $_.Directory.Name) {Rename-Item -NewName {$_.Directory.Name + " - " + $_.Name}}
This should do it:
$rootFolder = 'D:\test'
Get-ChildItem -Path $rootFolder -File -Recurse | ForEach-Object {
$folder = $_.Directory.Name
if (!($_.Name.StartsWith($folder))) { $_ | Rename-Item -NewName ('{0} - {1}' -f $folder, $_.Name) }
}
Theo's answer works well, but there's an alternative that is both conceptually simpler and performs noticeably better:
You can take advantage of the fact that passing an unchanged file name to -NewName is a quiet no-op, so you can place all your logic in the -NewName script block:
Get-ChildItem -File -Recurse |
Rename-Item -NewName {
if ($_.Name -like ($_.Directory.Name + ' - *') { # already renamed
$_.Name # no change
}
else { # rename
$_.Directory.Name ' - ' + $_.Name
}
} -WhatIf
-WhatIf previews the renaming operation; remove it to perform actual renaming.
Rather than using ForEach-Object call with a nested Rename-Item call in its script block - which means that Rename-Item is called once for each input file - this solution uses a single pipeline with a single Rename-Item invocation, where the new name (if changed) is determined via a delay-bind script block - see this answer for details.
I was trying it in a way close to the way the question was asked. I wish I didn't have to add another foreach.
dir -recurse -file | & {
foreach ($i in $input) {
if(-not ($i.Name.contains($i.Directory.Name))) {
Rename-Item $i.fullname -NewName ($i.Directory.Name + ' - ' + $i.Name) -whatif
}
}
}
Or like this
dir -recurse -file | % {
if(-not ($_.Name.contains($_.Directory.Name))) {
Rename-Item $_.fullname -NewName ($_.Directory.Name + ' - ' + $_.Name) -whatif
}
}

PS to rename directory of files using only the first 4 characters

I have a directory c:\test with files 0001 test.pdf, 0002ssssit.pdf, 0003llllllllllll.pdf
My goal is to use PS to use a a loop to go through the directory and rename the files to:
0001.pdf
0002.pdf
0003.pdf
I keep getting path errors
$List = get-childitem "C:\test"
$List |Format-Wide -Column 1 -property name
ForEach($File In $List)
{
$First4 = $File.name.substring(0,4)
Rename-Item -newname $First4".pdf"
}
You need to pass the original file path to Rename-Item, otherwise it won't know what to rename!
Either:
$file | Rename-Item -NewName "${First4}.pdf"
or
Rename-Item -LiteralPath $file.FullName -NewName "${First4}.pdf"
inside the foreach body.
You could also use a single pipeline to accomplish the same (-NewName supports pipeline binding):
$List | Rename-Item -NewName { $_.Name.Substring(0,4) + $_.Extension }
try Something like this:
Get-ChildItem "c:\temp" -file "*.pdf" |
where Name -match "^[0-9]{4}" |
rename-item -NewName {"{0}{1}" -f $_.BaseName.Substring(0, 4), $_.Extension}

Cycle through sub-folders to rename files in Powershell

I have a file directory that contains many folders within it. Inside each of these sub-folders, I have a variety of files. I would like to go through each file, rename some of the items, and add extensions to some of them. I am using Powershell to do this.
I have file names with "." that all need to be replaced with "_" for example, "wrfprs_d02.03" should be "wrfprs_d02_03". I was able to successfully do that in one folder with the following code:
dir | rename-item -NewName {$_.name -replace "wrfprs_d02.","wrfprs_d02_"}
After, I make those replacements, I want to add .grb extensions on to some of the files, which all happen to start with "w", and I was able to do that within one folder with:
Get-ChildItem | Where-Object {$_.Name -match "^[w]"} | ren -new {$_.name + ".grb"}
When I step back from one folder and try to do it iteratively within many folders, my code doesn't work. I am in a directory called "Z:\Windows.Documents\My Documents\Test_data\extracted" which contains all my sub-folders that I want to iterate over. I am using the following code:
$fileDirectory = "Z:\Windows.Documents\My Documents\Test_data\extracted"
foreach($file in Get-ChildItem $fileDirectory)
{
dir | rename-item -NewName {$_.name -replace "wrfprs_d02.","wrfprs_d02_"}
Get-ChildItem | Where-Object {$_.Name -match "^[w]"} | ren -new {$_.name + ".grb"}
}
Any ideas on what my problem is?
because you $_ is replaced into loop when you use pipe. I propose you a new code:
$fileDirectory = "Z:\Windows.Documents\My Documents\Test_data\extracted"
Get-ChildItem $fileDirectory -recurse -file -filter "*.*" |
%{
#replace . by _
$NewName=$_.Name.Replace(".", "_")
#add extension grb if name start by w
if ($NewName -like "w*") {$NewName="$NewName.grb"}
#Add path file
$NewName=Join-Path -Path $_.directory -ChildPath $NewName
#$NewName
#rename
Rename-Item $_.FullName $NewName
}
Not sure what error you were getting, but using rename-item can be finicky. Or at least so in my experience.
I used the follow without issue. My files names were different so I replaced all periods with underscores. If the file starts with "W" then it changed the extension for that file.
$FilePath = Get-ChildItem "Z:\Windows.Documents\My Documents\Test_data\extracted" -Recurse -File
foreach ($file in $FilePath)
{
$newName = $file.Basename.replace(".","_")
$New = $newName + $file.Extension
if($file.Name -match "^[w]")
{
Rename-Item $file.FullName -NewName "$($New).grb"
}
else
{
Rename-Item $file.FullName -NewName $New
}
}
Hope that helps.

Using Powershell how can I bulk rename files recursively and include a counter in the new name?

I have a project where I need to search for multiple pdfs within multiple subfolders which contain a specific string and then rename them using a counter variable. I'm a pretty novice powershell user but I think I've got it pretty close. The only thing that is not working is the counter. The counter variable never changes. This is what I have so far for code:
$prefix = "sample"
$id = 1
Get-ChildItem -Filter "*combined*" -Recurse | Rename-Item -NewName ($prefix + ($id.tostring("000")) + '_regular_' + ($id.tostring("000")) + '.pdf' -f $id++ )
What am I missing? Should I be using a 'foreach' loop?
Yes you need to use a ForEach loop. This will go through and do the renames, ensuring that any files found in subdirectories are preserved in those directories after renaming
Get-ChildItem -Filter "*combined*" -Recurse | %{
$fullId = $id.toString("000")
$curPath = Split-Path $_.FullName
Rename-Item $_.fullname -NewName "$curPath\$($prefix)$($fullId)_regular_$($fullId).pdf" )
$id += 1
}
Here is my edited version of the above code:
$id = 1
Get-ChildItem -Filter "*combined*" -Recurse | %{
$fullId = $id.toString("000")
$curPath = Split-Path $_.FullName
Rename-Item $_.fullname -NewName "$curPath\$($prefix)_$($fullId)_regular_$($fullId).pdf"
$id++
}