Powershell - Recursivly change path containing a value - powershell

I recently started using powershell, cause i find it very usefull and powerfull :)
So this is the scenario :
Customer have a folder structure that used to have commas in it.
Because of their latest program addition, this fails, due to the commas.
Essentially, they just want to replace the commas with for example " - "
This is what i have.. And it works, but i feel it's inefficient.
The script does what it's supposed to, but as soon as one path is changed, the remaining will fail because the original path have been changed, you follow me? :)
$folderpath = "C:\pathcontainingcomma"
foreach ($i in get-childitem $folderpath -Recurse) {
$name = $i.name.replace(","," - ")
Rename-Item -Path $i.fullname -NewName $name -Force -Verbose
}
i hope i explained well enough, please ask questions if you have any :)

You would need to rename from the inside out to avoid changing paths you still need to process, so I guess the following should work:
$folderpath = 'C:\pathcontainingcomma'
$items = Get-ChildItem -Recurse $folderpath
[Array]::Reverse($items)
$items | ForEach-Object { Rename-Item -Path $_ -NewName ($_ -replace ',', '-') -Force -Verbose }

Try this:
Get-ChildItem $folderPath -r '*,*' -name | foreach {
$p = "$folderPath\$_"; rename-item $p ($p -replace ',',' - ') -whatif }
The -Name paramete is handy here because the output order with -Name would allow you to rename the higher level dirs first and the replace fixes up all the elements of the path as you foreach through the output.

Related

replacing files names with split output

I am trying to use PowerShell to read filenames from a dir;
then within a for loop:
split names using a delimiter; store desired output in a new variable. Now I want to replace the original filenames in the directory with this new variable. So far I have gathered the following with the expected outputs shown:
$files = Get-ChildItem -Path C:\Test
write-output $files
Directory: C:\Test
1_N04532L_LEFT.JPG
2_N04532R_RIGHT.JPG
code continues
foreach ($file in $files)
{
$nameArray = $file -split "_"
$newName = $nameArray[1]
write-output $newName
}
N04532L
N04532R
Any Ideas on how to accomplish this. I am not a programmer and there is lots of data on this, but it's not working for me.
As both commenters already explained, there is the Rename-Item cmdlet for renaming files.
Since this cmdlet can take a scriptblock in its NewName parameter, you can use that to create a new filename.
# adding switch -File makes sure you do not also try to rename subfolders
$files = Get-ChildItem -Path 'C:\Test' -File
foreach ($file in $files) {
$file | Rename-Item -NewName { '{0}{1}' -f ($file.BaseName -split '_')[1], $file.Extension }
}
You can shorten this by piping the results from Get-ChildItem trhough one-by-one to the Rename-Item cmdlet.
Because we're piping the FileInfo objects here, we can make use of the $_ automatic variable
# enclose the Get-ChildItem cmd in brackets so this will enumerate the files to completion
# before passing them on to te Rename-Item cmdlet.
# if you don't, files you already have renamed could be picked up and processed again..
(Get-ChildItem -Path 'C:\Test' -File) |
Rename-Item -NewName { '{0}{1}' -f ($_.BaseName -split '_')[1], $_.Extension }
Note: when renaming files, you can always run into naming collisions, upon which you will receive an exception

Renaming multiple files with different names

I am a programmer by no means and am brand new to using powershell, but have been tasked with setting up some batch export processes for daily files we FTP. I need to come up with a script that will take changing file names and change them within the same directory to new names;
Example: files will come in as below (YYYYMMDD will be the changing variable)
YYYYMMDD_Share_Support.txt
YYYYMMDD_Person_Support.txt
We need them to be stripped from the above to:
Share.txt
Person.txt
so on and so forth.
I have found ways to make this work, but only on an as needed basis for one file at a time with specific names, not names that will change daily.
So far I am using:
Get-ChildItem -Filter *.txt
Dir | %{Rename-Item $_ -NewName ("NEWFILENAME.txt" -f $nr++)}
You could use the regex -replace operator inside a pipeline-bound scriptblock:
$files = Get-ChildItem -filter *.txt
$files |Rename-Item -NewName { $_.Name -replace '^\d{8}_(.*)_Support\.txt$', '$1.txt' }
As suggested by TheIncorrigible1, if you know the relative position of the word you need, you can also use -split:
$files |Rename-Item -NewName {'{0}.txt' -f ($_.Name -split '_')[-2]} # grab 2nd last word
How about:
dir *.txt |
rename-item -newname { $null,$base,$null = $_.basename -split '_'; "$base.txt" } -whatif
Probably a longer version of the answer. An alternative mentioned by #TheIncorrigible1
$logDir = "D:\Satish\TestFolders"
cd $logDir
$files = ls
foreach ($file in $files){
$fileSplit=($file.ToString()).split("_")
ren $file "$($fileSplit[1]).txt"
}
And for Share.txt to YYYYMMDD_Share_Support.txt
$logDir = "D:\Satish\TestFolders"
cd $logDir
$files = ls
$date = Get-Date -Format "yyyyMMdd"
foreach ($file in $files){
$fileSplit=($file.ToString()).split(".")
ren $file "$($date)_$($fileSplit[0])_Support.txt"
}

Splatting with Move-Item gives an error

Ok, so the script itself is over 500 lines long, so I'll refrain from posting the entire thing. However, I have narrowed down the issue to a single line.
If I use the below line of code, everything works as expected.
Move-Item -Path $path -Include *.txt,*.doc,*.pdf -Destination $dest -Force
But when I change it to use splatting, it gives me an error
$downloadDir = "G:\Downloads"
$dest = "G:\Test\"
$editList = Get-ChildItem -LiteralPath "$downloadDir" -include "[" -File | ForEach-Object -Process {Rename-item -LiteralPath $_.FullName -NewName ($_.Name -replace "[][]"," ") -ErrorAction SilentlyContinue}
$mainList = Get-ChildItem -Path "$downloadDir" -File | Select-Object Name
ForEach ($list in $mainList) {
$item = $list.Name
$path = "$downloadDir\*"
$opts = #{
Path = $path;
Include = '*.txt,*.doc,*.pdf';
Force = $true;
Destination = $dest
}
Move-Item #opts
}
Move-Item : Cannot move item because the item at 'G:\Downloads\test.txt' does not exist.
I feel like I am probably missing something very basic, but I don't know enough about hash tables/splatting yet, to spot the mistake.
Any ideas?
EDIT:
Just to clarify, G:\Downloads\test.txt comes from $path which is generated from a Get-ChildItem.
I am literally doing a straight swap of the 2 versions of code(Splatting/Non-splatting).
EDIT 2:
Added all the parts of the script relevant to that Move-Item
EDIT 3:
Got this working by using double quotes for the "Include" line:
Include = "*.txt","*.doc","*.pdf";
Change your Include from:
Include = '*.txt,*.doc,*.pdf';
to
Include = "*.txt","*.doc","*.pdf";
The Path statement can be tricky as well.
For example
get-childitem c:\temp -include *.txt
will not work, while
get-childitem c:\temp\* -include *.txt
will work, if you have any .txt files in c:\temp
It's stupid, but that's how it is with some of these cmdlets.

Renaming Recursively with if-condition

I'm having big troubles combining the rename with an if-condition. PS cannot rename when the file has the same name as before and won't do anything afterwards.
Plus it's unable to rename recursively.
I wanna do sth like:
$entrys = Get-ChildItem -Recurse $myPath
foreach ($name in $entrys) {
$newName=$name.FullName -replace('[\,\/\*\+\#\~\-\=\^\°\$\%\&\<\>\|]','')
if (-not ($newName -like $name)) {
Rename-Item $name -NewName $newName
}
}
I found something similar here but they dont have any conditions there.
So how do I pipe into an if-condition before renaming, so I can pipe directly from get-childitem -recurse to if() then rename()? Or is there another possibility?
Thanks for help
When I try your code I have the same issue that it reports it's unable to rename the file. However, I modified a bit of your code, and now it seems to work:
$entrys = Get-ChildItem -Recurse $myPath -File
foreach ($name in $entrys) {
$newName = $name.Name -replace('[\,\/\*\+\#\~\-\=\^\°\$\%\&\<\>\|]','')
if ($newName -ne $name.Name) {
Rename-Item -LiteralPath $name.FullName -NewName $newName
}
}
First you have to only check for files and not folders. Because once you renamed a folder the files are no longer found when you recurse into a non existing folder name (one that has changed).
If you need to rename folders also. It needs some more work as the folder names might change.
Hope this helps you out.
My PowerShell doesn't throw any error on the Rename-Item cmdlet if the file has the same name. But you could try to use -ErrorAction 0.
However, this oneliner works for me:
gci $myPath -r | % { Rename-Item $_.FullName ($_.FullName -replace('[\,\/\*\+\#\~\-\=\^\°\$\%\&\<\>\|]','')) }

Using Powershell how can I bulk rename files recursively and include a counter in the new name?

I have a project where I need to search for multiple pdfs within multiple subfolders which contain a specific string and then rename them using a counter variable. I'm a pretty novice powershell user but I think I've got it pretty close. The only thing that is not working is the counter. The counter variable never changes. This is what I have so far for code:
$prefix = "sample"
$id = 1
Get-ChildItem -Filter "*combined*" -Recurse | Rename-Item -NewName ($prefix + ($id.tostring("000")) + '_regular_' + ($id.tostring("000")) + '.pdf' -f $id++ )
What am I missing? Should I be using a 'foreach' loop?
Yes you need to use a ForEach loop. This will go through and do the renames, ensuring that any files found in subdirectories are preserved in those directories after renaming
Get-ChildItem -Filter "*combined*" -Recurse | %{
$fullId = $id.toString("000")
$curPath = Split-Path $_.FullName
Rename-Item $_.fullname -NewName "$curPath\$($prefix)$($fullId)_regular_$($fullId).pdf" )
$id += 1
}
Here is my edited version of the above code:
$id = 1
Get-ChildItem -Filter "*combined*" -Recurse | %{
$fullId = $id.toString("000")
$curPath = Split-Path $_.FullName
Rename-Item $_.fullname -NewName "$curPath\$($prefix)_$($fullId)_regular_$($fullId).pdf"
$id++
}