For loop while rename and move files withing a folder - powershell

Good morning,
started last week using powershell for some small scripts and now I'm stucked at creating a for loop for rename and move files.
I've got these 2 commands
get-childitem "$Quellordner" | Rename-Item -NewName {$_.Name.Replace("[Index]","-")}
get-childitem "$Quellordner" | Move-Item -Force -Destination $Zielordner -Verbose *>&1 | Set-Content $Logfileordner$Logfilename
and they are working fine but it's a bit odd not using a for loop for this. Unfortunately I can't get it to work :/
Any help will be appreciated!
(PS: Is there an other way to create a descending log file (newest to oldest) than copy the actual content and paste it belowe the new line?)

You can combine the rename and move by simply extending the pipeline:
Get-ChildItem -Path *.txt |
Rename-Item -NewName {$_.Name -replace "[Index]","-"} -PassThru |
Move-Item -Destination $Zielordner -Force
Writing to the start of a file is not directly supported, likely because it is an expensive operation (you need to move everything along somehow to make room), and seems like it will be more prone to corruption/data loss. One thing to look at is writing to the log as normal, but displaying it in reverse order. For example, Get-Content can read the individual lines of a text file into an array, which could easily be output from the end to the start.

You're actually already using a foreach loop. ForEach-Object to be precise.
Your line of code:
get-childitem "$Quellordner" | Rename-Item -NewName {$_.Name.Replace("[Index]","-")}
does exactly the same as the following code does:
$files = get-childitem "$Quellordner"
foreach($_ in $files){
Rename-Item -NewName {$_.Name.Replace("[Index]","-")}
}
About your PS: there is no way, I know of, to add a new line at the top of a text file without reading the file, adding the line you want to add at the top and write it back.

Related

Powershell - Search for Pattern and Copy

i have a bunch of *.CSV Files. Huge *.CSV Files. I try to search for a specific pattern in these Files called "Secure". If found, the script shall copy it to a folder.
It works, but it has one Problem i could'nt solve.
In some files, the Word i'm looking for is present more than once. Now my script searches for the word, finds it and copies it. Then it searches in the same file again, finds the pattern again and copies again.
But it should copy after the first find of the word and then search in the next *.CSV file and not in the same again.
i tried a bunch of things "-SimpleMatch" or "-First 1"
the Code so far is :
Select-String -Path 'C:\Tools\Test\*\*.csv' -Pattern "Secure" | Select -first 1 | Copy-Item -Destination C:\Tools\Found -Verbose
can someone help me ?
Thank you!
Use Get-ChildItem to discover the initial set of files, then use Select-String on one file at a time. This way Select -First 1 will return after the first match in each file, rather than breaking the whole pipeline after outputting the first file:
Get-ChildItem -Path 'C:\Tools\Test\*\*.csv' |Where-Object { $_ |Select-String -Pattern "Secure" |Select -First 1 } |Copy-Item -Destination C:\Tools\Found -Verbose

Using the rename-item command to overwrite an existing file?

I'm trying to tidy up imported files from my iPhone using a PowerShell script, specifically wanting edited photos (IMG_E001.jpg) to overwrite the non-edited photos (IMG_001.jpg).
I'm using the rename-item but can't figure out how to get it to overwrite the file. My current workaround is to move all of the edited files into their own folder, run the script, and then copy them over the top of the original files but this is a bit of a pain, plus it doesn't seem as reliable as a fully automated script.
Here's the code I'm using currently:
get-childitem -recurse -Include *.JPG | foreach { rename-item $_ $_.Name.Replace("E", "") };
Please can anyone help me to get this script to overwrite the existing files? Thank you
This is a limitation of rename-item as #postanote mentioned in his comment this is because windows does not allow you to rename a file to an existing name. You will need to remove the other file first or overwrite it. Instead you can use move-item -force for essentially the same effect as it will perform the overwrite.
get-childitem -recurse -Include *.txt | foreach { Move-Item $_ $_.Name.Replace("E", "") -Force };
For more information; here is a related thread rename-item and override if filename exists

Copy same file to multiple different folders PowerShell

I want to copy one file logo.png to different multiple folders. As of now I am doing like this
Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" |
Copy-Item -Destination "D:\LoginPage"
Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" |
Copy-Item -Destination "D:\HomePage"
Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" |
Copy-Item -Destination "D:\AboutUs"
Is there any way to make it single command?
I have seen this but looks different.
I am not aware of one single command to achieve what you are trying to do.
As pointed out in the link you posted, you can achieve your goal with one line of code, but this involves piping.
"D:\LoginPage", "D:\HomePage", "D:\AboutUs" | ForEach-Object { Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" | Copy-Item -Destination $_}
In the first part you just list your destinations as strings and separated by comma.
The second part will execute the code within the braces { } for each destination.
Note: $_ stands for the data currently in the pipeline, so on each iteration $_ will be replaced with your destination.
I guess if this is something you need to do regularly with different destinations, sources and filenames you could always write a script file that accepts input for it's parameters, but that's a topic for another question.
Hope this is useful.

Reset Filenumber for new folder in Recurse Filerename Powershell

I am working on a powershell batch file.
I want to rename all the files in a certain amount of folders. I need to rename it to a certain part of the folder name followed by an incremental number. So far i managed to create a rename command in powershell that also add numbers to the files.
Get-ChildItem -recurse -filter "*.jpg" | %{$x=1} {Rename-Item $_.FullName -NewName ('{0}-{1}.jpg' -f ($_.FullName.substring(18,8) -replace("-","")) ,$x++)}
This works well how ever i want to reset the number back to 1 for each separate folder. At the moment i keep numbering up trough different folders. How do i reset $x back to 1 when i change folder?
As you can't be sure that each directory is enumerated at ones, I would create a hashtable to keep track of the index. Something like:
$Directories = #{}
Get-ChildItem -recurse -filter "*.jpg" | ForEach {
Rename-Item $_.FullName -NewName ('{0}-{1}.jpg' -f ($_.FullName.substring(18,8) -replace("-","")) ,++$Directories[$_.DirectoryName])
}

Powershell Rename-Item issue with special characters

I've run into the issue I know has been addressed several times here previously but I'm not overly familiar with PS scripts or regular expressions and I'm struggling to implement a fix here.
Basically, I'd be very happy if this line of my script would work:
Get-childItem *.* -recurse -force | % {rename-item $_.name ($_.name -replace '(\d{2}) \[(\d{1})x(\d{2})\]','$1 s0$2e$3')}
And example file name would be "24 [1x01].avi" and should instead be named "24 s01e01.avi" - I'm trying to tidy up my media collection :)
I know the reason it doesn't is the square brackets in the file names. I think i have to move the files to a temp location, changing the name while doing so and then move back. My difficulty is that I haven't been able to find an example of this using the regular expression and I haven't been able to get this to work.
Also, is there a better workaround than this available yet? The bug on Microsoft Connect is closed as fixed?
Thanks!
I think your regular expressions might make more sense (to you), especially as a beginner, if you used "named groups" (a regular expression concept). I've modified your regular expression slightly to take this into account. You should really get familiar with regular expression terminology though, to ensure that you can update your regex to work in all scenarios.
"24 [1x01].avi" -replace '(?<ShowName>.*) \[(?<Season>\d{1})x(?<Episode>\d{2})\]','${ShowName} s0${Season}e${Episode}';
Result:
24 s01e01.avi
Can you give an example of a file name that doesn't work?
EDIT: Attaching example script. Let me know if this works for you.
# 1. Define a test folder path
$RootPath = "$env:SystemDrive\test";
# 2. Create the folder
mkdir -Path $RootPath;
# 3. Create a test file
Set-Content -Path "$RootPath\24 [1x01].txt" -Value '';
# 4. Get a list of files in the directory
$FileList = Get-ChildItem -Path $RootPath;
foreach ($File in $FileList) {
# 5. Fix up the name of each file
$NewName = $File.Name -replace '(?<ShowName>.*) \[(?<Season>\d{1})x(?<Episode>\d{2})\]','${ShowName} s0${Season}e${Episode}';
# 6. Rename the file
Move-Item -Path $File.FullName -Destination ((Split-Path -Path $File.FullName -Parent) + $NewName);
}
powershell Rename-Item fail to rename
If you are running PS 3+ add -LiteralPath switch to your rename:
One of the easiest ways to handle the Special Characters (such as square/block brackets[]) in the file-names, is to simply use the -LiteralPath parameter.
Error: When attempting to rename files or folders that contain square/block brackets [], the standard error message that PowerShell returns is "file not found", which is not accurate.
Reason: Windows still uses old fashioned 8.3 format short-file-names (max 8 chars with limited allowed chars) unfortunately PowerShell's -Path parameter (even in version 5.1) uses these internal names.
Solution: Use the -LiteralPath argument, available for most cmdlets (including Get-ChildItem or Rename-Item etc.)
Examples: Depicting handling of files or folders that contain square/block brackets []:
Get-ChildItem -LiteralPath "test[1].txt";
Test-Path -LiteralPath "C:\dir\test[1].txt";
Rename-Item -LiteralPath "test[1].txt" "test[2].txt";
Note: In PowerShell version below 3.0, to rename files/directories containing special characters, use Move-Item with -LiteralPath, instead of Rename-Item cmdlet because Rename-Item didn't have -LiteralPath in PS version 2.0 (or below).
Thanks to pointers from #Trevor Sullivan I was able to get the desired results by:
Updating to the most recent version of PowerShell (download link available in the comments)
Edited the script to the following:
Get-childItem *.* -recurse -force | Move-Item -Destination {$_ -replace '(\d{2}) \[(\d{1})x(\d{2})\]','$1 s0$2e$3'}