PowerShell Move-Item to folders efficiently - powershell

I am trying to to create an efficient PowerShell script that moves a list of files of .xlsx extension into another folder. About 30 files get generated with the current month and year at the end e.g "- January 2018" into this folder path \otnas6uk\sd.test-it.com$\PROJECTS\
Ideally if the Month and Year could be defined at the start so it loops through all files in the root directory and moves them to the correct folder listed.
This is pseudocode of how I think it could work.
$month = "February"
$year = "2018"
Move-Item -Path "\\otnas6uk\sd.test-it.com$\PROJECTS\\Zentic Report - $month $year.xlsx" -Destination \\zemnas\sd.Zentic-test.com$\Technology\Reports
All files and destinations would be predefined with only the month and year used as a parameter.

#region inputs
$month = 12
$year = 2018
$sourceDirectory = "C:\temp"
$destinationDirectory = "C:\destination"
$fileFilter = "*.xlsx"
#endregion
#region input validation
if (-not (Test-Path -Path $sourceDirectory)) {
throw "Can't find source directory"
}
# Month has to be between 1 and 12
if ($month -lt 1 -or
$month -gt 12
) {
throw "BAD MONTH!"
}
# Recent-ish years only
if ($year -lt ((Get-Date).Year - 1) -or
$year -gt ((Get-Date).Year + 2)
) {
throw "BAD YEAR!"
}
#region
#region destination
# Build up new folder path
$destinationDirectory = Join-Path -Path $destinationDirectory -ChildPath $year
$destinationDirectory = Join-Path -Path $destinationDirectory -ChildPath $month
#Create destination if not exists
if (-not (Test-Path -Path $destinationDirectory)) {
New-Item -Path $destinationDirectory -ItemType Directory | Out-Null
}
#endregion
#region move files
Get-childItem -Path $sourceDirectory -File -Filter $fileFilter |
Move-Item -Destination $destinationDirectory
#engregion

$oldFolder = '\\otnas6uk\sd.test-it.com$\PROJECTS\\Zentic Report'
$jan2018Folder = '\otnas6uk\sd.test-it.com$\PROJECTS'
# Get a list of the files ending with .xlsx
$files = Get-ChildItem $oldFolder | Where { $_.Extension -eq '.xlsx' }
# Move each file over to the new directory
foreach ($file in $files) {
# Repeat if for all months
if ($file.Name -like '*January*' -and $file.Name -like '*2018*') {
$newPath = "$jan2018Folder\$($file.Name)"
}
Move-Item $file $newPath
}

May be this should help move forward:
$Month = "Febuary";
$Year = "2018"
dir .\excelfiles\*$Month*$Year.xlsx|%{move-item -Path $_.FullName -Destination .\Destination.Folder}

Related

Archive files from a folder which are older than one week to a sub folder using powershell

I have tried below powershell script to move files older than 7 days from Newfolder to Archive_folder. The script is moving the entire path to the Archive_folder (means its creating folders \Users\529817\New folder in to Archive_folder and then copying files and not zipping the folder) , I need help in copying only files from NewFolder to Archive_folder and zip that folder.
$ArchiveYear = "2018"
$ArchiveMonth = "10"
$ArchiveDay = "10"
$SourcePath = "C:\Users\529817\New folder"
$TargetPath = "C:\Users\529817\New folder\Archive_folder"
$YourDirToCompress = "C:\Users\529817\New folder"
$ZipFileResult = "C:\Users\529817\New folder\Archive_folder\$ArchiveDay$ArchiveMonth.zip"
Get-ChildItem $YourDirToCompress -Directory |
#where { $_.Name -notin $DirToExclude} |
Compress-Archive -DestinationPath $ZipFileResult -Update
$Days = "7"
$LogPath = "C:Users\529817\Temp"
$Date = Get-Date -format yyyy-MM-dd_HH-mm
$TargetFolder = "$TargetPath\$Date"
$LogFile = "$LogPath\ArchiveLog-$date.txt"
$TargetZipFile = "$TargetPath\$Date.zip"
$Activity = "Move files older than $Days days from $SourcePath to $TargetFolder"
Write-Verbose $Activity
$OldFiles = Get-Childitem -Path $SourcePath -recurse | Where-Object {$_.LastWriteTime -lt (get-date).AddDays( - $days)}
$Total = $Oldfiles.Count
$Current = 0
$OldFiles | ForEach {
$Current ++
$Filename = $_.fullname
Write-Progress -Activity $Activity -Status $FileName -PercentComplete ($Current / $Total * 100)
$Split = $FileName -split '\\'
$DestFile = $split[1..($split.Length - 1)] -join '\'
$DestFile = "$TargetFolder\$DestFile"
Try {
$null = New-Item -Path $DestFile -Type File -Force
$Null = Move-Item -Path $FileName -Destination $DestFile -Force -ErrorAction:SilentlyContinue
"Successfully moved $filename to $targetfolder" | add-content $LogFile
}
Catch {
$Err = $_.Exception.Message
Write-Error $Err
"Error moving $filename`: $Err " | add-content $LogFile
}
}
You have two problems here:
Your zip file isn't going where you want it to go
Instead, all of the items which should be in the zip are going where the zip should go.
Let's figure out why this is happening so you can do what you need to get it working.
Problem 1
You have line 10 which looks like this:
Compress-Archive -DestinationPath $ZipFileResult -Update
This creates the Zip file but you don't actually do anything with this file, as in we don't see this $ZipFileResult used again in the code. This is why your zip file isn't showing up where you want it to be.
Problem 2
The end of this script has this big block where you are expressly copying the files to the directory,right where you don't want them.
Try {
$null = New-Item -Path $DestFile -Type File -Force
$Null = Move-Item -Path $FileName -Destination $DestFile -Force -ErrorAction:SilentlyContinue
"Successfully moved $filename to $targetfolder" | add-content $LogFile
}
If you only want to move the Zip file, then you can shorten this whole script. Delete everything from line 19 and on down, which begins with this line.
$OldFiles = Get-Childitem -Path $SourcePath -recurse | Where-Object {$_.LastWriteTime -lt (get-date).AddDays( - $days)}
And instead, add a Move-Item command to copy that $ZipFileResult file over to whichever directory you want it to go.
Finally, there are a number of lines which don't do anythign and can be deleted, like this line $TargetZipFile = "$TargetPath\$Date.zip"

PowerShell moving files based on dates

I'm trying to move all files six months or older into an archive file
I have
#set root folder
$baseFolder = "C:\Users\Caleb\Desktop"
$archiveBase = "C:\Users\Caleb\Desktop"
$limit_to=(Get-date (Get-date -Format d)).AddDays(-180)
#get files inside root
$folder = Get-ChildItem $baseFolder -File
#for each folder
foreach($file in Where-$folder.CreationTime -lt $limit_to ) {
#build the move destination path
$a=$file.CreationTime.Date.Year
$archive="Archive"
$name=$a+" "+$archive
$destination = Join-Path $archiveBase $name
#Create Directory And Deposite Files
if(Test-Path $destination)
{
mv $file $destination
}
else
{
mkdir $destination
mv $file $destination
}
}
I cant seem to get only the files that are older than 180 days.
I am a beginner so any efficiency changes I could make I'm open to
try this
$baseFolder = "C:\Users\Caleb\Desktop\"
$archiveBase = "C:\Users\Caleb\Desktop\"
$limit_to=(Get-date (Get-date -Format d)).AddMonths(-6)
mkdir $archiveBase -force
Get-ChildItem $baseFolder -File | where CreationTime -lt $limit_to | foreach {move-item $_.FullName -Destination ($archiveBase + $_.CreationTime.Year + " Archive" + $_.Name) -Force }

Powershell: Move files to folder based on Date Created

I'm not a coder but I've still attempted tweaking PS scripts found here and still can't get the behavior I desire. The tough part for me has been the 2 digit Day requirement (dd). After several noob attempts I would like some help.
I have a folder that contains hundreds of JPG's. I manually sort these JPG's into folders based on the date taken. Folder name examples are 2015.02.04, 2016.10.31, 2016.12.01.
1) I would like a script to scan my JPG folder.
2) For each file, scan the date
3) If the file was created June 1st, 2016 then it will be moved to .\2016.06.01
Help a brother out?
$Filepath = ""
$file = ""
$date = ""
$month = ""
$year = ""
$MonthPath = ""
$FilePath = Read-Host "Place the directory which contains the files."
Write-Warning "Note: This action can take several minutes, depending on the amount of files in $FilePath."
get-childitem $FilePath | % {
$file = $_.FullName
$date = Get-Date ($_.LastWriteTime)
$month = $date.month
$year = $date.year
$day = $date.day
$MonthPath = "$FilePath\$year.$month.$day"
Write-Verbose "month = $month"
Write-Verbose "Date = $date"
Write-Verbose "year = $year"
Write-Verbose "FilePath = $FilePath"
Write-Verbose "Filename = $file"
Write-Verbose "MonthPath = $MonthPath"
if(!(Test-Path -Path "$MonthPath" )){
Write-Verbose "Creating log location $MonthPath."
#Write-Host -backgroundcolor green -ForegroundColor black "Creating log location $MonthPath."
Write-Verbose "MonthPath inside path test = $MonthPath"
New-Item -ItemType directory -Path $MonthPath | Out-null
}
ELSE {
#Write-Host -backgroundcolor green -ForegroundColor black "Log location exists already exist $MonthPath"
Write-Verbose "Log location exists already exist $MonthPath"
}
move-item "$file" "$MonthPath" | Out-null
}
Write-Warning "All files are sorted now based upon year and month."
[DateTime]$start_time="2016-6-1 00:00:00"
[DateTime]$end_time="2016-6-1 23:59:59"
$des_folder = "C:\test\2016.06.1"
Get-ChildItem c:\test\*.jpg -Recurse | foreach {if($_.lastwritetime -ge $start_time -and $_.lastwritetime -le $end_time) { move-item $_.fullname $des_folder }}
Please ensure there is no name conflict .
You may change"c:\test" in "c:\test*.jpg" to the path you want to scan .
Also the value of variable "$des_folder" to the destination folder you want to store the matched pictures .
EDIT:
Get-ChildItem c:\test\test2\*.jpg -Recurse | foreach {
$x = $_.LastWriteTime.ToShortDateString()
$new_folder_name = Get-Date $x -Format yyyy.MM.dd
$des_path = "c:\test\test2\$new_folder_name"
if (test-path $des_path){
move-item $_.fullname $des_path
} else {
new-item -ItemType directory -Path $des_path
move-item $_.fullname $des_path
}
}
I ended up creating a script that does exactly what you're asking for here. You can find it in GitHub here, which will have the latest version of the code.
Here is the current implementation, edited for conciseness, removed unnecessary features, and tailored to the question's needs:
[string] $SourceDirectoryPath = 'C:\FilesToMove'
[string] $TargetDirectoryPath = 'C:\SortedFiles'
[System.Collections.ArrayList] $filesToMove = Get-ChildItem -Path $SourceDirectoryPath -File -Force -Recurse
$filesToMove | ForEach-Object {
[System.IO.FileInfo] $file = $_
[DateTime] $fileDate = $file.LastWriteTime
[string] $dateDirectoryName = $fileDate.ToString('yyyy.MM.dd')
[string] $dateDirectoryPath = Join-Path -Path $TargetDirectoryPath -ChildPath $dateDirectoryName
if (!(Test-Path -Path $dateDirectoryPath -PathType Container))
{
Write-Verbose "Creating directory '$dateDirectoryPath'."
New-Item -Path $dateDirectoryPath-ItemType Directory -Force > $null
}
[string] $filePath = $file.FullName
Write-Information "Moving file '$filePath' into directory '$dateDirectoryPath'."
Move-Item -Path $filePath -Destination $dateDirectoryPath
}
Note that it copies the file paths into an array before iterating over them. This is important for the cases where you are copying files to subdirectories of their current directory, otherwise Get-ChildItem could scan files twice, iterating over files that it just moved.
Expanded more to cover off duplicates
$jpg_files = Get-ChildItem "F:\*.jpg" -Recurse
foreach ($jpg in $jpg_files){
$x = $jpg.LastWriteTime.ToShortDateString()
$new_folder = Get-Date $x -Format yyyy-MM-dd
$des_path = "F:\Photos\$($new_folder)"
if (Test-Path $des_path){
if (Test-Path "$($des_path)\$($jpg.Name)"){
$index = 1
do {
$new_name = $des_path + "\" + $jpg.BaseName + " ($($index))" + $jpg.Extension
$index++
} While(Test-Path $new_name)
move-item $jpg.fullname -destination $new_name
}else {
move-item $jpg.fullname $des_path
}
}
else {
new-item -ItemType directory -Path $des_path
move-item $jpg.fullname $des_path
}
I would like to propose this variant based on last response for duplicates showing that multiple files can be selected and also that removing the absolute paths works and it will move the files that are bellow of your current prompt no mathers where the file is. Also add a missing }. Thanks to all that contributes to this thread, this helps a lot to organize the pictures and video!
$files = Get-ChildItem "*.jpg","*.mp4" -Recurse
foreach ($file in $files) {
$x = $file.LastWriteTime.ToShortDateString()
$new_folder = Get-Date $x -Format yyyy-MM
$des_path = "$($new_folder)"
if (Test-Path $des_path) {
if (Test-Path "$($des_path)\$($file.Name)") {
$index = 1
do {
$new_name = $des_path + "\" + $file.BaseName + " ($($index))" + $file.Extension
$index++
} While(Test-Path $new_name)
move-item $file.fullname -destination $new_name
}else {
move-item $file.fullname $des_path
}
}
else {
new-item -ItemType directory -Path $des_path
move-item $file.fullname $des_path
}
}

how to only move specific file types in powershell

I'm trying to move only specific filetypes (.txt,.fehler for example) to another directory. I want to seperate the files by last modified date into seperate folders (by year). If the directory isn't there it should create that folder. The following code works, if I am not filtering for the file types. What do i need to do to filter correctly?
This is my code so far:
$path = "H:\Downloads\tmp\source\"
$targetDir = "H:\Downloads\tmp\dst\"
Foreach($file in (Get-ChildItem $path -Include *.txt,*.fehler))
{
$year = $file.LastWriteTime.Year
$pastePath = $targetDir + $year.ToString()
if(-not (Test-Path $pastePath ) -and ($year.ToString().Length -eq 4))
{
md $pastePath
}
$source = $path + $file
Move-Item $source $pastePath -Force
}
Put your extentions in quotes,
Like this:
Foreach($file in (Get-ChildItem $path -include "*.txt","*.fehler"))
I still don't know why the filter isn't working but this works for me:
$path = "H:\Downloads\tmp\source\"
$targetDir = "H:\Downloads\tmp\dst\"
Foreach($file in (Get-ChildItem $path | Where-Object {$_.Extension -match ".txt" -or ".fehler" } ))
{
$year = $file.LastWriteTime.Year
$pastePath = $targetDir + $year.ToString()
if(-not (Test-Path $pastePath ) -and ($year.ToString().Length -eq 4))
{
md $pastePath
}
$source = $path + $file
Robocopy.exe $path $pastePath $file /MOV
<#Move-Item $source $pastePath -Force -Verbose#>
}

Copy Wav files older than 3 months to archive, creating year\month paths

I was hoping someone can help me out with this script which is currently baffling me, I'm not very good at powershell ;)
What I'm trying to achieve is a script that will scan folders and subfolders of my source, looking for *.wav files older than 60 days and then move them to an archive destination, creating a folder structure of \year\month
This is what i've got
$SourceDir = "d:\test"
$DestinationDir = "e:\test"
$files = get-childitem $SourceDir *.wav
foreach ($file in $files)
{
$Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
where-object {$_.LastWriteTime -lt (get-date).AddDays(-61)} | move-item $file.fullname $Directory
}
The script runs without error but doesn't move files :/
--
Following on from Keiths comments below, my script looks as so:
$SourceDir = "d:\test\"
$DestinationDir = "e:\test\"
$date = (get-date).AddDays(-91)
$files = get-childitem -literalpath $SourceDir *.wav
foreach ($file in $files)
{
$Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
if ($file.LastWriteTime -lt $date) {
Write-Host $file
move-item -LiteralPath $file.fullname -Destination $Directory
}
}
And is working perfectly! Thanks Keith
Where-Object is never at the beginning of a pipeline. It requires input to populate the $_ variable you usually use to compare against. Replace that line with:
if ($file.LastWriteTime -lt (get-date).AddMonths(-3)) {
move-item $file.fullname $Directory
}
Although I would compute the date outside the loop:
$date = (get-date).AddMonths(-3)
And use that inside the loop:
...
if ($file.LastWriteTime -lt $date) {
Move-Item -LiteralPath $file.fullname -Destination $Directory
}
...