I have 900k files in a particular folder that I need to move daily to another folder based on the total size of 100 mbs. I've tried the following code, but it moves 100 files, not the total amount of 100 mbs
#echo on
set Source=C:\Users\%Username%\Desktop\Dropbox\Pre
set Target=C:\Users\%Username%\Desktop\Dropbox\Pos
set MaxLimit=10
for /f "tokens=1* delims=[]" %%G in ('dir /A-D /B "%Source%\*.*" ^| find /v /n ""') do (
move /y "%Source%\%%~nxH" "%Target%"
if %%G==%MaxLimit% exit /b 0
)
pause
I need the batch to move a selection on files that the sum of their size is less than or equal to 10 kbs. Basically to do the same if I manually selected N files that make up 100 mbs.
I believe that it didn't work because it checks only the single file size.
The basic problem is that you must keep track of how much data has been copied and check to see if it is over MaxLimit. This is not difficult in PowerShell. This script will copy up to $MaxLimit bytes to $TargetDir. This script requires PowerShell Core 6+. The current stable version at https://github.com/PowerShell/PowerShell is 7.1.5. This can be made to work with the old Windows PowerShell 5.1 by changing the Join-Path statements.
Place these two (2) files in the same directory. When you are confident that the correct files will be copied to the correct directory, remove the -WhatIf from the Move-Item command.
=== Move-PictureBatch.bat
#pwsh -NoLogo -NoProfile -File "%~dp0Move-PictureBatch.ps1"
=== Move-PictureBatch.ps1
#Requires -Version 6
$MaxLimit = 100MB
$SourceDir = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop' -AdditionalChildPath 'Pre'
$TargetDir = Join-Path -Path $Env:USERPROFILE -ChildPath 'Desktop' -AdditionalChildPath 'Pos'
$CurrentSize = 0
Get-ChildItem -File -Path $SourceDir |
ForEach-Object {
if (($CurrentSize + $_.Length) -lt $MaxLimit) {
Move-Item -Path $_.FullName -Destination $TargetDir -WhatIf
$CurrentSize += $_.Length
} else {
break
}
}
Related
I have a folder and many subfolders containing videos. One subfolder is named Screenshots and has a folder structure that mirrors the video subfolders. Each video has one jpg screenshot: filename.ext.jpg. Some of those jpg files are no longer needed as the corresponding videos have been deleted.
d:\folder1
- video1.mp4
- video2.mkv
d:\folder2
d:\folder3
d:\screenshots\folder1
- video1.mp4.jpg
- video2.mkv.jpg
d:\screenshots\folder2
d:\screenshots\folder3
I created this to find and delete the outdated jpg's. It saves a list of screenshots with full paths, minus the .jpg, then removes the screenshot folder from the path resulting in a list of paths to the video files.
It is then supposed to return a list of all video files that no longer exist It does that, but also lists many files that are still present.
Looking for a way to fix this, or a smarter way to do the task.
Thank you.
set screenshotlist="%temp%\screenshot_work\screenshots.txt"
set folder=D:\screenshots
mkdir %temp%\screenshot_work
:: get list of screenshots without .jpg extension
for /f "delims=" %%f in ('dir %folder% /s /a-d /b') do echo %%~dpnf >>%screenshotlist%
:: edit screenshots.txt, remove "screenshots\"
call jrepl "screenshots\\" "" /f %screenshotlist% /i /o -
:: check if files exist in D:\
for /f "usebackqdelims=" %%f in (%screenshotlist%) do (if not exist %%f echo %%f needs to be deleted)
rd /s /q %temp%\screenshot_work
pause
The way I have understood your question was that you would like to delete the ".jpg" files within the Screenshots directory that do not have a corresponding video file in the Video directory. A corresponding video file would be the name of the screenshot without the ".jpg" extension.
Open PowerShell ISE
Paste the code into the script pane
Modify $Video_Directory and $Screenshot_Directory
Press Play
$Video_Directory = "C:\temp4\Video"
$Screenshot_Directory = "C:\temp4\Screenshot"
$Date = Get-Date -UFormat "%d %b %Y %H%M%S"
$Transcript_Directory = "C:\POSH_Transcripts"
$Transcript = "$Transcript_Directory\Transcript_$($Date)"
New-Item -ItemType "Directory" -Path $Transcript_Directory
Start-Transcript -Path $Transcript -Append
Get-ChildItem -Path $Screenshot_Directory -File -Recurse -Include "*.jpg" | ForEach-Object {
$Video = $_.Name.Replace(".jpg", "")
If (Test-Path "$Video_Directory\$Video"){
Write-Host -ForegroundColor Green "The video ($($_.Name.Replace(`".jpg`", `"`"))) for the screenshot ($($_.Name)) exists."
}
Else{
Write-Host -ForegroundColor Red "The video for screenshot $($_.Name) does not exist. Removing screenshot."
Remove-Item $_.FullName -Force -Verbose
Write-Host -ForegroundColor Green "$($_.Name) has been removed"
}
}
Stop-Transcript
Start-Process notepad.exe $Transcript
How can I use windows bat or powershell to mass-copy files from child-dirs to the root/main directory? eg,
c:\dir\1
c:\dir\2
c:\dir\3
etc
to
c:\dir
without having to copy-paste them all manually.
In a batch file:
for /d %%d in ("C:\Dir\*") do for %%f in ("%%d\*") do copy "%%f" "%%d\.."
Interactively:
for /d %d in ("C:\Dir\*") do for %f in ("%d\*") do copy "%f" "%d\.."
Hint: for /d iterates over directories. Use for /? for more details.
If it's only the files you want to move then a quick a dirty method would be something like:
$InputFolder = "C:\Dir"
$FilesToMove = Get-ChildItem -LiteralPath $InputFolder -Recurse | where { ! $_.PSIsContainer }
foreach ($File in $FilesToMove)
{
Move-Item -LiteralPath $File.PSPath -Destination $InputFolder -Force
}
So if for example you have:
C:\Dir\MyDir1\File.txt it will move it to c:\dir\file.txt
However, no folders will be moved.
eg say c:\Dir\MyDir2\AnotherDir\ contains File1.txt and Fle2.txt only the .txt files will get moved, c:\Dir\MyDir2\AnotherDir\ would remain intact but without any files.
I have a folder (let's call it mainFolder) which holds hundreds of more folders inside. In each of these hundreds of folders I have two png images and a text file. I want to move (or copy) all the text files into a folder (let's call this targetFolder). How can I do this in Powershell or Batch?
If you want to move all items from source (including subfolders) to the destination.
This should do it:
$Source = "C:\Source"
$Destination = "C:\Destation"
Get-ChildItem -Path $Source -Filter "*.txt" -Recurse | Move-Item -Destination $Destination
You can add -Whatif to the end of the Get-ChildItem (after $Destination) in order to test it before execution
If you want to copy only you can replace the Get-ChildItem line with :
Copy-Item -Path $Source -Recurse -Include "*.txt" -Destination $Destination
Something like this, as an example if you want to copy all txt files from the source, recursively in all sub directories:
for /R "c:\source folder" %%f in (*.txt) do copy "%%f" "c:\destination folder\"
to actually move the files, simply use the command instead of copy, perhaps consider the /Y
If however your destination folder were to be inside of your source folder you could simply ignore it.
for /R "c:\source folder" %%f in (*.txt) do (
if not "%~dpf"=="c:\source folder\" copy "%%f" "c:\destination folder\"
)
I have a text file list of approx 120,000 filenames. Many of the files on the list are in a folder or it's subfolders, but with slight variations on the filenames.
so I want to search using the list of partial filenames and copy the matches to another folder.
Each line on the list is a name and a title separated by a bar for example:
A Name|The Title
John Smith|A Life
The files are various text formats and all have extra stuff in the filenames like:
A Name - The Title V1.4 (html).lit
John Smith - A Life: Living on the Edge [MD] (pdf).rar
I've tried the code from this thread
and this thread but neither are finding any of the files. Can anyone help please.
This PowerShell script assumes that if both the first field "name" and the second field "title" are anywhere in the filename that it should be copied. When you are confident that the correct files will be copied, remove the -WhatIf from the Copy-Item command.
Note that this does not address the issue of multiple files with the same name.
If you wanted to require the "name" field to be at the beginning of the string, you could add it to the match expression. $_.Name -match '^'+$pair.name. If you want the matches to be case sensitive, use -cmatch.
$sourcepath = 'C:\src'
$targetpath = 'C:\other'
$searchpairs = Import-Csv -Header "name","title" -Delimiter "|" -Encoding ASCII -path .\mdb.txt
foreach ($pair in $searchpairs) {
Get-ChildItem -Recurse -File -Path $sourcepath |
Where-Object { ($_.Name -match $pair.name) -and ($_.Name -match $pair.title) } |
ForEach-Object { Copy-Item $_.FullName $targetpath -WhatIf}
}
Adjust the paths and you should be good with this one:
#ECHO OFF
REM **************************************************
REM Adjust location of list
SET list=C:\adjust\path\list.txt
REM Source dir
SET source=C:\adjust\path\source
REM Target dir
SET destination=C:\adjust\path\destination
REM **************************************************
FOR /F "tokens=1,* delims=|" %%A IN (%list%) DO (
ECHO.
ECHO %%A - %%B
CALL :copy "%%A - %%B"
)
ECHO.
ECHO Done^!
PAUSE
EXIT
:copy
FOR /R "%source%" %%F IN (*) DO (
ECHO "%%~nF" | FINDSTR /C:%1 >nul && COPY "%%~fF" "%destination%\%%~nxF" && EXIT /B
)
EXIT /B
Be aware: this requires the scheme in list.txt to be A|B and the scheme of every file to be copied *A - B* (including spaces) while * may be no or any character(s).
Might not be the solution you are looking for, but I ditched batch scripting years ago. I use Powershell instead, and simply call the Powershell script from batch file.
Here is the code in case you are interested,
searchfiles.ps1
$searchStrings = #("city", "sniper") # Declare an array to iterate over.
foreach ($string in $searchStrings) {
Get-ChildItem -Path D:\Movies\Movies | ? { $_ -match $string }
}
And now call the Powershell script from batch file.
searchfiles.bat
Powershell.exe -ExecutionPolicy RemoteSigned -Command "& searchfiles.ps1 -Verb RunAs"
Hope it helps!
That's not to say I don't use batch scripting at all. I will use them only for simpler operations, like calling another script, or opening a folder, etc. With Powershell, I love taking the help of the underlying .NET framework and sweet piping!
Ok, so I have a large amount of ebooks and other files that I would like to sort into folders by Author name. The way I would normally do this in Linux will not work on my Windows 8 laptop. I've been using Powershell, but if there is a better way in Python or by using a bash script I am willing to use whichever can get this done the easiest way. I need it to work recursively because there are many subfolders, (a lot are sorted by genre). What I have tried so far is:
mkdir 'C:\Users\Amanda\Downloads\BOOKS\Peter Straub'
Copy-Item 'C:\Users\Amanda\Downloads\*Peter Straub*' -recurse `
'C:\Users\Amanda\Downloads\BOOKS\Peter Straub'
Unfortunately for me, that only looks for directories named peter straub. And if i change it to ~\Downloads*Peter Straub*.* it just doesn't work. I tried using the -match and -contains but they failed to work as well. I am relatively new to scripting in windows 8 and would really appreciate anyones help. I would like to implement the read-host -prompt so I don't have to edit the script everytime i run it. And I would like it to actually MOVE the file not just copy but Move-Item doesn't have a recurse option. So could I somehow have the script copy and then delete the original. I tried this also:
$author = (read-host -prompt 'Enter Name')
mkdir 'C:\Users\Amanda\Downloads\BOOKS\$author'
Copy-Item 'C:\Users\Amanda\Downloads\*$author*.*' -Recurse | Remove-Item
But this also did not work. I would love to get something like this to work in an automated batch.
So basically I want to pick an authors name, make a new directory using that authors name, then search and move all files containing that authors name into the new directory.
EDIT::::
So basically I combined the suggestions of the three answers and what I got works PERFECTLY! Here is the .bat that worked:
#echo off &setlocal
set /p "Author=Enter Name: "
md "%author%"
for /f "delims==" %%i in ('dir C:\Users\Amanda\Downloads /b /s^|find "%author%" /i') do (move "%%i" "C:\Users\Amanda\Downloads\BOOKS\%author%")
EDIT AGAIN:
So I tried the revised one to try and get it to accept spaces:
#echo off &setlocal
set /p "Author=Please enter an Author: "
md "C:\Users\Amanda\Downloads\BOOKS\%author%"
for /f "delims==" %%i in ('dir C:\Users\Amanda\Downloads /b /s^|find "%author: =.%" /i') do (move "%%i" "C:\Users\Amanda\Downloads\BOOKS\%author%")
It works correctly in making the directory but it does not move the files.
set /p author=Please enter an Author:
md "C:\Users\Amanda\Downloads\BOOKS\%author%"
for /f "delims==" %%i in ('dir C:\Users\Amanda\Downloads /b /s^|findstr "%author: =*%"') do (move "%%i" "C:\Users\Amanda\Downloads\BOOKS\%author%"
this should work. if not, please comment so I can fix it.
Try this:
$author = (read-host -prompt 'Enter Name')
$basedir = 'C:\Users\Amanda\Downloads'
$destdir = "$basedir\BOOKS\$author"
New-Item $destdir -Type directory
Get-ChildItem $basedir -Recurse | ? {
-not $_.PSIsContainer -and
$_.Name -like "*$author*" -and
$_.Directory.FullName -ne $destdir
} | % {
Copy-Item $_.FullName "$destdir\"
Remove-Item $_.FullName
}
#echo off &setlocal
set /p "author=Enter the author's name: "
cd /d "C:\Users\Amanda\Downloads"
md "books\%author%"
for /r %%a in (*"%author%"*) do move "%%~fa" "books\%author%"