Moving every n files into a separate folder - powershell

I have several files with a repetitive naming convention, e.g.
1*Intro*
2*
3*
…
10*intro*
….
I want to move each module into a separate folder. So, I should separate from every *intro* till the next one.
Also, I should note that files are numbered and sorted.
I guess, the easiest way to do this is to:
1. Get a list of intros.
2. Separate their numbers.
3. Start moving files starting from one number till their smaller than the next one.
$i = 1
Ls *intro* | ft {$_.name -replace '\D.*', ''}
// The reason for .* is that the files are `mp4`.
Ls * | ? {$_.name -match '[^firstNumber-SecondNumber-1]'} | move-item -literalpath {$_.fullname} -destination $path + $i++ + '/' +{$_.name}
So the last command should be something like:
Ls *intro* | % { ls * | ? {…} | move-item … }
Or maybe the move-item itself can do the filtering job.
The regular expression doesn't work and I don't have enough Powershell knowledge to write anything better. Can you think of any script to do that? Also how should I permit move-item to create the folder?
I'll be thankful if someone could edit this post with a better title.

This could be done with a simple Switch. The switch will be run against all items in the current folder (items gotten with the Get-ChildItem cmdlet which you use by it's alias 'LS'). It looks to see if the file has the string "Intro" in the file name. If it does, it creates a new folder with that file's name, and stores that folder's info in the $TargetFolder variable (variable created previously to avoid scoping issues). It then moves the file to that folder, and continues to the next file. If the file does not have "Intro" in its file name it simply moves the file to whatever the last assigned $TargetFolder is that was created.
$TargetFolder = ""
Switch(Get-ChildItem .\*){
{$_.BaseName -match "intro"} {$TargetFolder = New-Item ".\$($_.BaseName)" -ItemType Directory; Move-Item $_ -Destination $TargetFolder; Continue}
default {Move-Item $TargetFolder}
}

Related

Sorting jpg/pdf files into folders that already exist by name but only using the the first 6 digits

I am having issues trying to sort a large amount of files into folders.Screen shot of files that i need sorted,new files are added daily
My main issue is coming from the naming format of the files relative to the folders. Is there a way to move them by the first 6 digits into the corresponding folders that include those digits and if the folder doesn't exist have one created? I couldn't get name-split to work since the beginning of the file name isn't broken up by a break. Does anybody have any code that could do this for me? I'm still learning powershell, not great at writing from scratch yet :)
Use the String.Substring() or String.Remove() to extract the first 6 digits:
$sourceItemFolder = 'C:\unsorted'
$targetRootFolder = 'C:\folder\with\directories'
Get-ChildItem $sourceItemFolder -File |ForEach-Object {
if($_.Name.Length -ge 6){
# Extract prefix from file name
$prefix = $_.Name.Remove(6)
# Use prefix to find appropriate folder, pick the first match
$targetFolder = Get-ChildItem $targetRootFolder -Filter "${prefix}*" -Directory |Select -First 1
if(-not $targetFolder){
# No matching folder found, create one
$targetFolder = New-Item -Path $targetRootFolder -Name $prefix -Type Directory
}
# Move the file
$_ |Move-Item -Destination $targetFolder.FullName
}
}

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?

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])
}

Move a files that have the same name but different extension. Powershell

I am a junior tech and have been tasked to write a short powershell script. The problem is that I have started to learn the PS 5 hours ago - once my boss told that I'm assigned to this task. I'm a bit worried it won't be completed for tomorrow so hope you guys can help me a bit. The task is:
I need to move the files to different folders depending on certain conditions, let me start from the he folder structure:
c:\LostFiles: This folder includes a long list of .mov, .jpg and .png files
c:\Media: This folder includes many subfolders withe media files and projects.
The job is to move files from c:\LostFiles to appropiate folders in c:\Media folder tree if
The name of the file from c:\LostFiles corresponds to a file name in one of the subfolders of the C:\media We must ignore the extension, for example:
C:\LostFiles has these files which we need to move (if possible) : imageFlower.png, videoMarch.mov, danceRock.bmp
C:\Media\Flowers\ has already this files: imageFlower.bmp, imageFlower.mov
imageFlower.png should be moved to this folder (C:\media\Flowers) because there is or there are files with exactly the same base name (extension must be ignored)
Only the files that have corresponding files (the same name) should be moved.
So far I have written this piece of code (I know it is not much but will be updating this code as I am working on it now (2145 GMT time). I know I missing some loops, hey yeah, I am missing a lot!
#This gets all the files from the folder
$orphans = gci -path C:\lostfiles\ -File | Select Basename
#This gets the list of files from all the folders
$Files = gci C:\media\ -Recurse -File | select Fullname
#So we can all the files and we check them 1 by 1
$orphans | ForEach-Object {
#variable that stores the name of the current file
$file = ($_.BaseName)
#path to copy the file, and then search for files with the same name but only take into the accont the base name
$path = $Files | where-object{$_ -eq $file}
#move the current file to the destination
move-item -path $_.fullname -destination $path -whatif
}
You could build a hashtable from the media files, then iterate through the lost files, looking to see if the lost file's name was in the hash. Something like:
# Create a hashtable with key = file basename and value = containing directory
$mediaFiles = #{}
Get-ChildItem -Recurse .\Media | ?{!$_.PsIsContainer} | Select-Object BaseName, DirectoryName |
ForEach-Object { $mediaFiles[$_.BaseName] = $_.DirectoryName }
# Look through lost files and if the lost file exists in the hash, then move it
Get-ChildItem -Recurse .\LostFiles | ?{!$_.PsIsContainer} |
ForEach-Object { if ($mediaFiles.ContainsKey($_.BaseName)) { Move-Item -whatif $_.FullName $mediaFiles[$_.BaseName] } }