I have a directory with a certain number of mp3 files, that are sorted by name, for example:
Artist.mp3
Another artist.mp3
Bartist.mp3
Cool.mp3
Day.mp3
How can I add a unique continuous 3-digit prefix to each file, but in a random order, so that when sorting by name it would look something like this:
001 Cool.mp3
002 Artist.mp3
003 Day.mp3
...
Try this:
$files = Get-ChildItem -File
$global:i = 0; Get-Random $files -Count $files.Count |
Rename-Item -NewName {"{0:000} $($_.Name)" -f ++$global:i} -WhatIf
Or in the unlikely event the filename contains curly braces :-):
$files = Get-ChildItem -File
$global:i = 0; Get-Random $files -Count $files.Count |
Rename-Item -NewName {("{0:000} " -f ++$global:i) + $_.Name} -WhatIf
Or as #PetSerAl suggests, using [ref]$i as a good way to avoid global vs script scoping issues altogether:
$files = Get-ChildItem -File
$i = 0; Get-Random $files -Count $files.Count |
Rename-Item -NewName {"{0:000} {1}" -f ++([ref]$i).Value, $_.Name} -WhatIf
If the output looks good remove the -WhatIf and run this again to actually rename the files.
Related
I'm trying to write a PowerShell script that goes into every folder in a certain directory, and every child with the parent.
Example:
Z:\Folder1\File.txt
Z:\Folder1\Picture.jpeg
Z:\Folder1\Data.csv
Z:\Folder2\File.txt
Z:\Folder2\Picture.jpeg
Z:\Folder2\Data.csv
=
Z:\Folder1\Folder1.txt
Z:\Folder1\Folder1.jpeg
Z:\Folder1\Folder1.csv
Z:\Folder2\Folder2.txt
Z:\Folder2\Folder2.jpeg
Z:\Folder2\Folder2.csv
I have this so far
dir | rename-item -NewName {$_.name -replace *,"Folder1"}
Please let me know how I can loop through every folder, and how I can rename them based on the folder name.
Thanks!
This should do what you're asking:
Get-ChildItem Z:\Folder* -Directory | Get-ChildItem -File | Rename-Item -NewName { $_.DirectoryName.split('\')[-1] + $_.Extension } -WhatIf
Adjust the folder name filter (.\Folder*) as required and remove the -WhatIf if you're satisfied with the changes it will make.
Obviously this doesn't account for where you might have a name clash if there are two files in the folder with the same extension. The following would do that:
$FilesToRename = Get-ChildItem Z:\Folder* -Directory | Get-ChildItem -File
foreach ($FileToRename in $FilesToRename) {
$NewName = $FileToRename.DirectoryName.split('\')[-1] + $FileToRename.Extension
$NewFile = Join-Path $FileToRename.Directory $NewName
$i = 0
While (Test-Path $NewFile) {
$i = $i++
$NewName = $FileToRename.DirectoryName.split('\')[-1] + "[$i]" + $FileToRename.Extension
$NewFile = Join-Path $FileToRename.Directory $NewName
}
$FileToRename | Rename-Item -NewName $NewName
}
I have a series of folders and subfolders, structured in this way:
001/Fabric/Blue/ (.jpg files, sequentially named)
001/Fabric/Green/ (.jpg files, sequentially named)
002/Fabric/Blue/ (.jpg files, sequentially named)
002/Fabric/Green/ (.jpg files, sequentially named)
etc.
The file names have excess string characters that I would like to remove, and I would like to convert their file names into an easier sequential format (0.jpg, 1.jpg, etc.).
I tried working with a few different PowerShell examples to get this to work. I have the recursive searching functionality working, however I receive an error about an InvalidOperationException when trying to rename the files in the ForEach-Object loop. Additionally, I am afraid my sequential numbering is not being 'reset' for each of the folders where it renames files.
$i = 0
Get-ChildItem -Filter "*.jpg" -Recurse | ForEach-Object {
Rename-Item $_ -NewName ('$i.jpg' -f $i++)
}
So, two questions:
How can I fix the error with Rename-Item?
How can I ensure my variable is reset for each subfolder the script starts renaming files in?
If you take a two step approach, first getting all the folders containing jpg's and then iterating through this list, you have no problem beginning with 1. But I'd always use leading zeroes for such a renumbering.
$BaseFld = "Q:\Test\"
$Ext = "*.jpg"
$jpgFolders = gci $($BaseFld+$Ext) -Recurse |
Select -ExpandProperty Directory -Unique |
select -ExpandProperty Fullname | Sort
ForEach ($Folder in $jpgFolders) {
Set-location $Folder
$i = 1
Get-ChildItem $Ext | %{Ren $_ -NewName ('{0:D4}.jpg' -f $i++) -whatif}
}
If the ouptut suits you, remove the -whatif in the second last line
other method
$rootdir="C:\temp"
gci $rootdir -Recurse -Directory | %{$i=1; gci $_.FullName -Recurse -File -Filter "*.jpg" | %{Ren $_.FullName -NewName ('{0}.jpg' -f $i++)} }
I have 50 sub-Folders inside a Single Parent Folder.
Inside each sub folders there are multiple .txt files. I want to merge all the text files in a single sub-folder into 1 .txt file.
But I want a command so that it can be done in one go for all the subfolder, like i don't want to write command for each sub-folder.
For example:-
ABCD (Parent Folder ):-
A
B ; Here A and B are sub-folder
A\0001.txt
A\0002.txt
I want to merge and make a single text file A\0001.txt.
B\0001.txt
B\0002.txt
I want to merge both the text files in B Folder.
Can it be done in one go ?
This is probably a lot easier using powershell.
Try the following and change the basedir to the parent folder of all your subdirectories.
$basedir = "C:\Basedir"
$folderlist = Get-childitem -Path $basedir
foreach ($folder in $folderlist)
{
$dir = $folder
$outFile = Join-Path $dir "merged.txt"
# Build the file list
$fileList = Get-ChildItem -Path $dir -Filter File*.txt -File
# Get the header info from the first file
Get-Content $fileList[0] | select -First 2 | Out-File -FilePath $outfile -Encoding ascii
# Cycle through and get the data (sans header) from all the files in the list
foreach ($file in $filelist)
{
Get-Content $file | select -Skip 2 | Out-File -FilePath $outfile -Encoding ascii -Append
}
}
Maybe old but useful: this version works with folders and subfolders recursively:
$basedir = "..."
$folderlist = Get-childitem -Path $basedir -Recurse -Directory | Select-Object FullName
foreach ($folder in $folderlist)
{
Write-Host $folder.FullName
$dir = $folder.FullName
$outFile = Join-Path $basedir "merged.txt"
# Build the file list
$fileList = Get-ChildItem -Path $dir -Filter *.log | Select-Object FullName
# Get the header info from the first file
#Get-Content $fileList[0] | select -First 2 | Out-File -FilePath $outfile -Encoding ascii
# Cycle through and get the data (sans header) from all the files in the list
foreach ($file in $filelist)
{
Write-Host $file.FullName
Get-Content $file.FullName | Out-File -FilePath $outfile -Encoding ascii -Append
}
}
I have following Power Shell script I need to modify.
$filepath = "F:\feeds\Amazon\"
$temppath = $filepath+"temp.csv"
$files = ls -Path $filepath *.csv
foreach ($file in $files){
gc $file.FullName |
% { if($_.indexOf("|~|") -eq -1) {$_ -replace "`"((?:`"`"|.)*?)`"(?!`")", "|~|`$1|~|" -replace "`"`"", "`""} else {$_ -replace " ", " "}} |
sc $temppath
ri $file.fullName
rni -Path $temppath -NewName $file.fullName
}
This script loops through all .csv files in a defined folder and change the text qualifier. Now I need to change this a bit and I am stucked.
Basically my CSV files are spitted into multiple folders like. Amazon1, Amazon2, Amazon3 .. so on. Is there anything wild card match sort of things I can do here so that it looks into all folders whose name starting with Amazon?
I Don't want to loop through folders.
... The * character? Try this:
$filepath = "F:\feeds\Amazon*"
$files = ls -Path $filepath *.csv -recurse
foreach ($file in $files){
$temppath = $file.directoryName+"\temp.csv"
gc $file.FullName |
% { if($_.indexOf("|~|") -eq -1) {$_ -replace "`"((?:`"`"|.)*?)`"(?!`")", "|~|`$1|~|" -replace "`"`"", "`""} else {$_ -replace " ", " "}} |
sc $temppath
ri $file.fullName
rni -Path $temppath -NewName $file.fullName
}
Yes withe Get-child-Item Cmdlet (dir) you can use wild card match on folders :
Get-ChildItem "C:\temp\Amazon?\" -include *.csv -Recurse
I'm trying to do the following:
Rename-Item c:\misc\*.xml *.tmp
I basically want to change the extension on every files within a directory to .tmp instead of .xml. I can't seem to find a straight forward way to do this in PowerShell.
From example 4 in the help documentation of Rename-Item retrieved with the command:
get-help Rename-Item -examples
Example:
Get-ChildItem *.txt| Rename-Item -NewName { $_.Name -replace '\.txt','.log' }
Note the explanation in the help documentation for the escaping backslash in the replace command due to it using regular expressions to find the text to replace.
To ensure the regex -replace operator matches only an extension at the end of the string, include the regex end-of-string character $.
Get-ChildItem *.txt | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }
This takes care of the case mentioned by #OhadSchneider in the comments, where we might have a file named lorem.txt.txt and we want to end up with lorem.txt.log rather than lorem.log.log.
Now that the regex is sufficiently tightly targeted, and inspired by #etoxin's answer, we could make the command more usable as follows:
Get-ChildItem | Rename-Item -NewName { $_.Name -replace '\.txt$','.log' }
That is, there is no need to filter before the pipe if our regex sufficiently filters after the pipe. And altering the command string (e.g. if you copy the above command and now want to use it to change the extension of '.xml' files) is no longer required in two places.
This works well too when you're in the desired directory.
Dir | Rename-Item –NewName { $_.name –replace "old","new" }
The existing answers suggest the -replace operator, but what if the file is called a.xml.xml? Both .xml substrings will be replaced and the end result would be a.tmp.tmp. Fortunately, there's a .NET method for this:
Dir *.xml | rename-item -newname { [io.path]::ChangeExtension($_.name, ".tmp") }
(Manish Kumar was close with GetFileNameWithoutExtension but this is more elegant and probably a bit more efficient, not that it overly matters in this case)
Here's another variant that will work.
dir *.xml | Rename-Item -NewName {$_.BaseName + ".tmp"}
$_.BaseName will do the "base" name without the (last) extension.
a shortened version using the alias would be:
ls *.xml | ren -new {$_.BaseName + ".tmp"}
dir -Recurse | where-object -FilterScript {$_.Extension -eq ".xml"} | Rename-Item -NewName {[System.IO.Path]::GetFileNameWithoutExtension($_.fullname) + ".tmp"}
use -WhatIf to evaluate the result first
Even easier - remember that the replace search string is a regular expression,
dir *.xml | rename-item -newname {$_.name -replace "xml$","tmp"}
The "$" represents end-of-string, so the characters "xml" must be the last three chars of the filename.
This seems to work and is a pythonic i.e simple is better than complex (https://www.python.org/dev/peps/pep-0020/) way of doing it (once you are in the directory):
$files = Get-ChildItem -file -Filter *.xml;
ForEach ($file in $files)
{
$n = $file.Basename
Copy-Item -Path $file -Destination "$n.tmp"
Remove-Item "$n.xml"
}