0

I have a 100 files Which are named for instance: (Without quotes)

"Managing and Improving Own Learning [L3] {CBA849}" and

"Note-taking and Note-making [L3] {CBA851}"

I would like to rename it in a such way that it only shows "CBA849" and "CBA851" and remove anything else.

Another words I would like to keep file code inside {....} curly brackets.

Is there a way we can implement this? (Note: It's not replacing characters)

Thanks

3 Answers 3

2
Rename-Item -LiteralPath $path ([regex]::match($path, '{(.+)}')).Groups[1].Value
  • You need -LiteralPath because the filename contains brackets.
  • [regex]::match($path, '{(.+)}') matches the curly braces and their contents, and captures the contents into a match group. .Groups[1].Value returns the value of the first (and in this case, the only) match group.
  • This assumes that all the files are named in the format shown in the question. If it's possible that there might be curly braces elsewhere in the name, change the regex {(.+)} to {(.+?)}$.
Sign up to request clarification or add additional context in comments.

5 Comments

TheMadTechnician raises a good question: Are these the full filenames, and do you want the full filename to be the part between the curly braces, with no extensions, or did you leave the extensions out of the description because you assumed that they'd be preserved when the file is renamed? If there are extensions, the regex match would need to include them. Please clarify.
I ended up modifying mine to match against the BaseName, and included the Extension property to preserve any extension on the file. Not sure how that would work with your answer, but it's something to consider.
@TheMadTechnician To preserve the extension (if any) I'd add + (Get-Item -LiteralPath $path).Extension to the NewName argument. Not editing the answer for now, because until we here from the OP on this point, I'm going too assume that "remove anything else" means remove anything else. ;)
Hi Guys,Sorry if I have confused you. My question is I have 100 files named like this: file1: "Managing and Improving Own Learning [L3] {CBA849}" and File2:"Note-taking and Note-making [L3] {CBA851}" File3: .....{CBA561}. All I am interested in what's in the {} brackets. I want my files to renamed it to "CBA851"..... and so on striping of all other string from it. So at the end my file names would look like File1:"CBA849.pdf" and File2:"CBA851.pdf"........File(n):".......pdf" hope this is clear. thanks
The idea was that once I have finished converting ".docx" to ".pdf" then i would go and run above to strip of the sting.
1

I'd personally use a Regex match:

GCI $path | ?{$_.Name -match "(?:.*?{)(.*?)(?:})(\..*)?$"}|%{$_.MoveTo("$($_.Directory)\$($matches[1])$($matches[2])")}

Edit: As Adi Inbar says, I have created an overly complicated RegEx pattern. Simplified as he suggested (though still allowing for extensions) is a revised answer:

GCI $path | ?{$_.BaseName -match "{(.*?)}$"}|%{$_.MoveTo("$($_.Directory)\$($matches[1])$($_.Extension)")}

Edit: Ok, here's the breakdown...

GCI is short for Get-ChildItem, it pulls a listing of the directory specified, but I think you probably figured that one out.

Then it pipes to a Where{} clause(? is an alias for Where). It matches the BaseName of the files and folders provided by the GCI command. The BaseName property is actually one generated by PowerShell that takes the name of the file, extension and all, and then removes the extension (with preceding period) from it so if the file name is Sample.txt then it provides you with Sample as the BaseName.

It matches that against a RegEx (short for Regular Expression) pattern. If you don't know what RegEx is, please feel free to look it up and read up on it (Google is your friend). The basics is that it matches a pattern instead of actual text. In this case the pattern is anything at the end of the file name that is between curly braces.

Past that it enters a ForEach loop (I used the % alias for ForEach). For each file that matched the RegEx pattern it performs the MoveTo() method for that file. The location that it is moving it to is that file's current directory (gotten with $.Directory), followed by a backslash, followed by $Matches[1] (I'll get to that in a second), and then the original extension of the file (gotten with $.Extension). Now you'll see I wrapped the Directory and Extension in a sub-expression $() because with string extrapolation (how it auto-magically expands variables if you put them within double quotes) if you try to specify a property of a variable you have to put it in a sub-expression. Otherwise it tries to expand just the variable itself, and shows the .Whatever property name in plain text.

Lastly, $Matches is an automatic variable that is populated when you make a match with a few things (such as <something> -match <something else> like we did in the Where clause). The first record of it is the whole string that was matched <something>, and then the next records are the matches based on <something else>.

I hope that clears it all up for you. If you have specific questions let me know. If this answer resolved your question please mark it as accepted.

4 Comments

A couple of pointers about the regex: 1. There's no need to match the text before the opening brace with .*?. A regex doesn't have to match the entire string, just part of it, so it should only focus on parts you want to match, no need for a universal match for the remainder. 2. It's redundant to use both a match group and non-capturing groups for this purpose. The value of the match group, which is all you're using, is exactly the same with {(.*?)} as with (?:{)(.*?)(?:}). You could also use (?:{).*?(?:}), and then use the entire match ($matches[0]), but no need for both.
@AdiInbar Thanks for the reminder! I had actually done multiple matching groups because (while the user didn't specify) I was allowing for extensions. I couldn't remember if you can do it without non-capturing groups, so decided to error on the side of caution, but I do appreciate the reminders. I'll update my answer with the shorter RegEx as suggested.
Good question about the extensions. I answered the question literally as asked--if he says he wants the filenames to be just the part inside the curly braces "and remove anything else", that's what he's going to get. But if he assumed that extensions are out of scope and assumed that they'll be preserved, that won't happen unless they're included in the match.
this code worked for me: Excellent @TheMadTechnician You sould be called ThePowerTechnician: Thanks a lot GCI $path | ?{$_.BaseName -match "{(.*?)}$"}|%{$_.MoveTo("$($_.Directory)\$($matches[1])$($_.Extension)")}. Bit of explanation would be really helpful how it works
0
$f=gi $filepath;
$f.MoveTo($f.fullname.Replace($f.name,$f.name.substring($f.name.indexof("{")+1,($f.name.indexof("}")-1)-$f.name.indexof("{"))+$f.extension))
  1. Get the File you're looking to rename as a [System.IO.FileInfo] object using get-item (gi).
  2. Once you have the file object in $f the script is doing:

    • MoveTo
    • $f.FullName: The full path of the existing file (C:\some\dir\Test {ABC123}.txt)
    • Modify FullName to be the new filename by using the Replace function to replace the old filename ($f.name), with the desired name
      • The Substring function of the filename will allow you to get just the string between the curly braces.
        • Find the index of the OpenCurlyBracket within the name string
        • Find the index of the CloseCurlyBracket within the name string
      • Once the text between the curly brackets is identified with the Substring function, append the file extension to the new filename

3 Comments

Be careful of the MoveTo method. If you don't specify the full path, it will move the file to the .NET working directory, which is the working directory at the start of the PowerShell session (usually the user profile directory), so what you have there would typically move the files to C:\Users\<username>\CBA849, etc. So if you want to do it this way, you need to add "$pwd\" + at the beginning of the path argument. Personally I think it's better to just stick to Rename-Item and Move-Item.
Thanks, updated with $f.FullName path to ensure the file stays in its original location.
Some elaboration may be in order on what powershell is doing here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.