Recursively Search Dirs & SubDirs And Numerically Rename Files - powershell

I am attempting to recursively scan a directory and rename all .jpg and .jpeg files in the dirs (and sub dirs) to a numeric naming convention.
I have this syntax
get-childitem -Recurse -path C:\Users\jsimpson\Desktop\Test123 | where {($_.extension -eq '.jpg') -or ($_.extension -eq '.jpeg') | %{Rename-Item $_ -NewName (‘MyFile{0}.txt’ -f $nr++)}
However - this gives me an error of
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndCurlyBrace
I am sure this is something mundane on my end that I am overlooking - but what would be the proper syntax to numerically rename all files?
EDIT
Current filename is P1870426.jpeg I want to rename it to 1.jpeg
The files are all an import from a digital camera and Since the files have garbage names - I am basically wanting a way to import them into a program and have the files remain in the same order.

As the error message says, there's a } missing to close Where :
Get-ChildItem -Recurse -Path 'C:\Users\jsimpson\Desktop\Test123' | Where-Object {$_.Extension -match 'jpg|jpeg'} | ForEach-Object {
$newFile = "{0}$($_.Extension)" -f $nr++
Rename-Item $_.FullName -NewName $newFile -Force
}

Related

How do I rename each .jpg file name with consecutive numbers in PowerShell

I'm completely new to PowerShell, or any shell for that matter. I'm trying to figure out a way to rename 109 photos that are marked IMG_3571 to IMG_3679. I want to number them consecutively starting at 236. I've tried a few things and this is where I am at right now:
Get-ChildItem "C:\Files to Transfer\test"*.jpg | ForEach-Object -begin {$count=236} -process {rename-item -Path "C:\Files to Transfer\test" -NewName "$count"}
I get this error message 108 times:
At line:1 char:95
+ ... } -process {rename-item -Path "C:\Files to Transfer\test" -NewName "$ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
Also the file named "test" (where all the photos are contained) gets changed to 236...
Edit: I would like to have the files without "IMG" in the name. Only the numbers.
Thanks everyone! Here is what did it:
Get-ChildItem "C:\Files to Transfer\test\*.jpg" | ForEach-Object -begin {$count=236} -process {rename-item -Path $_.fullname -NewName "$count.jpg";$count++}
You are close.
You need $_ in the rename. $_ is the pipeline variable that Get-ChildItem is feeding.
Your output file needs IMG- as a prefix
And you need to increment count.
Try this:
Get-ChildItem "C:\Files to Transfer\test\*.jpg" | ForEach-Object -begin {$count=236} -process {rename-item -Path $_.fullname -NewName "$count.jpg";$count++}
It is very useful to add -WhatIf to things you are trying so that you can see what will happen without actually doing it.

How to move and rename multiple files using 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' }

How to give extensionless files an extension in SubFolders

I have a parent folder with 100s of subfolders. In those there are random files that do not have any extension applied to them.
I'm trying to use PS to apply a .txt extension to any file found that just doesn't have an extension.
Things I've attempted:
Get-ChildItem G:\Those -Filter {!($_.Extension)} -Recurse |
Rename-Item -NewName {$_.DirectoryName + '.txt'}
Get-ChildItem G:\Those (gci -File -Recurse | ?{!($_.Extension)}) |
Rename-Item -NewName {$_.Directory.Name + '.txt'}
This one works if I have a file extension but I don't know how to convert it to only find files without an extension.
Get-ChildItem G:\Those -Filter *.ext -Recurse |
Rename-Item -NewName {$_.Directory.Name + '.txt'}
I'm getting this error:
Rename-Item : Cannot rename the specified target, because it represents a path or
device name.
At line:1 char:63
+ ... {-not $_.Extension} | Rename-Item -NewName {$_.DirectoryName+'.txt'}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Item], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.RenameItemCommand
I figured it out in a roundabout way, but if someone could provide a one-liner for this I would love you.
{-not $_.Extension} got me those files but the rename wouldn't work until I changed $_.DirectoryName+ to $_.FileName+ with the -File added before -Recurse.
This actually renamed the files that had no extension to just ".txt"
Name that they all had the same name I used my original command to rename anything .txt to $_.DirectoryName+'.txt', which did the trick.

PowerShell: Rename multiple folders using $_.FullName.Replace

I have a google drive folder that occasionally gets out of sync. Google (or someone) will append (1) to the directory/file names. Then it will remove the original directory and I'll have a bunch of folders and files named "xxx (1)".
I've been trying to write a powershell script that will crawl the directory tree and rename the folders/files by simply removing the " (1)" portion. I realize that this may result in some collisions, but I was hoping to get most of them replaced using a script. I'm not that concerned about the directory structure, I'll restore if needed, but it's just kind of a nuisance.
I've tried several powershell scripts, and the closest I've come so far is this...
This will return the correct NEW folder names
Get-ChildItem -Path "* (1)" -Recurse | select { $_.FullName.Replace(" (1)", "")}
So I tried this...
Get-ChildItem -Path "* (1)" -Recurse | Replace-Item -Path $_.FullName -Destination $_.FullName.Replace(" (1)", "") -WhatIf
I get the error "You cannot call a method on a null-valued expression."
You cannot call a method on a null-valued expression.
At line:1 char:1
+ Get-ChildItem -Path "* (1)" -Recurse | rename-item $_.FullName $_.Fu ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Try surrounding the last half in a foreach-object, using Rename-Item instead of Replace-Item, etc etc:
Get-ChildItem -Path "* (1)" -Recurse | ForEach-Object {Rename-Item -Path $_.Fullname -NewName $($_.Name.Replace(" (1)", "")) -WhatIf}
$_ is only a variable inside a scriptblock. With:
.. | select { $_.FullName.Replace(" (1)", "")}
You can get-help select-object and see the first positional parameter is -Property, so this is short for
.. | Select-Object -Property { $_.FullName.Replace(" (1)", "") }
And now you can see the scriptblock gets the files in via the pipeline, accesses them as $_ and calculates a new Property for the output, and the $_ is used once for each file. When you try to use the same technique in your second line:
.. | Replace-Item -Path $_.FullName -Destination $_.FullName.Replace(" (1)", "") -WhatIf
The $_ is just free-floating, you can't use it like that, outside a {} scriptblock it doesn't mean anything. And you're piping the input files in through the pipeline and also trying to specify them with -Path, which is doubling up - clashing and redundant. And you're using Replace instead of Rename.
So in the other answer, nferrell uses ForEach to create a scriptblock. And pipes the files into ForEach and then specifies their name to the -Path of Rename-Item.
Which works, but it's wordy and roundabout. Why take the filenames out of the pipeline and use ForEach to shuffle them round to the other end of the cmdlet, only to put them straight back in?
Get-ChildItem .. | Rename-Item -NewName { $_.Name.Replace(" (1)", "") }
Files go in by the pipeline, NewName is calculated. No loop, no doubling up of input, no

Removing trailing periods from folders in a directory using powershell?

Essentially I have a few hundred folders that have trailing periods at the end of the folder names because of my company's cloud service Box.com.
We're trying to remove the periods using a powershell script but admittedly my powershell knowledge is in its beginner stages.
$string = Get-ChildItem -Recurse | ? {$_.PSIsContainer} | Select Name
$string2 = Trim($string)
$string.Length
$string3 = $string.TrimEnd(".")
dir | ? { $string } | % { mv $_ -Destination ($_.Name.$string3) }
So above I am running the first line from within the folder in question to get the PSIsContainer names, then trimming them of white spaces, and then attempting to trim the end where I have my $string3 variable of any trailing periods in the PSIsContainer names. It's throwing an error though, and I can't figure out why.
Method invocation failed because [System.Object[]] doesn't contain a method named 'TrimEnd'.
At line:1 char:27
+ $string3 = $string.TrimEnd <<<< (".")
+ CategoryInfo : InvalidOperation: (TrimEnd:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Any help would be greatly appreciated!
$string is an array of directory names, not a string. You can't TrimEnd() an array.
You'll probably need to create a foreach loop to do what you want with each directory.
$Directories = Get-ChildItem -Recurse | ? {$_.PSIsContainer}
foreach($Dir in $Directories)
{
Rename-Item $Dir Trim($Dir.Name)
Rename-Item $Dir $Dir.Name.TrimEnd(".")
}
Still another way, if you are looking for a one-liner and if regex is not your friend:
ls -Rec -Dir -Incl '*.' | % { $_.MoveTo($_.FullName.Trim().TrimEnd('.')) }
If the pattern is simple enough, you can let the -Include parameter of Get-ChildItem do the filtering for you.
Edit: The -Include parameter does only work in combination with -Recurse.
Another way:
$pattern = '^\s*(.*?)\.+\s*$'
Get-ChildItem -Recurse -Directory |
? { $_.Name -match $pattern } |
Rename-Item -NewName { $_.Name -replace $pattern, '$1' }