Requirements:
Iterate through all folders and files in each directory
Delete all files in each subdirectory except for the newest one (contains filename time stamp) and has a specific filename pattern or instead copy the one file in each subdirectory that is the newest and that is preceded with LIVE_DATA. (There are other files in each subdirectory I wish to ignore).
Directory: AISI-301.0000000001006165.2015-08-24_23-57-46-1
File: LIVE_DATA_2015-08-24_23-57-51.413+0000.MCA
How can I iterate through all of the files recursively while doing comparisons between files in each subdirectory only? I don't want to compare all of them together. Just the one's inside each subdirectory.
for $filename in Get-ChildItem -recurse {
for $filename in $directory {
if ($filename > $filename2) {
$temp = $filename
}
$filename2 = $filename1
}
}
This is what I ended up using to rename my file's after the directory names. It appends the file name to the end and the directory name comes first. I hope this helps somebody else that might be searching for this solution.
Get-ChildItem -include *LIVE_DATA_*.MCA -recurse | Rename-Item -NewName { $_.Directory.Name+'_'+$_.Name}
If you want to remove all files LIVE_DATA_* except the most recent one on a per-folder basis you could do something like this:
$root = 'C:\path\to\root\folder'
Get-ChildItem $root -Recurse | ? { $_.PSIsContainer } | ForEach-Object {
Get-ChildItem (Join-Path $_.FullName 'LIVE_DATA_*') |
Sort-Object Name -Desc |
Select-Object -Skip 1 |
Remove-Item -Force
}
Get-ChildItem $root -Recurse | ? { $_.PSIsContainer } lists all subfolders of $root. Then the ForEach-Object runs another Get-ChildItem statement (without recursion) for each subfolder separately. The Join-Path statement builds a wildcard path from the filename pattern and the full path to the folder (C:\path\to\root\folder\sub\folder\LIVE_DATA_*).
Basically the code lists all folders, then processes the files for each individual folder.
Related
I need to batch copy a sort of file extensions from subfolders to specific folders for each location.
All folders have a 6 digit number
let's say folder Rood folder: BATCH
Subfolder 1: 000000
Subfolder 2: 111111
despite their extensions, most files have the name as the subfolder but some of them may have extra alphanumeric characters, therefore the script should grab only the ones that are not larger than 6 digits.
Example Subfolder1: 000000.pdf 000000.eps the script would need to grab all pdf within subfolders and export them to a PDF exclusive new folder, and the same would apply for eps files.
I know nothing about powershell but I know that something like this would work for an specific subfolder but I'm still missing the parts where it distributes them to a new PDFONLY and EPSONLY folders and the fact the I want to apply this to all the folders whiting the root folder.
Get-ChildItem -Path "C:\BATCH\*" -Include *.pdf,*.eps -Recurse | Copy-Item -Destination D:\
You can use Group-Object to group all the files by their extension and then loop over each group of objects, create a new folder with the desired name and lastly copy all objects of each group to their folders.
$target = 'D:\' # Set destination here
Get-ChildItem -Path C:\BATCH\* -Include *.py, *.ps1 -Recurse |
Group-Object Extension | ForEach-Object {
# Example of `$folderName` would be `PDF ONLY`
$folderName = '{0} ONLY' -f $_.Name.TrimStart('.').ToUpper()
$destination = Join-Path $target -ChildPath $folderName
# If the `$destination` folder doesn't exist
if(-not (Test-Path $destination)) {
# Create it
$null = New-Item $destination -ItemType Directory
}
Copy-Item -LiteralPath $_.Group.FullName -Destination $destination
}
Similar to Santiago's answer but with an extra filter and without grouping you can do this:
$destination = 'X:\somewhere'
Get-ChildItem -Path "C:\BATCH" -Include '*.pdf','*.eps' -File -Recurse |
Where-Object {$_.BaseName -match '^\d{6}$' } | # filter files with a BaseName of just 6 digits
ForEach-Object {
$targetPath = Join-Path -Path $destination -ChildPath ('{0}ONLY' -f $_.Extension.TrimStart(".").ToUpper())
# make sure the target path exists
# for directories, using the -Force switch either creates a new folder
# or returns the DirectoryInfo object of an existing folder.
$null = New-Item -Path $targetPath -ItemType Directory -Force
$_ | Copy-Item -Destination $targetPath
}
I am trying to clean up and group files in a directory by creating subdirectories and then copying the files into the new directories.
Example:
test01.a.jpg
test01.a.txt
test01.b.bak
test01.b.txt
test02.a.txt
test02.a.jpg
test02.a.bak
test03.a.txt
test03.a.bak
test03.b.txt
I wish to create subdirectories like test01, test02, test03 and ideally copy the relevant files over. All groups will have a txt file but more or less of the others.
To create the directories I have got as far as
gci -file *.txt | New-Item -ItemType directory $_.name
which doesn't work as expected.
If your files have names like that, you can simply split the filename on the dot and take only the first part as new folder name.
Then test if a subfolder like that already exists (if not create it) and move the file.
Something like this
$sourcePath = 'D:\Test' # put the real path to the files here
# if you want only the files with extension .txt, use filter '*.*.txt'
(Get-ChildItem -Path $sourcePath -File -Filter '*.*.*') | ForEach-Object {
# use the first part of the file name for subdirectory name
$destinationPath = Join-Path -Path $sourcePath -ChildPath $_.Name.Split(".")[0]
if (!(Test-Path -Path $destinationPath -PathType Container)) {
# if a subdirectory with that name does not already exist, create it
$null = New-Item -Path $destinationPath -ItemType Directory
}
# now move the file to that (new) destination folder
$_ | Move-Item -Destination $destinationPath
}
Actually, algorithm is simple (we don't need to previously compare names of files. All we need is just use a $_.BaseName property)
<#Creating folders and moving files using BaseName property #>
gci *.txt | % { new-item -ItemType Directory -Path ($_.Directory.ToString() + "\" + $_.BaseName.ToString())}
gci -file | % { Move-item $_.Fullname ($_.Directory.ToString() + "\" + $_.BaseName.ToString())}
I have a main folder where other folders reside with .mkg files . These folders have a certain format.
Folder = NameSerie.SxEy.Randomstuf
Item in folder = NameSerie.SxEy.Randomstuf.mkv
Where x is the season number and y is the episode number.
What i want to do is automaticly create a folder if the nameSerie isnt already created and put the .mkv files in this folder.
So, if we have folders named NameSerie.SxEy.Randomstuf we check if folder NameSerie exists, if not we create one. Then we enter folder NameSerie.SxEy.Randomstuf and copy the NameSerie.SxEy.Randomstuf.mkv file in the NameSerie folder.
the file name needs to change from NameSerie.SxEy.Ra.n[dom}stuf.mkv to NameSerie.SxEy.mkv but I cant seem to figure out how to remove the random stuf after the NameSerie.SxEy.< >.mkv
This is the code that i have managed to create but im still stuck. I have managed to create a folder if one does not exists but this only works if the .mkv file is not in a folder.
$Location = "\\<ip>\Share\Media\Series"
#rename files
Get-ChildItem $Location | Rename-Item -NewName {$_.Name.Replace(" [480p]","") }
#make folder for serie if it does not exist
Get-ChildItem "$Location\*.mkv" |
Foreach-Object {
$FullName = $_.Name
$pos = $FullName.IndexOf(" - ")
$Name = $FullName.Substring(0, $pos)
Write-Host $_.FullName
$TARGETDIR = "$Location\$Name"
if( -Not (Test-Path -Path $TARGETDIR ) )
{
New-Item -ItemType directory -Path $TARGETDIR
}
Move-Item -Path $_.FullName -Destination $TARGETDIR
}
You could use the parameter -Recurse when you list files from the path like this:
Get-ChildItem "$Location\*.mkv" -Recurse
instead of:
Get-ChildItem "$Location\*.mkv"
With the -Recurse parameter, the script will list files in the current directory and for each directory in the current directory, it will do the same recursively. So the .mkv inside other folders won't hide any longer.
I am trying to search for 2 files in a directory tree and delete them. I want to keep the path of the file that had been deleted.
So far that's what I have:
#set the path to search for the file
$path = ".\"
#File name
$file = "GeneratedCode.cs"
$file2 = "TypedEnums.cs"
#Look for the file and delete every instance of it in all directories.
Get-Childitem $path -include $file -recurse | foreach ($_) {remove-item $_.fullname}
#Look for the file and delete every instance of it in all directories.
Get-Childitem $path -include $file2 -recurse | foreach ($_) {remove-item $_.fullname}
EDIT:
I forgot to mention that I want to delete every instance of the files.
I would store the result of the Get-ChildItem cmdlet to a variable lets say $filesToDelete. Then you could simple pipe the object to the Remove-Item cmdlet (you don't need the foreach there):
$filesToDelete = Get-Childitem $path -include $file -recurse
$filesToDelete | Remove-Item
I have a series of folders and subfolders, structured in this way:
001/Fabric/Blue/ (.jpg files, sequentially named)
001/Fabric/Green/ (.jpg files, sequentially named)
002/Fabric/Blue/ (.jpg files, sequentially named)
002/Fabric/Green/ (.jpg files, sequentially named)
etc.
The file names have excess string characters that I would like to remove, and I would like to convert their file names into an easier sequential format (0.jpg, 1.jpg, etc.).
I tried working with a few different PowerShell examples to get this to work. I have the recursive searching functionality working, however I receive an error about an InvalidOperationException when trying to rename the files in the ForEach-Object loop. Additionally, I am afraid my sequential numbering is not being 'reset' for each of the folders where it renames files.
$i = 0
Get-ChildItem -Filter "*.jpg" -Recurse | ForEach-Object {
Rename-Item $_ -NewName ('$i.jpg' -f $i++)
}
So, two questions:
How can I fix the error with Rename-Item?
How can I ensure my variable is reset for each subfolder the script starts renaming files in?
If you take a two step approach, first getting all the folders containing jpg's and then iterating through this list, you have no problem beginning with 1. But I'd always use leading zeroes for such a renumbering.
$BaseFld = "Q:\Test\"
$Ext = "*.jpg"
$jpgFolders = gci $($BaseFld+$Ext) -Recurse |
Select -ExpandProperty Directory -Unique |
select -ExpandProperty Fullname | Sort
ForEach ($Folder in $jpgFolders) {
Set-location $Folder
$i = 1
Get-ChildItem $Ext | %{Ren $_ -NewName ('{0:D4}.jpg' -f $i++) -whatif}
}
If the ouptut suits you, remove the -whatif in the second last line
other method
$rootdir="C:\temp"
gci $rootdir -Recurse -Directory | %{$i=1; gci $_.FullName -Recurse -File -Filter "*.jpg" | %{Ren $_.FullName -NewName ('{0}.jpg' -f $i++)} }