File Name Contains Certain Text - powershell

I know this is a new guy question, but I cant find anything. I think the issue might have to do with variable type issue?
I'm trying to look at a files name and see if pattern1 is contained in the file name. If so then replace the pattern text with "TEST".
Right now it doesn't error out, but it skips the IF, I do have files with the pattern in the directory.
Can't insert actually code, so here is a sample
$pattern1 = "January"
$pattern2 = "December 31"
$path = "C:\Users\...\METRICS-TEST\Metrics 2014\January 2014 Client Metrics"
$search_results = Get-ChildItem -Path $path | Where-Object { ((! $_.PSIsContainer))}
foreach ($file in $search_results) {
if($file.Name -contains $pattern1){
$new_name = $file.Name -replace $pattern1, "TEST1"
Rename-Item -Path $file.FullName -NewName $new_name
}else{
$new_name = $file.Name -replace $pattern2, "TEST2"
Rename-Item -Path $file.FullName -NewName $new_name
}
}

-contains work on collections, not strings.
For strings, you'd want either -match (for RegEx matching) or -like for simple wildcard matching:
$file.name -match $pattern1
$file.name -like "*$pattern1*"
-contains would be appropriate if you had an array of strings and wanted to know if it contained one or more copies of a specific string:
$Strings = "abc","def","ghi","jkl"
# This evaluates to true
$Strings -contains "abc"
# This evaluates to false
$Strings -contains "ab"

The whole issue is that you use -Contains where you should use -Match. Try this though, it's easily expandable if you have more conditions to add:
$pattern1 = "January"
$pattern2 = "December 31"
$path = "C:\Users\...\METRICS-TEST\Metrics 2014\January 2014 Client Metrics"
Switch(Get-ChildItem -Path $path){
{$_.Name -match $pattern1}{$new_name = $_.Name -replace $pattern1, "TEST1"
Rename-Item -Path $_.FullName -NewName $new_name}
{$_.Name -match $pattern2}{$new_name = $_.Name -replace $pattern2, "TEST2"
Rename-Item -Path $_.FullName -NewName $new_name}
}

I realize I have an accepted answer, but I thought another elegant way to handle this would be mapping Old-To-New in a hashtable, matching against the keys of that hashtable (regex escaped and joined with pipes to form the regex match pattern), and then renaming in a ForEach against the matches rather than a switch. I suppose at this point it's all academic.
$path = "C:\Users\...\METRICS-TEST\Metrics 2014\January 2014 Client Metrics"
$RenameMap = #{
"January" = "Test1"
"December 31" = "Test2"
}
$Pattern = "($(($RenameMap.keys|ForEach{[regex]::Escape($_)}) -join "|"))"
Get-ChildItem $Path | Where{$_.Name -match $Pattern} | ForEach {Rename-Item $_.FullName -NewName ($_.Name -Replace $Matches[1],$RenameMap[$Matches[1]])}

Related

Replacing only part of the file name in Powershell

I got a problem with powershell and some pdfs names
So there is a bunch of them:
2021_01_21_Aneks_nr2.pdf
2021_11_31_Aneks_nr3.pdf
2021_05_04_Aneks_nr4.pdf
I need to replace "_" with "-" but only near date.
Output should look like this:
2021-05-04_Aneks_nr4.pdf
I'm new to programming and couldn't find solution in internet.
I was using this code :
Get-Childitem | foreach { rename item $_ $_.Name.Replace("_","-") }
But it works on all "_" so I cant use it in this scenario.
Thanks for help! :)
Using the -replace operator instead of the dot net method you can use regex. And there you can specify to replace only underlines between digits:
Get-ChildItem |
ForEach-Object {
Rename-Item -Path $_.FullName -NewName $($_.Name -replace '(?<=\d)_(?=\d)', '-')
}
Here you go
#Loop through files
get-childitem [path] | ForEach-Object {
#match pattern
$null = $_.name -match '\d{4}_\d{2}_\d{2}'
#get matching pattern
$pattern = $matches[0]
#replace _ with -
$replace = $pattern -replace '_','-'
#build new name
$newName = $_.name -replace $pattern,$replace
#rename file
rename-item -Path $_.fullname -NewName $newName
}
It matches the current name of the file for the pattern '\d{4}_\d{2}_\d{2}', gets the matching string, replaces _ with - and finally build the new name by replacing the matching string with the updated version.

Rename-Items twice in the same pipeline using powershell

I'm trying to rename a bunch of files using powershell by removing the prefix (which is the same in all files), replacing "+" with a space and setting the remainder to title case. Here's what I have so far:
Where-Object { $_ -Match '^Website\.com_+' } |
ForEach-Object
{
$_ |
Rename-Item -NewName {$_.Name -replace 'Website\.com_','' -replace '\+',' '};
Rename-Item $_.Fullname (Get-Culture).TextInfo.ToTitleCase($_)
}
The first rename works, it removes and formats files properly, but then the second rename says the items don't exist, which makes me think I should just then pass them into another foreach loop in another pipe, but I can't seem to make that work either.
It seems like having 2 rename-items isn't really working and I tried having the title case with the replace and it doesn't seem to work either.
It would be more straight forward to build the name in 2 stages and then do one Rename-Item
Something like below should do what you need
Where-Object { $_ -Match '^Website\.com_+' } |
ForEach-Object {
$BaseName = ($_.Name -replace 'website\.com','' -replace '\+','')
$FinalName = (Get-Culture).TextInfo.ToTitleCase($BaseName)
Rename-Item $_.FullName -NewName $FinalName
}
$_ in your ForEach-Object loop is a snapshot of the item - it won't dynamically change to follow things you do to the underlying file. When you rename the item, $_ represents the old name. So, when you attempt the second rename based on $_.FullName, Rename-Item won't find anything.
A potential solution to your problem of "setting the remainder to title case" would be, outside the loop, do another Get-ChildItem search for anything that falls into this condition, and then rename them separately.
Finally found something that works:
$path = "G:\Downloads\Chrome\test2"
$items = (Get-ChildItem -Path $path -File *.mp4 |
Where-Object { $_ -Match '^Website\.com_+' } |
ForEach-Object{
$_ |
Rename-Item -NewName {$_.Name -replace 'Website\.com_','' -replace '\+',' '} -PassThru
})
$items | % {
Rename-Item -Path $_.FullName -NewName (Get-Culture).TextInfo.ToTitleCase($_.Name)
}
Thanks to everyone who tried to help me!

Programmatically edit file names to remove leading text

I have a variety of files with names in the directory that look like this:
first_file_123456.jpg
5 * second_file_246531 (2).jpg
What I am looking to do is lay my hands on a PowerShell script that can take these files and rename them like this:
123456.jpg
246531 (2).jpg
I am looking to strip the last underscore and all text leading up to it to rename my files so they can match item numbers in my enterprise resource planning system. This system is much older (2004 technology) so automating from that side is out.
What i have tried to wire up so far and does not seem to work properly is as follows:
Get-ChildItem -Recurse -filter *_* | `
Foreach-Object {
$oldName = $_.Name
$pos = $oldName.LastIndexOf("_")
$newName = $oldName.Substring($pos + 1)
if (Test-Path $newName) {
# This is where I get lost - if it runs into a duplicate file name
# how can I make the name unique
}
#write-host $_.fullname
write-host $oldName renamed To: $newName | Out-File renamelog.txt
#rename-item $_.FullName -NewName $newName
}
I commented out the commands that actually do something to see what the output is.
Enumerate your files, filter for filenames containing an underscore, then rename them with everything up to and including the last underscore removed.
$re = '^.*_'
Get-ChildItem 'C:\some\folder' |
Where-Object { $_.Name -match $re } |
Rename-Item -NewName { $_.Name -replace $re }
Here's a short demo that uses the LastIndexOf and Substring methods:
$name = "first_file_123456.jpg"
$indexOfLastUnderscore = $name.LastIndexOf("_")
$newName = $name.Substring($indexOfLastUnderscore + 1, $name.Length - $indexOfLastUnderscore - 1)
# $newName now contains "123456.jpg"
Here's another way that uses PowerShell's -split operator and array indexing:
$name = "first_file_123456.jpg"
$newName = ($name -split '_')[-1]
$newName
# $newName now contains "123456.jpg"
Batch rename:
Get-Childitem -path $startDir -recurse |
where { ! $_.PSIsContainer } |
foreach {
$newName = Join-Path $_.Directory ($_.Name -replace '.*_', '');
Rename-Item $_.FullName $newName;
};

Powershell renaming files recursively, not renaming duplicates

I have some powershell code that is meant to take specific characters out of file names recursively. This works great, unless taking the characters out causes 2 files to match names in the same folder.
I found the Powershell here PowerShell script to remove characters from files and folders but it doesn't solve the issue I am having.
$characters = "$#"
$regex = "[$([regex]::Escape($characters))]"
$filesandfolders = Get-ChildItem -recurse "D:\projects\filenameCleaner\TEST" | Where-Object {$_.name -match $regex}
$filesandfolders | Where-Object {!$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
Rename-Item -path $_.Fullname -newname $New -passthru
}
$filesandfolders | Where-Object {$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
Rename-Item -path $_.Fullname -newname $New -passthru
}
I'm not very versed in Powershell yet and would love some help with this. I just want the script that, if it finds a duplicate, it should just add a (1) or (2) etc at the end, depending on how many there are.
Please don't just give me an answer, explain it so that I can learn what is happening
I think the way to tackle this is to create a new PSOBJECT which contains your source and target paths. You can then use the Group-object to group on the target path which will give you a count which you can then use to determine which files will need a number suffix.
Something like this:
Get-ChildItem -recurse "D:\projects\filenameCleaner\TEST" | ? {!$_.PsIscontainer} | % {
New-Object psobject -Property #{
source = $_.FullName
target = ($_.FullName -replace [regex]::Escape($_.Name)) + ($_.Name -replace '[\$#]+', '')
}
} | Group-Object target | % {
$g = $_.Group
0..($g.Count - 1) | % {
New-Object psobject -Property #{
source = $g[$_].source
target = $g[$_].target -replace '\.', #('.', "($($_)).")[$_ -gt 0]
}
}
} | % {Rename-Item -Path $_.source -NewName $_.Target}
The nice thing about doing it this way is that it can two, three or more duplcates
I have only done the code for files so you would need another version for folders.
I was able to do this by adding an if-statement that checks the new path
$characters = "$#}"
$regex = "[$([regex]::Escape($characters))]"
$path = "D:\projects\filenameCleaner\TEST"
$filesandfolders = Get-ChildItem -recurse $path | Where-Object {$_.name -match $regex}
$filesandfolders | Where-Object {!$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
$newPath = $path+"\"+$New
$loop = 0
while (Test-Path $newPath) {
$loop = $loop + 1
$basename = $_.basename -Replace $regex
$New = $basename + " ("+$loop+")"+$_.extension
$newPath = $path+"\"+$New
}
"Rename `""+$_.name+"`" to `""+$New+"`""
Rename-Item -path $_.Fullname -newname $New -passthru
}
$filesandfolders | Where-Object {$_.PsIscontainer} | foreach {
$New=$_.name -Replace $regex
$newPath = $path+"\"+$New
$loop = 0
while (Test-Path $newPath) {
$loop = $loop + 1
$basename = $_.basename -Replace $regex
$New = $basename + " ("+$loop+")"+$_.extension
$newPath = $path+"\"+$New
}
"Rename `""+$_.name+"`" to `""+$New+"`""
Rename-Item -path $_.Fullname -newname $New -passthru
}
-- Another update that handles the extensions separately when adding the number to the string for duplicates. I was having issues that the number would go onto the file name after the extension which is obviously a no-go

Renaming a file that has a bracket in the file name using power shell

I am trying to rename a file that has a bracket in the file name. This does not seem to work because powershell sees [] as special characters and does not know what to do.
I have a folder on my computer c:\test. I want to be able to look through that folder and rename all files or portions of the file. The following code seems to work but if the file has any special characters in it the code fails:
Function RenameFiles($FilesToRename,$OldName,$NewName){
$FileListArray = #()
Foreach($file in Get-ChildItem $FilesToRename -Force -Recurse | Where-Object {$_.attributes -notlike "Directory"})
{
$FileListArray += ,#($file)
}
Foreach($File in $FileListArray)
{
IF ($File -match $OldName )
{
$File | rename-item -newName {$_ -replace "$OldName", "$NewName" }
}
}
}
renamefiles -FilesToRename "c:\test" -OldName "testt2bt" -NewName "test"
I did find a similar question: Replace square bracket using Powershell, but I can't understand how to use the answer cause it's just a link explaining the bug:
For multiple files this can be done with one line.
To remove the bracket you should try:
get-childitem | ForEach-Object { Move-Item -LiteralPath $_.name $_.name.Replace("[","")}
Move-Item -literalpath "D:\[Copy].log" -destination "D:\WithoutBracket.txt"
Use the literalpath switch with the Move-Item cmdlet [instead of using the rename-item cmdlet]
As far as bracket are concerned, you've got Microsoft official answer in an old Technet Windows PowerShell Tip of the Week.
You can use :
Get-ChildItem 'c:\test\``[*``].*'
Thanks for help guys you all helped a lot this is the solution I came up with in the end after reading your reply’s .
I have a folder on my pc called c:\test and it has a file in it called "[abc] testfile [xas].txt" and i want it to be called testfile2.txt
Function RenameFiles($FilesToRename,$OldName,$NewName){
$FileListArray = #()
Foreach($file in Get-ChildItem $FilesToRename -Force -Recurse | Where-Object {$_.attributes -notlike "Directory"})
{
$FileListArray += ,#($file.name,$file.fullname)
}
Foreach($File in $FileListArray)
{
IF ($File -match $OldName )
{
$FileName = $File[0]
$FilePath = $File[1]
$SName = $File[0] -replace "[^\w\.#-]", " "
$SName = $SName -creplace '(?m)(?:[ \t]*(\.)|^[ \t]+)[ \t]*', '$1'
$NewDestination = $FilePath.Substring(0,$FilePath.Length -$FileName.Length)
$NewNameDestination = "$NewDestination$SName"
$NewNameDestination | Write-Host
Move-Item -LiteralPath $file[1] -Destination $NewNameDestination
$NewNameDestination | rename-item -newName {$_ -replace "$OldName", "$NewName" }
}
}
}
renamefiles -FilesToRename "c:\test" -OldName "testfile" -NewName "testfile2"