Reset Filenumber for new folder in Recurse Filerename Powershell - 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])
}

Related

Powershell: Find Folders and Run Command in Those Folders

so trying to find a way to combine a couple of things the Stack Overflow crowd has helped me do in the past. So I know how to find folders with a specific name and move them where I want them to go:
$source_regex = [regex]::escape($sourceDir)
(gci $sourceDir -recurse | where {-not ($_.psiscontainer)} | select -expand fullname) -match "\\$search\\" |
foreach {
$file_dest = ($_ | split-path -parent) -replace $source_regex,$targetDir
if (-not (test-path $file_dest)){mkdir $file_dest}
move-item $_ -Destination $file_dest -force -verbose
}
And I also know how to find and delete files of a specific file extension within a preset directory:
Get-ChildItem $source -Include $searchfile -Recurse -Force | foreach{ "Removing file $($_.FullName)"; Remove-Item -force -recurse $_}
What I'm trying to do now is combine the two. Basically, I'm looking for a way to tell Powershell:
"Look for all folders named 'Draft Materials.' When you find a folder with that name, get its full path ($source), then run a command to delete files of a given file extension ($searchfile) from that folder."
What I'm trying to do is create a script I can use to clean up an archive drive when and if space starts to get tight. The idea is that as I develop things, a lot of times I go through a ton of incremental non-final drafts (hence folder name "Draft Materials"), and I want to get rid of the exported products (the PDFs, the BMPs, the AVIs, the MOVs, atc.) and just leave the master files that created them (the INDDs, the PRPROJs, the AEPs, etc.) so I can reconstruct them down the line if I ever need to. I can tell the script what drive and folder to search (and I'd assign that to a variable since the backup location may change and I'd like to just change it once), but I need help with the rest.
I'm stuck because I'm not quite sure how to combine the two pieces of code that I have to get Powershell to do this.
If what you want is to
"Look for all folders named 'Draft Materials.' When you find a folder with that name, get its full path ($source), then run a command to delete files of a given file extension ($searchfile) from that folder."
then you could do something like:
$rootPath = 'X:\Path\To\Start\Searching\From' # the starting point for the search
$searchFolder = 'Draft Materials' # the folder name to search for
$deleteThese = '*.PDF', '*.BMP', '*.AVI', '*.MOV' # an array of file patterns to delete
# get a list of all folders called 'Draft Materials'
Get-ChildItem -Path $rootPath -Directory -Filter $searchFolder -Recurse | ForEach-Object {
# inside each of these folders, get the files you want to delete and remove them
Get-ChildItem -Path $_.FullName -File -Recurse -Include $deleteThese |
Remove-Item -WhatIf
}
Or use Get-ChildItem only once, having it search for files. Then test if their fullnames contain the folder called 'Draft Materials'
$rootPath = 'X:\Path\To\Start\Searching\From'
$searchFolder = 'Draft Materials'
$deleteThese = '*.PDF', '*.BMP', '*.AVI', '*.MOV'
# get a list of all files with extensions from the $deleteThese array
Get-ChildItem -Path $rootPath -File -Recurse -Include $deleteThese |
# if in their full path names the folder 'Draft Materials' is present, delete them
Where-Object { $_.FullName -match "\\$searchFolder\\" } |
Remove-Item -WhatIf
In both cases I have added safety switch -WhatIf so when you run this, nothing gets deleted and in the console is written what would happen.
If that info shows the correct files are being removed, take off (or comment out) -Whatif and run the code again.

How to prevent PowerShell -Recurse from renaming first file twice?

When using powershell to rename files with their directory name and file name, my code works, except in the first file in a directory, it gives it two copies of the directory name. So the file book1.xlsx in folder folder1 should become folder1book1.xlsx but it becomes folder1folder1book1.xlsx. The remaining files in folder1 are correctly named folder1book2.xlsx, folder1book3.xlsx, etc.
I have a directory, with many sub-directories. In each sub-dir are files that need their sub-dir name added in.
I've been following this code. For me it looks like:
dir -Filter *.xlsx -Recurse | Rename-Item -NewName {$_.Directory.Name + "_" + $_.Name}
I've also tried
--setting the Recurse -Depth 1 so that it doesn't keep looking for folders in the sub-folders.
--using ForEach-Object {$_ | ... after the pipe, similar to this.
--running it in Visual Studio Code rather than directly in PowerShell, which turns it into:
Get-ChildItem "C:\my\dir\here" -Filter *.xls -Recurse | Rename-Item -NewName {$_.DirectoryName + '_' + $_.Name}
--putting an empty folder inside the sub-directory, setting -Depth 2 to see if that will "catch" the recurse loop
I would expect the files to be named folder1_book1.xlsx, folder1_book2.xlsx, folder1_book3.xlsx.
But all of the attempted changes above give the same result. The first file is named folder1_folder1_book1.xlsx [INCORRECT], folder1_book2.xlsx[CORRECT], folder1_book3.xlsx[CORRECT].
A workaround might be writing an if statement for "not files that contain the sub-directory name" as suggested here. But the link searches for a text string not an object (probably not the correct term) like #_.Directory.Name. This post shows how to concatenate objects but not something like #_.Directory.Name. Having to put in an if statement seems like an unnecessary step if -Recurse worked the way it should, so I'm not sure this workaround gets at the heart of the issue.
I'm running windows 10 with bootcamp on a 2018 iMac (I'm in Windows a lot because I use ArcMap). Powershell 5.1.17134.858. Visual Studio Code 1.38.0. This is a task I would like to learn how to use more in the future, so explanations will help. I'm new to using PowerShell. Thanks in advance!
This was a script I created for one of my customers that may help
<##################################################################################################################################
This script can be used to search through folders to rename files from their
original name to "filename_foldername.extension". To use this script
please configure the items listed below.
Items to Congfigure
-$Original
-$Source
-$Destination
-$Files
Also please change the Out-File date on line 29 to today's date ****Example: 2019-10-02****
We've also added a change log file that is named "FileChange.txt" and can be found in the location identified on line 30
>
$Original="C:\temp\test" #Location of ".cab" files copied
$Source="C:\temp\Test" #Location were ".cab" files are stored
$Destination="C:\temp\Test\2019-10-02" #Location were you want to copy ".cab" files after the file name change. Be sure to change the date to the date you run this script. The script creates a folder with todays date
$Files=#("*.cab") #Choose the file type you want to search for
$ErrorActionPreference = "SilentlyContinue" #Suppress Errors
Get-ChildItem $Original -Include "*.cab" -File -Recurse | Rename-Item -NewName {$_.BaseName+"_"+$_.Directory.Name +'.cab'}
New-Item -ItemType Directory -Path ".\$((Get-Date).ToString('yyyy-MM-dd'))"; Get-ChildItem -recurse ($Source) -include ($Files) | Copy-Item -Destination ($Destination) -EA SilentlyContinue
Get-ChildItem $Original | Where {$_.LastWriteTime -ge [datetime]::Now.AddMinutes(-10)} | Out-File C:\temp\test\2019-10-02\FileChange.txt

How do I move a selection of files into several different directories in one loop?

First time toying seriously with Powershell. I'm running into the problem that my little loop doesn't do what I want it to; it creates a list of series names from the files found in a directory and creates the directories needed to hold the files.
[TAG]Series first.txt
[TAG]Series something else.txt
File.jpg
etc.
This should be sorted into
Series first [Sometag]\[TAG]Series first.txt
Series something else [Sometag]\[TAG]Series something else.txt
File.jpg
etc.
But I can't get Move-Item to actually move the files into the new directories. It leads to extensionless files or errors stating that the file (directory) already exists.
$details = ' [Sometag]'
$series = Get-ChildItem . -Name -File -Filter *.txt |
% {$_.Replace("[TAG]", "").Split("-")[0].Trim()} |
Get-Unique
$series | ForEach-Object {
New-Item -ErrorAction Ignore -Name $_$details -ItemType Directory
}
This is the command that should move the files that it finds using the $serie collection into the directories previously created.
foreach ($serie in $series) {
Get-ChildItem -File -Filter *$serie*.txt |
Move-Item -Destination '.\$serie$details'
}
Which results in it complaining that the file already exists. What would be the best way to deal with this, and can I optimize the first two lines?

I would like to exclude the files in subfolders and delete files in the other folders

I have mulitple sub-folders in the main folder which has number of files in each of them. I want to keep the contents of certain folders intact and delete the contents in the rest of them.
I tested the code, but it deletes the files in all the sub-folders 7 days before.
$Path="C:\Shreyas1"
$NumberOfDays="-7"
$CurrentDate=Get-Date
$DeleteDays=$CurrentDate.AddDays($NumberOfDays)
## Heading
##$excludes="Specs"
Get-ChildItem $Path -Exclude $excludes -Recurse |
Where-Object{($_.LastWriteTime -lt $DeleteDays )} |
Remove-Item
You should try using the same "Where" statement after your Get-ChildItem cmdlet to filter out specific file names. Try something like this:
Get-ChildItem $Path -Recurse | Where-Object {$_.Name -notlike "*$excludes*" -and $_.LastWriteTime -lt $DeleteDays}
Run that first to make sure you get what you want, then you can pipe to Remove-item -Confirm:$false like you have done in your OP. Edit: The -Confirm:$false switch means that it won't prompt you to confirm whether or not you want to delete the file, it will just delete. That is why you want to run Get-ChildItem first.

Rename bulk files with given name, in directory and subfolders using PowerShell

I’m looking for a solution to rename all files with given name in the directory and subfolders.
E.g.
There is a directory called c:\blah and in this folder, there is one file called BaR.txt and one folder called foo. In the foo folder, there is another file called bAr.txt.
I want to find all files with name bar.txt and change the name of each file to “neo.txt”. It must also be possible to rename the files to lower case as well e.g. bar.txt.
So far, I’ve tried to do this manually using the Windows Explorer in Windows10 but for some weird reason when I try to rename the bulk files there is extra “(1)” sign added to the end of each file name.
I’ve tried to play with PowerShell and I created a command
$_.name -replace 'bar.txt','neo.txt'
But it didn’t work for me.
To do this, you need 2 cmdlets: Get-ChildItem and Rename-Item.
This should work:
Get-ChildItem -Path 'C:\Blah' -Filter 'bar.txt' -Recurse | ForEach-Object {
Rename-Item -Path $_.FullName -NewName 'neo.txt'
}
However, if inside the foo folder there are more subfolders, this code will rename all files called bar.txt (case-insensitive) it finds in all of these subfolders.
If you do not want to go any deeper than the first subfolder in C:\Blah (the one called foo), you can use the -Depth parameter on the command like this:
Get-ChildItem -Path 'C:\Blah' -Filter 'bar.txt' -Recurse -Depth 1 | ForEach-Object {
Rename-Item -Path $_.FullName -NewName 'neo.txt'
}