modify script for duplicate renamed files - powershell

Using the code below in PowerShell, I'm renaming many pictures. How do I modify the code to manage duplicates? Note; many of the photos have the SAME CreationTime value. As they occur, I need them to be output as:
yyyyMMdd-HHmm-1
yyyyMMdd-HHmm-2
yyyyMMdd-HHmm-3
etc.
Script:
Dir | Rename-Item -NewName {$_.CreationTime.toString("yyyyMMdd-HHmm") + ".jpg"}

Add more to your scriptblock to check paths and cycle through until it finds something unique:
Dir | Rename-Item -NewName {
$NewName=$_.CreationTime.toString("yyyyMMdd-HHmm") + ".jpg";
$i=1
While(Test-Path ".\$NewName"){
$NewName=$_.CreationTime.toString("yyyyMMdd-HHmm") + "-$i.jpg"
$i++
}
$NewName
}
Edit: Hm, I'm not sure why it would do that unless you didn't copy my code right. I ran it against a test folder and ended up with:
PS C:\temp\test> gci
Directory: C:\temp\test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/12/2016 11:13 AM 35228885 20161012-1113.jpg
-a---- 10/12/2016 11:28 AM 31413221 20161012-1128.jpg
-a---- 10/12/2016 11:37 AM 33243498 20161012-1137.jpg
-a---- 10/12/2016 4:42 PM 2110424 20161012-1642-1.jpg
-a---- 10/12/2016 4:42 PM 3300892 20161012-1642-2.jpg
-a---- 10/12/2016 4:42 PM 3295345 20161012-1642-3.jpg
-a---- 10/12/2016 4:42 PM 101138881 20161012-1642.jpg
Edit2: Ok, fixed the issue where it can't manage more than 10 of a file with the same datetime.

try this, but modify the path C:\temp with your path directory
$listcouple=gci -File -Path "C:\temp" | select name, fullname, #{Name="Datstring";Expression={$_.CreationTime.toString("yyyyMMdd-HHmm") }} | group Datstring
foreach ($item in $listcouple)
{
if ($item.Count -gt 1)
{
$compteur=0
foreach ($value in $item.Group)
{
$compteur++
$newname= $value.Datstring + "-" + $compteur.ToString() + ".jpg"
Rename-Item -path $value.fullname -newname $newname
}
}
else
{
$newname= $item.Group[0].Datstring + ".jpg"
Rename-Item -path $item.Group[0].fullname -newname $newname
}
}

Related

I want to import a csv to use as filter in the powershels gci command

I have a csv file with extension and description.
I want to import that file and use it as the filter parameter in a gci command.
But I get no results.
I expect to get a list of the jpg files but get no results.
$extensions=Import-CSV -Path c:\scripts\Media-extension-foto.csv
#$extensions=Import-CSV -Path c:\scripts\Media-extension-foto.csv -header extension
$extensions.extension
$src = "c:\scripts\"
#gci c:\scripts\ -Include $Extensions.extension #-Force -recurse
#gci c:\scripts\ -filter $Extensions.extension #-Force -recurse
gci c:\scripts\|where{$_ -like $extensions.extension}`
my csv file looks like this (just made a small file for testing)
extension,"description"
*.JPEG,JPEG Image
*.JPF,JPEG 2000 Image
*.JPG,JPEG Image
*.JPG_LARGE,Twitter Large JPEG Image
There are jpg files in that folder :
Directory: C:\Scripts
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23/11/2022 11:02 509592 nieuw9754560_02-10.jpg
-a--- 23/11/2022 11:02 576486 nieuw9754560_02-15.jpg
-a--- 23/11/2022 11:02 641802 nieuw9754560_02-20.jpg
-a--- 23/11/2022 11:01 705702 nieuw9754560_02-25.jpg
-a--- 23/11/2022 11:01 763249 nieuw9754560_02-30.jpg
I've just tested this - I think all you're missing is changing the $_ to $_.Extension for the Get-ChildItem, on the last line.
Hope that helps.
Doesn't directly fix the code but here's another way of getting the result using foreach to iterate through each extension in the array:
foreach($e in $extensions.extension) {
gci c:\scripts\ | where {$_ -like $e}
}

How can I rename files by prepending a sequence number to the original file names?

guys does anyone know how can i do this? I am trying to list some files in a numerical order by adding 1, 2, 3 and so on to the beginning of the file names while also keeping the files' original names.
Here are the codes i tried
$nr = 1
Dir -path C:\x\y\deneme | %{Rename-Item $_ -NewName (‘{0} $_.Name.txt’ -f $nr++ )}
dir | select name
This code just orders the files like 1, 2, 3... Without keeping the original names.
$n = 1
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace $_.Name ,'{0} $_.Name' -f $n++}
This one did not work like i thought.
Try the following, which renames all .txt files in the current dir. by prepending a sequence number to them:
$n = 1
Get-ChildItem *.txt |
Rename-Item -WhatIf -NewName { '{0} {1}' -f ([ref] $n).Value++, $_.Name }
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
The ([ref] $n).Value++ trick makes up for the fact that delay-bind script blocks run in a child scope of the caller, where the caller's variables are seen, but applying ++ (or assigning a value) creates a transient, local copy of the variable (see this answer for an overview of PowerShell's scoping rules).
[ref] $n in effect returns a reference to the caller's variable object, whose .Value property can then be updated.
As for what you tried:
'{0} $_.Name.txt', as a single-quoted string, is interpreted verbatim by PowerShell; you cannot embed variable references in such strings; for that you need double-quoting ("...", and you'd also need $(...) in order to embed an expression such as $_.Name) - see the bottom section of this answer for an overview of PowerShell's string literals.
So yeah, I agree with #Abraham, I don't see a scenario where you can rename the files but also retain the original files without copying them :)
This should do the trick:
$i = 0; Get-ChildItem x:\path\to\files | ForEach-Object {
$i++
$destPath = Join-Path $_.DirectoryName -ChildPath "$i $($_.Name)"
Copy-Item -Path $_.FullName -Destination $destPath
}
Example:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 6/24/2021 7:08 PM 2 1 testfile0.txt
-a---- 6/24/2021 7:08 PM 2 2 testfile1.txt
-a---- 6/24/2021 7:08 PM 2 3 testfile2.txt
-a---- 6/24/2021 7:08 PM 2 4 testfile3.txt
-a---- 6/24/2021 7:08 PM 2 5 testfile4.txt
-a---- 6/24/2021 7:08 PM 2 testfile0.txt
-a---- 6/24/2021 7:08 PM 2 testfile1.txt
-a---- 6/24/2021 7:08 PM 2 testfile2.txt
-a---- 6/24/2021 7:08 PM 2 testfile3.txt
-a---- 6/24/2021 7:08 PM 2 testfile4.txt

Foreach loop not reading files in numeric order

I have below files which i am reading using a foreach loop.
$GetGeneratedFiles = Get-ChildItem -Path "C:\Script\LF*.csv" -recurse | % { $_.FullName }
C:\Script\LF_Batch_1.csv
C:\Script\LF_Batch_10.csv
C:\Script\LF_Batch_11.csv
C:\Script\LF_Batch_12.csv
C:\Script\LF_Batch_13.csv
C:\Script\LF_Batch_14.csv
C:\Script\LF_Batch_15.csv
C:\Script\LF_Batch_16.csv
C:\Script\LF_Batch_17.csv
C:\Script\LF_Batch_18.csv
C:\Script\LF_Batch_19.csv
C:\Script\LF_Batch_2.csv
C:\Script\LF_Batch_20.csv
C:\Script\LF_Batch_21.csv etc...upto LF_Batch_.96.csv
Problem is it is reading the files like above not 1,2,3...and so on.
Please need idea how to read in ordered way
Solved using below approach
$GetGeneratedFiles = Get-ChildItem -Path "C:\Script\LF*.csv" -recurse | % { $_.FullName }
$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
$GetGeneratedFiles = $GetGeneratedFiles | Sort-Object $ToNatural
Thanks #vonPryz for the reference.
Another way. It's funny how I just did another answer similar to this. A numeric sort on the names.
echo hi | set-content (1,2,10,20 | % tostring LF_Batch_0\.csv)
dir | sort {[void]($_ -match '\d+'); [int]$matches.0}
Directory: C:\Users\js\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 9/17/2020 9:14 AM 4 LF_Batch_1.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_2.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_10.csv
-a--- 9/17/2020 9:14 AM 4 LF_Batch_20.csv

How to split string and rename files in PowerShell?

I want to bulk rename the files in my folder, and all of them have the format of FilenameYeara\b.pdf, for example, TestData2001a.pdf, File2015b.pdf. I want to rename all of them to something like [Yeara\b]Filename, such as [2001a]TestData. The problem is that I don't know how can I split my filename into two parts (actually three if we count the extension, .pdf part), such that I put that second part as the first part of the file name.
Get-ChildItem | Rename-Item {$_.name -replace ‘current’, ’old’ }
How can I achieve this?
This does the regex match "anything, four digits, one character, .pdf" and replaces it with those items in the new ordering.
PS D:\t> gci | ren -newname { $_ -replace '(.*)(\d{4})(.)\.pdf', '[$2$3]$1.pdf' }
Directory: D:\t
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 13/05/2016 02:54 0 File2015b.pdf
-a--- 13/05/2016 02:53 0 TestData2001a.pdf
becomes
Directory: D:\t
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 13/05/2016 02:53 0 [2001a]TestData.pdf
-a--- 13/05/2016 02:54 0 [2015b]File.pdf
(Maybe try it with -Whatif before running for real)
This should get you started
$Matches.Clear()
Get-Item | % {
$_.BaseName -match "(\D+)([0-9]{4}[ab])"
Rename-Item -Path $_.FullName -NewName "$($Matches[2])$($Matches[1])$($_.Extension)"
}

"(" char doesn't work in PowerShell

I can't get this to work. It doesn't like the "(" char;
how do I fix it?
Dir | Rename-Item -NewName { $_.name -replace "(","" }
How do I handle this type of special character in PowerShell?
You've got a great explanation of the exact cause of your problem from #vonPryze, but there's a much simpler solution. The -replace operator uses regular expressions which need escaping, but the .Replace() string method just uses strings. So if you don't need a regex, just use the method and there's no need to escape anything:
dir | rename-item -NewName { $_.name.Replace("(","") }
Let's try analyzing the problem a bit. First off, create some dummy files that contain a parenthesis like so,
for($i=0;$i -le 4; ++$i) { set-content -path $("file($i).txt" -f $i) -value $i }
Output:
gci
Directory: C:\temp\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 17.2.2014 10:34 3 file(0).txt
-a--- 17.2.2014 10:34 3 file(1).txt
-a--- 17.2.2014 10:34 3 file(2).txt
-a--- 17.2.2014 10:34 3 file(3).txt
-a--- 17.2.2014 10:34 3 file(4).txt
Now that we have some test data, let's try to run the command that provied an error message like so,
Dir | Rename-Item -NewName { $_.name -replace "(","" }
Rename-Item : The input to the script block for parameter 'NewName' failed.
Invalid regular expression pattern: (.
At line:1 char:27
+ Dir | Rename-Item -NewName <<<< { $_.name -replace "(","" }
+ CategoryInfo : InvalidArgument: (file(0).txt:PSObject) [Rename-Item], ParameterBind ingException
+ FullyQualifiedErrorId : ScriptBlockArgumentInvocationFailed,Microsoft.PowerShell.Commands.Re nameItemCommand
Oops! The error message says that an invalid regular expression was used. That means -replace is not going to just replace strings but it supports regular expressions too!
In order to get -replace to treat the input as literal text instead of a regex, the input needs to be escaped. The simple way is to insert backslashes \, but this gets soon tedious. There luckily is an easier way, as .Net Regex class has a built-in escape method [Regex]::Excape(). Like so,
Dir | Rename-Item -NewName { $_.name -replace [regex]::escape("("),"" }
Output:
ls
Directory: C:\temp\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 17.2.2014 10:34 3 file0).txt
-a--- 17.2.2014 10:34 3 file1).txt
-a--- 17.2.2014 10:34 3 file2).txt
-a--- 17.2.2014 10:34 3 file3).txt
-a--- 17.2.2014 10:34 3 file4).txt
Dir | Rename-Item -NewName { $_.name -replace "\(","" } # This works