remove random text from file name - powershell

I have a folder full of files which have had some text prepended to the filenames. For example:
program1.m has become John Smith 23423_file_program1.m.
program2.m has become Jane Doe 235_file_program2.m.
The number of characters that have been prepended is not consistent, but the substring file_ is always the final set of characters I wish to remove. Is there anyway to remove all characters up to and including the file_ in a folder full of files? This was my attempt, but as expect the * does not work in this scenario:
get-childitem *.m | foreach { rename-item $_ $_.Name.Replace("*file_","") }

This should do the trick. There are other ways to do this as well so don't be surprised if you find another one.
get-childitem *.m -Filter *.m | ForEach{
Rename-Item -Path $_.FullName -NewName ($_.Name -replace ".*file_")
}
Or shorter
get-childitem -Filter *.m | Rename-Item -NewName {$_.Name -replace ".*file_"}
You had the right idea but the issue you have is the string .replace() method is looking to match static strings and does not use wildcards. The way you had it it expected an asterisks to appear in the string which one did not.
Instead we use -replace which supports regex. .*file_ would satisfy the requirement of remov[ing] all characters up to and including the _file. Since you just want it removed we don't offer a replacement string.
If regex is not your friend you should try and warm up to him. If not some old school methods work just as well.
$file = "blah_file_program.m"
$file.Substring($file.LastIndexOf("_") + 1)
program.m

Related

Appending string to the end of all file names in PowerShell

I have files look like
data.svg
map.svg
aplicationp.svg
...
*.svg
I am trying to add -b string to the end of all files names bu using power shell rename command like
D:\icons> Dir | Rename-Item -NewName {$_.name -replace ".","-b."}
to get these
data-b.svg
map-b.svg
application-b.svg
but this is not changing anything. How can I achieve this?
Powershell's -replace operator is based on regular expressions. And since . is a wildcard in regex, what should be happening is that each character in the file name is being replaced with the resulting string. So test.txt would become -b.-b.-b.-b.-b.-b.-b in your example.
You likely want to use the Replace method of the .NET String type like this instead.
dir | Rename-Item -NewName { $_.Name.Replace('.','-b.') }
If you want to keep using -replace, you need to escape the . in your expression like this.
dir | Rename-Item -NewName { $_.Name -replace '\.','-b.' }
Both of these have a couple edge case problems that you may want to avoid. The first is narrowing the scope of your dir (which is just an alias for Get-ChildItem) to avoid including files or directories you don't actually want to rename. The second is that a simple replace in the file name doesn't account for file names that contain multiple dots. So you may want to ultimately do something like this if you only care about SVG files that may have multiple dots.
Get-ChildItem *.svg -File | Rename-Item -NewName { "$($_.BaseName)-b$($_.Extension)" }
The replace operator uses regex. Therefore your . needs to be escaped, otherwise it just stands for any character. I would generally make sure to be as specific as possible when writing regexes. The following is a possible solution
Get-ChildItem *.svg | Rename-Item -NewName { $_.name -Replace '\.svg$','-c.svg' }
The $ anchors the expression to the end of the string which makes sure it only changes the extension and not any other text inside the file names.

Removing Parts of a File Name based on a Delimiter

I have various file names that are categorized in two different ways. They either just have a code like: "866655" or contain a suffix and prefix "eu_866655_001". My hope is to write to a text file the names of files in the same format. I cannot figure out a successful method for removing the suffix and prefix.
Currently this what I have in my loop in Powershell:
$docs = Get-ChildItem -Path $source | Where-Object {$_.Name -match '.doc*'}
if ($docs.basename -contians 'eu_*')
{
Write-Output ([io.fileinfo]"$doc").basename.split("_")
}
I'm hoping to turn "eu_866655_001" into "866655" by using "_" as the delimiter.
I'm aware that the answer is staring me down but I still can't seem to figure it out.
You could do something like the following. Feel free to tweak the -Filter on the Get-ChildItem command.
$source = 'c:\path\*'
$docs = Get-ChildItem -Path $source -File -Filter "*_*_*" -Include '*.doc','*.docx'
$docs | Rename-Item -NewName { "{0}{1}" -f $_.Basename.Split('_')[1],$_.Extension }
The important things to remember is that in order to use the -Include switch, you need an * at the end of the -Path value.
Explanation:
-Filter allows us to filter on names that contain two underscores separating three substrings.
-Include allows us to only list files ending in extensions .docx and .doc.
Rename-Item -NewName supports delayed script binding. This allows us use a scriptblock to perform any necessary operations for each piped object (each file).
Since the target files will always have two underscores, the .Split('_') method will result in an three index array delimited by the _. You have specified that you always want the second delimited substring and that is represented by index 1 ([1]).
The format operator (-f) puts the substring and extension together, completing the file name.

Rename-Item renaming issue

I am wrote some code and the first time it worked fine. However, I've now replaced the files with new dummy files and I'm now getting the following:
MyTestFile.zip is changed to MyTestFile_zip.zip_zip.zip
MyTestFile.prd is changed to MyTestFile_prd.prd_prd.prd
Here's the code:
Get-ChildItem -Filter "*.prd" -Recurse | Rename-Item -NewName {$_.name -replace '.prd','_prd.prd'}
Get-ChildItem -Filter "*.zip" -Recurse | Rename-Item -NewName {$_.name -replace '.zip','_zip.zip'}
Got any ideas how I can avoid this problem?
Thanks
The -replace operator
takes a regular expression as its first operand and
performs substring matching by default.
Therefore, you must modify the regex that is the first operand for the replacement to work as intended:
$_.Name -replace '\.prd$','_prd.prd'
. is escaped as \. to make sure that -replace treats it as a literal; without the \, . would match any character.
$ ensures that the expression is anchored to the end of the input, i.e., only matches at the end.
A more generic reformulation that covers both .prd and .zip:
$_.Name -replace '\.(prd|zip)$','_$1.$1'
See below for an explanation.
If we put this all together, we can get away with a single pipeline:
Get-ChildItem -File *.prd, *.zip -Recurse |
Rename-Item -NewName { $_.Name -replace '\.(prd|zip)$','_$1.$1' }
Use of regular expressions allows you to process more than one extension at a time, and also allow you to reference parts of what the regular expression matched (captured) through capture groups (parenthesized subexpressions) that you can reference as $1 (1st capture group, ...) in the replacement string
> #( 'example.zip', 'example.prd' ) -replace '\.(prd|zip)$','_$1.$1'
example_zip.zip
example_prd.prd
Note how $1 in the replacement string refers to whatever capture group (prd|zip) captured, which is zip for the first input, and prd for the second.
Editor's note:
While this answer doesn't work for the specific question at hand, because it inserts an extraneous ., it does show the use of [System.IO.Path]::ChangeExtension() as a robust way to change a file's extension in general.
Alternatively use the .net method to change the file extension:
Get-ChildItem -Filter "*.prd" -Recurse | Rename-Item -NewName {[System.IO.Path]::ChangeExtension($_.name,"_prd.prd")}

bulk rename using powershell to get rid of 9 characters that follow a "-"

I need to rename around 5000 files that have the following naming format:
"322xxx-710yy.tiff"
i need to remove -710yy from the name to get 322xxxx.tiff
can anyone suggest a rename-item command for power-shell to do this?
i tried:
get-childitem -filter "322*" -recurse | Rename-item -NewName{$_.name -replace '-710*', ''}
but all that does is remove the "710" leaving the remaining characters after it.
-replace takes a regex, not a wildcard match (unlike the -Filter parameter of Get-ChildItem), so you need
$_.Name -replace '-710[^.]*'
instead (you can also leave out the , '' in that case, as it's implied). Note that I'm only replacing non-dot characters after the 710, to keep the extension intact.

Why won't it rename the file? Powershell

Can someone tell me why this script won't work?
Get-ChildItem "\\fhnsrv01\home\aborgetti\Documentation\Stage" -Filter *.EDIPROD | `
Foreach-Object{
$content = Get-Content $_.FullName
#filter and save content to a new file
$content | Where-Object {$_ -match 'T042456'} | Rename-Item `
($_.BaseName+'_834.txt')
I found this syntax from another question on here and changed the environment variables.
For some reason it won't change the name of the file. The filename is
'AIDOCCAI.D051414.T042456.MO.EDIPROD'
Help much appreciated.
UPDATE
Thanks to TheMadTechnician I was able to get some working stuff. Great stuff actually. Figure I should share with the world!
#Call Bluezone to do file transfer
#start-process "\\fhnsrv01\home\aborgetti\Documentation\Projects\Automation\OpenBZ.bat"
#Variable Declarations
$a = Get-Date
$b = $a.ToString('MMddyy')
$source = "\\fhnsrv01\home\aborgetti\Documentation\Stage\"
$dest = "\\fhnsrv01\home\aborgetti\Documentation\Stage\orig"
#Find all the files that have EDIPROD extension and proceed to process them
#First copy the original file to the orig folder before any manipulation takes place
Copy-item $source\*.EDIPROD $dest
# Now we must rename the items that are in the table
Switch(GCI \\fhnsrv01\home\aborgetti\Documentation\Stage\*.EDIPROD){
{(GC $_|Select -first 1) -match "834*"}{$_ | Rename-Item -NewName {$_.BaseName+'_834.txt'}}
{(GC $_|Select -first 1) -match "820*"}{$_ | Rename-Item -NewName {$_.BaseName+'_820.txt'}}
}
Get-ChildItem's -Filter has issues, I really hesitate to use it in general. If it were up to me I'd do something like this:
Get-ChildItem "\\fhnsrv01\home\aborgetti\Documentation\Stage" |
?{$_.Extension -match ".EDIPROD" -and $_.name -match "T042456"}|
%{$_.MoveTo($_.FullName+"_834.txt")}
Well, I would put it all on one line, but you can line break after the pipe and it does make it a little easier to read, so there you have it. I'm rambling, sorry.
Edit: Wow, I didn't even address what was wrong with your script. Sorry, kind of distracted at the end of my work day here. So, why doesn't your script work? Here's why:
You pull a file and folder listing for the chosen path. That's great, it should work, more or less, I have almost no faith in the -Filter capabilities of the file system provider, but anyway, moving on!
You take that list and run it through a ForEach loop processing each file that matches your filter as such:
You read the contents of the file, and store them in the variable $content
You run the contents of the file, line by line, there a Where filter looking for the text "T042456"
For each line that matches that text you attempt to rename something to that line's basename plus _834.txt (the line of text is a string, it doesn't have a basename property, and it's not an object that can be renamed, so this is going to fail)
So, that's where the issue is. You're pulling the contents of the file, and parsing that line by line trying to match the text instead of matching against the file name. If you removed Everything after the first pipe up to the Where statement, and then for your rename-item put -newname before your desired name, and change the ( ) to { } that goes around the new name, and you would be set. Your code would work. So, your code, modified as I said, would look like:
Get-ChildItem "\\fhnsrv01\home\aborgetti\Documentation\Stage" -Filter *.EDIPROD |
Where-Object {$_ -match 'T042456'} | Rename-Item -NewName {$_.BaseName+'_834.txt'}
Though I have a feeling you want $.Name and not $.BaseName. Using $_.BaseName will leave you with (to use your example file name):
'AIDOCCAI.D051414.T042456.MO_834.txt`
Edit2: Really that's a whole different question, how to match multiple criteria, but the question is here, I'm here, why not just get it done?
So, you have multiple criteria for matching the file names. That really doesn't affect your loop to be honest, what it does affect is the Where statement. If you have multiple options what you probably want is a RegEx match. Totally doable! I'm only going to address the Where statement (?{ }) here, this won't change anything else in the script.
We leave the extension part, but we're going to need to modify the file name part. With RegEx you can match against alternative text by putting it in parenthesis and splitting up the various options with a pipe character. So it would look something like this:
"(T042456|T195917|T048585)"
Now we can incorporate that into the rest of the Where statement and it looks like this:
?{$_.Extension -match ".EDIPROD" -and $_.name -match "(T042456|T195917|T048585)"}
or in your script:
Where-Object {$_ -match "(T042456|T195917|T048585)"}
Edit3: Hm, need the first line for the qualifier. That complicates things a bit. Ok, so what I'm thinking is to get our directory listing, get the first line of each file with the desired extension, make an object that has two properties, the first property is the fileinfo object for the file, and the other property will be the first line of the file. Wait, I think we can do better. Switch (GCI *.EDIPROD){(get-content|select -first 1) -match 820}{Rename 820};{blah blah -match 834}{rename 834}}. Yeah, that should work. Ok, actual script, not theoretical gibberish script time. This way if you have other things to look for you can just add lines for them.
Switch(GCI \\fhnsrv01\home\aborgetti\Documentation\Stage\*.EDIPROD){
{(GC $_|Select -first 1).substring(177) -match "^834"}{$_ | Rename-Item -NewName {"834Dailyin$b"};Continue}
{(GC $_|Select -first 1).substring(177) -match "^820"}{$_ | Rename-Item -NewName {$_.BaseName+'_820.txt'};Continue}
}
Again, if you want the EDIPROD part to remain in the file name change $_.BaseName to $_.Name. Switch is pretty awesome if you're trying to match against different things and perform different actions depending on what the results are. If you aren't familiar with it you may want to go flex your google muscles and check it out.
Hm, alternatively we could have gotten the first line inside the Where filter, run a regex match against that, and renamed the file based on the regex match.
GCI \\fhnsrv01\home\aborgetti\Documentation\Stage\*.EDIPROD | ?{(GC $_ | Select -First 1) -match "(820|834)"}|Rename-Item -NewName {$_.Name+"_"+$Matches[1]+".txt"}
Then you just have to update the Where statement to include anything you're trying to match against. That's kind of sexy, though not as versatile as the switch. But for just simple search and rename it works fine.
Try it like this way
Get-ChildItem -Filter "*T042456*" -Recurse | % {Rename-Item $_ "$_ _834.txt"}