I am trying to create a powershell script to rename media files that have a bunch of descriptions in the file name like DTS,1080P,720P,x264,DVD etc...
Is there some sort of or condition that can be used in the replace option?
To be honest, I'd probably just do it the lazy way and replace all the terms you don't want with nothing, do the same with underscores if desired (included in my example code), trim spaces from the end, and then rename the file (I just use the .MoveTo method).
gci "C:\Movies" | %{$_.MoveTo("$($_.Directory)\$(($_.BaseName -replace '(?i)(1080p|720p|DTS|DVD|x264|_)').TrimEnd(" "))$($_.Extension)")}
Use the -filter parameter
$count = 0
ls -filter "*1080p*" | % { Rename-item $_ "NewFile$count.ext";$count++}
Careful, that will rename all files in current directory with "1080p" in the name to newfile0.ext.. just an example
Related
I would like to use PowerShell to add a line break for every tilde it finds in a file.
The source could contain main .in files which contain tildes.
I have this script so far, and could benefit by some assistance in how to tweak it.
This will work for one file, but not for many:
(Get-Content -Path '.\amalgamatedack.in') |
ForEach-Object {$_.Replace('~', "~`r`n")} |
Set-Content -Path '.\amalgamatedack.in'
You can use Get-ChildItem to find all your .in files, then follow the same logic, just replace the input and output hardcoded file name for the absolute path of each file (.FullName property).
Your code could also benefit by using Get-Content -Raw, assuming these files are not very big and they fit in memory, reading the content as single multi-line string is always faster.
# If you need to search recursively for the files use `-Recurse`
Get-ChildItem path\to\sourcefolder -Filter *.in | ForEach-Object {
($_ | Get-Content -Raw).Replace('~', "~`r`n") |
Set-Content -Path $_.FullName
}
I have a special need and I feel stuck on that..
Some user will put some file in a directory with several different name, and I need to rename them regarding a special pattern for those files to be consume by another app.
Example:
In directory -> Target
file1-dd-mm-yyyy -> file1
file2 -> thisfile2
flie45224 -> file123
So as you can see this can be some variables, dates, ID etc..
The target will always be the same but the file in source can be different because of date for example.
So first I had 2 files, so I write the script in plain text "If test-path blabla do this else go out" but it seems that now I will have 37 different files with all differents name. So I thought about using an excel sheet(CSV?), but I can't really find any help on this need.
The goal is to have a sheet as "pattern" like if you found file like in 'A1' then rename as in 'A2' etc...
Do you guys have an idea ?
Thanks by advance :)
I understand you need a csv with the following columns:
A1: regex/pattern to match
A2: transform rule which should be
dynamic
The trick is to use scriptblock if you want to use variables like the file name.
Basically, your csv will be:
A1;A2
"^file1-\d\d-\d\d-\d\d\d\d$";"file1"
"^file2$";"this$($file.Name)"
"^flie*";"file123"
And the code would be:
$myRules = Import-Csv "C:\xxx\test.csv" -Delimiter ";"
$files = gci C:\temp\
foreach ($file in $files) {
foreach ($rule in $myRules) {
if ($file.Name -match $rule.A1) {
Write-host "$($file.Name) is matching pattern ""$($rule.A1)"". Applying rename to ""$($rule.A2)"""
$NewScriptBlock = [scriptblock]::Create("rename-item -Path $($file.FullName) -NewName ""$($rule.A2)""")
$NewScriptBlock.Invoke()
}
}
}
Which gives before:
file1-01-02-0344
file2
flie45224
Output during the execution:
file1-01-02-0344 is matching pattern "^file1-\d\d-\d\d-\d\d\d\d$". Applying rename to "file1"
file2 is matching pattern "^file2$". Applying rename to "this$($file.Name)"
flie45224 is matching pattern "^flie*". Applying rename to "file123"
And after:
file1
thisfile2
file123
Explanations
The first foreach is parsing the files. Then for each of those files, we are checking if one of the rule is matching thanks to the -match $rule.A1.
With the first example, you can use regexp (\d to match digits). For the other cases, I kept it simple as you didn't clarify the rules but this will be your homework :)
Then in the transform rules, you can use the filename variable as shown in the second transform rule: this$($file.Name)
NB: it could be a good idea to add a flag to leave the loop for the current file once it has been renamed to avoid unecessary check and to display a message if the file hasn't match any pattern.
Seems a bit odd, I suspect you should be able to use a regex pattern instead but can't say without seeing the csv contents. Otherwise try this. Assumes the CSV has a column headers called First and Second, First matches the basename (no extension) of the file and Second contains the basename you want it changed to.
$csv = Import-Csv -Path c:\filenames.csv
Get-ChildItem -Path c:\temp | %{if($csv.First -contains $_.BaseName){Rename-Item -Path $_.FullName -NewName "$($csv.Second[$csv.First.IndexOf($_.BaseName)]+$_.Extension)"}}
I have a bunch of file which I like to copy or duplicate in the same folder but renaming part of the filename during the copying...
Ex.
Copying these files
¸Ó¸®30_³²_0.pal
¸Ó¸®30_³²_1.pal
¸Ó¸®30_³²_2.pal
¸Ó¸®30_³²_3.pal
¸Ó¸®30_³²_10.pal
¸Ó¸®30_³²_11.pal
¸Ó¸®30_³²_12.pal
But must be renamed to these
¸Ó¸®31_³²_0.pal
¸Ó¸®31_³²_1.pal
¸Ó¸®31_³²_2.pal
¸Ó¸®31_³²_3.pal
¸Ó¸®31_³²_10.pal
¸Ó¸®31_³²_11.pal
¸Ó¸®31_³²_12.pal
Also I want an input of what to copy and what it will be renamed to...
I only need to input 30_ for the files to copy then input 31_ or 41_ for the copied files..
If it's not possible for input.. I can do with hard coded value...
Update:
I found a code that copies and renames the files..
Get-ChildItem '*30_*.pal' -recurs | % {
$copyto = $_.FullName -replace "30_","41_"
Copy-Item $_.FullName $copyto
}
The input is what's missing now.. and I don't know how to do it...
This should replace the each file if your get-childitem is working properly
Get-ChildItem '*30_*.pal' -Recurse |% {$_.Replace('30','31')}
Ranadip Dutta's answer is good, but the replace might give issues if the second set of numbers ever contains a 30...for example, if there are more files in the group and you have one:
¸Ó¸®30_³²_30.pal
It would get renamed to:
¸Ó¸®31_³²_31.pal
In order to avoid this, use more identifying characters in the Replace to be sure that you are replacing the number in the correct location in the file, like this:
Get-ChildItem '*30_*.pal' -Recurse |% {$_.Replace('®30','®31')}
I know this question was already asked by someone but I will ask again.
Can someone tell me how to rename in bulk and in ascending order if possible in CMD. I already tried renaming in powershell but to no avail. It only let me use once and I need to rename another folder files but to no avail. It didn't let it rename files in another folder. This is the code I use in powershell:
$i = 1
Get-ChildItem *.mkv | %{Rename-Item $_ -NewName ('Haikyuu - {0:D2}.mkv' -f $i++)}
I'm renaming my anime series per folder and some of my copies have 100+ videos. and somehow you could teach me what each code mean (the code that must use in CMD). The ones I've searched can't understand it in layman's term or doesn't tell the user how it's supposed to work. Thank you in advance. by the way, the folder is placed in an external drive.
so from the beginning:
$i= variable for storing the initial value 1
Get-ChildItem = is like "dir" which lists the files and folder under a certain path.
In this case, it is listing all the files which starts with anything but have the extension .mkv
* indicates wildcard.
| = pipeline which passes the output of the first command as an input of the next command.
% = ForEach-Object is iterating each object one by one coming from the pipeline.
$_= Current pipeline object . Here it is taking each object one by one and renaming it using Rename-Item
-NewName = is the parameter of the Rename-Item which asks for the new name to pass.
Hope it clarifies your need.
The reason why I can't rename my video files is there were [brackets] on the filename.
So I use this:
Get-ChildItem -Recurse -Include *.mkv | Rename-Item -NewName { $_.Name.replace("[","").replace("]","").replace("(","").replace(")","") }
Which on the same directories, I can access subfolders too to omit brackets and parethesis. then I proceed using the code above in the question to rename my files in every folder. The Reason why I'm doing the 'renaming' per folder is that, each folder is different anime series. but the code above is working.
if anyone can give me less code than repeating the 'replace' and concatenating it, I will gladly accept and choose that as the best answer. :)
If you use the parameter -LiteralPath for the source, no prior renaming is necessary.
%i = 1
Get-ChildItem *.mkv |
ForEach {Rename-Item -LiteralPath "$_" -NewName ('Haikyuu - {0:D2}.mkv' -f $i++)}
A hint on sorting, I hope the present numbering of the source files has a constant width, otherwise the result is mixed up as an alphabetic sort (which is inherent to ntfs formatted drives) will sort the number 10 in front of 2.
To check this append the parameter -whatif to the Rename-Item command
Anyone have any ideas on how to rename files by finding an association with an index file?
I have a file/folder structure like the following:
Folder name = "Doe, John EO11-123"
Several files under this folder
The index file(MS Excel) has several columns. It contains the names in 2 columns(First and Last). It also has a column containing the number EO11-123.
What I would like to do is write maybe a script to look at the folder names in a directory, compare/find an associated value in the index file(like that number EO11-123) and then rename all the files under the folder using a 4th column value in the index.
So,
Folder name = "Doe, John EO11-123", index column1 contains same value "EO11-123", use column2 value "111111_000000" and rename all the files under that directory folder to "111111_000000_0", "111111_000000_1", "111111_000000_2" and so on.
This possible with powershell or vbscript?
Ok, I'll answer your questions in your comment first. Importing the data into PowerShell allows you to make an array in powershell that you can match against, or better yet make a HashTable to reference for your renaming purposes. I'll get into that later, but it's way better than trying to have PowerShell talk to Excel and use Excel's search functions because this way it's all in PowerShell and there's no third party application dependencies. As for importing, that script is a function that you can load into your current session, so you run that function and it will automatically take care of the import for you (it opens Excel, then opens the XLS(x) file, saves it as a temp CSV file, closes Excel, imports that CSV file into PowerShell, and then deletes the temp file).
Now, you did not state what your XLS file looks like, so I'm going to assume it's got a header row, and looks something like this:
FirstName | Last Name | Identifier | FileCode
Joe | Shmoe | XA22-573 | JS573
John | Doe | EO11-123 | JD123
If that's not your format, you'll need to either adapt my code, or your file, or both.
So, how do we do this? First, download, save, and if needed unblock the script to Import-XLS. Then we will dot source that file to load the function into the current PowerShell session. Once we have the function we will run it and assign the results to a variable. Then we can make an empty hashtable, and for each record in the imported array create an entry in the hashtable where the 'Identifier' property (in your example above that would be the one that has the value "EO11-123" in it), make that the Key, then make the entire record the value. So, so far we have this:
#Load function into current session
. C:\Path\To\Import-XLS.ps1
$RefArray = Import-XLS C:\Path\To\file.xls
$RefHash = #{}
$RefArray | ForEach( $RefHash.Add($_.Identifier, $_)}
Now you should be able to reference the identifier to access any of the properties for the associated record such as:
PS C:\> $RefHash['EO11-123'].FileCode
JD123
Now, we just need to extract that name from the folder, and rename all the files in it. Pretty straight forward from here.
Get-ChildItem c:\Path\to\Folders -directory | Where{$_.Name -match "(?<= )(\S+)$"}|
ForEach{
$Files = Get-ChildItem $_.FullName
$NewName = $RefHash['$($Matches[1])'].FileCode
For($i = 1;$i -lt $files.count;$i++){
$Files[$i] | Rename-Item -New "$NewName_$i"
}
}
Edit: Ok, let's break down the rename process here. It is a lot of piping here, so I'll try and take it step by step. First off we have Get-ChildItem that gets a list of folders for the path you specify. That part's straight forward enough. Then it pipes to a Where statement, that filters the results checking each one's name to see if it matches the Regular Expression "(?<= )(\S+)$". If you are unfamiliar with how regular expressions work you can see a fairly good breakdown of it at https://regex101.com/r/zW8sW1/1. What that does is matches any folders that have more than one "word" in the name, and captures the last "word". It saves that in the automatic variable $Matches, and since it captured text, that gets assigned to $Matches[1]. Now the code breaks down here because your CSV isn't laid out like I had assumed, and you want the files named differently. We'll have to make some adjustments on the fly.
So, those folder that pass the filter will get piped into a ForEach loop (which I had a typo in previously and had a ( instead of {, that's fixed now). So for each of those folders it starts off by getting a list of files within that folder and assigning them to the variable $Files. It also sets up the $NewName variable, but since you don't have a column in your CSV named 'FileCode' that line won't work for you. It uses the $Matches automatic variable that I mentioned earlier to reference the hashtable that we setup with all of the Identifier codes, and then looks at a property of that specific record to setup the new name to assign to files. Since what you want and what I assumed are different, and your CSV has different properties we'll re-work both the previous Where statement, and this line a little bit. Here's how that bit of the script will now read:
Get-ChildItem c:\Path\to\Folders -directory | Where{$_.Name -match "^(.+?), .*? (\S+)$"}|
ForEach{
$Files = Get-ChildItem $_.FullName
$NewName = $Matches[2] + "_" + $Matches[1]
That now matches the folder name in the Where statement and captures 2 things. The first thing it grabs is everything at the beginning of the name before the comma. Then it skips everything until it gets tho the last piece of text at the end of the name and captures everything after the last space. New breakdown on RegEx101: https://regex101.com/r/zW8sW1/2
So you want the ID_LName, which can be gotten from the folder name, there's really no need to even use your CSV file at this point I don't think. We build the new name of the files based off the automatic $Matches variable using the second capture group and the first capture group and putting an underscore between them. Then we just iterate through the files with a For loop basing it off how many files were found. So we start with the first file in the array $Files (record 0), add that to the $NewName with an underscore, and use that to rename the file.