Piped dir within Foreach - powershell

I'm writing a script to delete pdf files older than 6 months in folder with the 'Email' prefix.
However, my second dir command within my foreach never runs, its code is blocked.
$Now = Get-Date;
$DaysTillDelete = "180";
$LastWrite = $Now.AddDays(-$DaysTillDelete);
$TargetFolder = "C:\Test EMDATA\EMDATA\";
$BackupPath = "\\SHPFS02\IT\EmPower Old";
$EmailFolders = #();
if(-Not(Test-Path -path ($TargetFolder + "\OldFiles" ))) {
mkdir -p ($TargetFolder +"\OldFiles");
}
$Network = Test-Path $BackupPath
#New-PSDrive -Name O -PSProvider FileSystem -Root "$BackupPath"; #-Credential $cred
Write-Host "Running Script"
dir $TargetFolder | %{
# Only delete files with the Email prefix
$name = $_.Name;
if ($_.Name.Length -le 5) {return;}
$id = $_.Name.SubString(0,5);
if ($id -eq "Email")
{
Write-Host "Found slip folder"
$EmailFolders += $TargetFolder + $_;
}
}
ForEach ($folder in $EmailFolders)
{
Write-Host $folder;
dir -path $folder -include *.pdf | %{
Write-Host "Checking" $name;
# Only select files older than 6 months
if( $_.LastWriteTime -le "$LastWrite")
{
$activeItem = Get-Item $TargetFolder + $_;
#Move files into oldfiles
Write-Host $TargetFolder
move-item -path $activeItem -destination ($TargetFolder + "OldFiles\");
if ($Network)
{
move-item -path $activeItem -destination "O:\";
}
Write-Host $_;
remove-item $activeItem;
Write-Host "Deleting" + $name;
}
}
}
The script works till line 31 but doesn't continue on past line 32 and being a fairly beginner PS user I can't see why.

Only use -include with the -recurse parameter.
http://technet.microsoft.com/en-us/library/hh849800.aspx
The Include parameter is effective only when the command includes the
Recurse parameter or the path leads to the contents of a directory,
such as C:\Windows*, where the wildcard character specifies the
contents of the C:\Windows directory.
What you want instead is the -filter parameter:
dir -path $folder -filter *.pdf

Related

Powershell: Find folders with a specific name, and move contents up one level, rename if exists

I've got the first two-thirds of this one accomplished, but I'm stuck on the last part. I've got a script that searches for subfolders with a specific name, and moves their contents up one level. I have another script that moves files from one place to another, and renames them if the file already exists. What I'm trying to do now is merge the two. So here's the one that moves files up:
$sourceDir="E:\Deep Storage"
$searchFolder="Draft Materials"
Get-ChildItem -path $sourceDir -filter $searchFolder -Recurse |
ForEach-Object {
Get-ChildItem -File -Path $_.FullName |
ForEach-Object {
Move-Item -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath)
}
}
And here's the one that moves things while renaming if they already exist:
$sourceDir="E:\Test1"
$targetDir="E:\Deep Storage\Test1"
Get-ChildItem -Path $sourceDir -Filter *.* -Recurse | ForEach-Object {
$num=1
$nextName = Join-Path -Path $targetDir -ChildPath $_.name
while(Test-Path -Path $nextName)
{
$nextName = Join-Path $targetDir ($_.BaseName + "_$num" + $_.Extension)
$num+=1
}
$_ | Copy-Item -Destination $nextName -Verbose
}
And lastly, my attempt to hybridize the two:
$sourceDir="E:\Deep Storage"
$searchFolder="Draft Materials"
Get-ChildItem -path $sourceDir -filter $searchFolder -Recurse |
ForEach-Object {
Get-ChildItem -File -Path $_.FullName |
ForEach-Object {
$num=1
$nextName = Join-Path -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath)
while(Test-Path -Path $nextName)
{
$nextName = Join-Path -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath) ($_.BaseName + "_$num" + $_.Extension)
$num+=1
}
$_ | Copy-Item -Destination $nextName
}
}
I feel like I'm on the right track, but after two hours of attempts I haven't been able to get this to work.
EDIT: providing the exact syntax I'm giving it
$sourceDir="E:\Deep Storage\Projects"
$searchFolder="Draft Materials"
$destinationPath = "$($sourceDir)\.."
Write-Host "OPERATION: Search for Folders Named" -ForegroundColor White -BackgroundColor DarkGreen -NoNewLine;
Write-Host " '$searchFolder' " -ForegroundColor Yellow -BackgroundColor DarkGreen -NoNewLine;
Write-Host "and Move Contents Up One Level" -ForegroundColor White -BackgroundColor DarkGreen;
Write-Host "SEARCHDIR: $sourceDir" -ForegroundColor White -BackgroundColor DarkGreen;
# Get all directories in specific folders inside the source directory
$folders = Get-ChildItem -Path $sourceDir -Directory | Where-Object {$_.Name -like "$searchFolder*" -or $_.FullName -like "*\$searchFolder\*"}
foreach ($folder in $folders) {
# Get all files in the current folder
$files = Get-ChildItem -Path $folder.FullName
foreach ($file in $files) {
$destinationFile = Join-Path -Path $destinationPath -ChildPath $file.Name
if (Test-Path $destinationFile) {
# If a file with the same name exists in the destination directory, rename it
$name = $file.Name
$extension = $file.Extension
$i = 0
while (Test-Path $destinationFile) {
$i++
$name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
$destinationFile = Join-Path -Path $destinationPath -ChildPath $name
}
Write-Host "Renaming $($file.Name) to $name"
}
Move-Item $file.FullName $destinationFile -Verbose -WhatIf
}
}
Here's what I came up with reading OP's post, code, and comments:
$sourcePath = 'E:\Deep Storage\Projects'
$searchFolder = 'Draft Materials'
Write-Host "OPERATION: Search for Folders Named" -ForegroundColor White -BackgroundColor DarkGreen -NoNewLine;
Write-Host " '$searchFolder' " -ForegroundColor Yellow -BackgroundColor DarkGreen -NoNewLine;
Write-Host "and Move Contents Up One Level" -ForegroundColor White -BackgroundColor DarkGreen;
Write-Host "SEARCHDIR: $sourcePath" -ForegroundColor White -BackgroundColor DarkGreen;
# Get all directories in specific folders inside the source directory
$folders = (Get-ChildItem -LiteralPath $sourcePath -Directory -Recurse) | Where-Object Name -match $searchFolder
### Check selected folders
$Folders.FullName | Out-GridView -Title 'Selected Folders'
Read-Host 'Paused. Check selected folders in GridView. Press <enter> to continue '
###
ForEach ($folder in $folders)
{
# Get all files in the current folder
$filesToCopy = $folder | Get-ChildItem -File
# Get list of names for exising files in target (parent folder)
$targetPath = $folder.Parent.FullName
$filesInTarget = (Get-ChildItem -LiteralPath $targetPath -File).Name
ForEach ($file in $filesToCopy)
{
If ($file.Name -notIn $filesInTarget)
{
$file | Move-Item -Destination $targetPath -Verbose -WhatIf
}
Else
{
$i = 0
Do
{
$newName = '{0}_{1}{2}' -f ($file.BaseName, $i++, $file.Extension)
} Until ( $newName -notIn $FilesInTarget )
Write-Host ('Renaming "{0}" to "{1}"...' -f $file.Name , $newName)
$file | Move-Item -Destination (Join-Path $targetPath $newName) -Verbose -WhatIf
}
}
# Delete (hopefully empty) folder
If (!($folder | Get-ChildItem -Force))
{
$folder | Remove-Item -WhatIf
}
Else
{
Write-Host ('Items still exist in "{0}". Folder not deleted.' -f $folder.FullName)
}
}
Syntax choice: For any cmdlet that has Path/LiteralPath parameter sets (gci, Copy, Move, Rename, etc.), the System.IO.FileSystemInfo | <Cmdlet> syntax succeeds with items that would fail in the <Cmdlet> -Path (System.IO.FileSystemInfo).FullNaame form becasue special characters in their name would require the -LiteralPath parameter.
In many cases replacing -Path with -LiteralPath (or its alias: -lp) will work as well. But the pipelined format reads "cleaner" (IMHO) when scanning code and, if you're just learning PowerShell, reminds you to think in terms of pipelining whenever possible and avoiding intermediate variables. Just for grins, here's a version of the above code where items are piped as much as possible, using ForEach-Object:
(Get-ChildItem -LiteralPath $sourcePath -Directory -Recurse) |
where Name -match $searchFolder |
ForEach-Object {
# Get list of names for exising files in target (parent folder)
$targetPath = $_.Parent.FullName
$filesInTarget = (Get-ChildItem -LiteralPath $targetPath -File).Name
$_ | Get-ChildItem -File | ForEach-Object {
If ($_.Name -notIn $filesInTarget)
{
$_ | Move-Item -Destination $targetPath -Verbose -WhatIf
}
Else
{
$i = 0
Do
{
$newName = '{0}_{1}{2}' -f ($_.BaseName, $i++, $_.Extension)
} Until ( $newName -notIn $FilesInTarget )
Write-Host ('Renaming "{0}" to "{1}"...' -f $_.Name , $newName)
$_ | Move-Item -Destination (Join-Path $targetPath $newName) -Verbose -WhatIf
}
}
# Delete (hopefully empty) folder
If (!($_ | Get-ChildItem -Force))
{
$_ | Remove-Item -WhatIf
}
Else
{
Write-Host ('Items still exist in "{0}". Folder not deleted.' -f $_.FullName)
}
}
please try this:
$sourcePath = "C:\temp\test\Test"
$destinationPath = "$($sourcePath)\.."
# Get all files in the source directory
$files = Get-ChildItem -Path $sourcePath
foreach ($file in $files) {
$destinationFile = Join-Path -Path $destinationPath -ChildPath $file.Name
if (Test-Path $destinationFile) {
# If a file with the same name exists in the destination directory, rename it
$name = $file.Name
$extension = $file.Extension
$i = 0
while (Test-Path $destinationFile) {
$i++
$name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
$destinationFile = Join-Path -Path $destinationPath -ChildPath $name
}
Write-Host "Renaming $($file.Name) to $name"
}
Move-Item $file.FullName $destinationFile
}
This will not delete the original location and will move everything from the sourcePath to the parent location.
To delete the original location just add at the end:
Remove-Item -Path $sourcePath -Force -Confirm:$false
UPDATE1:
$sourcePath = "C:\temp\test\Test"
$destinationPath = "$($sourcePath)\.."
# Get all directories in specific folders inside the source directory
$folders = Get-ChildItem -Path $sourcePath -Directory | Where-Object {$_.Name -like "Folder1*" -or $_.FullName -like "*\Folder2\*"}
foreach ($folder in $folders) {
# Get all files in the current folder
$files = Get-ChildItem -Path $folder.FullName
foreach ($file in $files) {
$destinationFile = "$($folder.FullName)\.."
if (Test-Path $destinationFile) {
# If a file with the same name exists in the destination directory, rename it
$name = $file.Name
$extension = $file.Extension
$i = 0
while (Test-Path $destinationFile) {
$i++
$name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
$destinationFile = Join-Path -Path $destinationPath -ChildPath $name
}
Write-Host "Renaming $($file.Name) to $name"
}
Move-Item $file.FullName $destinationFile
}
}

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"

Copy file based a specified folder based on file name. Create folder if it doesn't exist

I'm trying to copy files to a specific folder based on a file name.
For example:
Current Folder - C:\Stuff\Old Files\
The File- 206.Little Rock.map.pdf
Destination Folder - D:\Cleanup\206\Repository
So basically the leading number on the file (206) is part of the subfolder. The "\Repository" would stay constant. Only the leading number would change.
If the file was 207.Little Rock.map.pdf then the destination folder would be
D:\Cleanup\207\Repository
I started with a code I got from here but I'm not sure how to account for the change in number and how to make it create a folder if the folder doesn't exist. So 206\Repository would probably already exist, but I would need the script to create the folder if it doesn't.
$SourceFolder = "C:\Stuff\Old Files\"
$targetFolder = "D:\Cleanup\"
$numFiles = (Get-ChildItem -Path $SourceFolder -Filter *.pdf).Count
$i=0
clear-host;
Write-Host 'This script will copy ' $numFiles ' files from ' $SourceFolder ' to ' $targetFolder
Read-host -prompt 'Press enter to start copying the files'
Get-ChildItem -Path $SourceFolder -Filter *.PDF | %{
[System.IO.FileInfo]$destination = (Join-Path -Path $targetFolder -ChildPath $Name.Repository(".*","\"))
if(!(Test-Path -Path $destination.Directory )){
New-item -Path $destination.Directory.FullName -ItemType Directory
}
[int]$percent = $i / $numFiles * 100
copy-item -Path $_.FullName -Destination $Destination.FullName
Write-Progress -Activity "Copying ... ($percent %)" -status $_ -PercentComplete $percent -verbose
$i++
}
Write-Host 'Total number of files read from directory '$SourceFolder ' is ' $numFiles
Write-Host 'Total number of files that was copied to '$targetFolder ' is ' $i
Read-host -prompt "Press enter to complete..."
clear-host;
This should do mostly what you need. You might have to tweak the destination path a bit, but that should be fairly straight forward to figure out. I Highly recommend that use a '-' as the delimiter for your file prefix as opposed to a '.' as this will prevent accidentally moving EVERY FILE in a directory if you happen to execute it in the wrong place.
Also, when you write a script, do create functions to do individual units of work, and then call those functions at the end. It's much easier to modify, and debug that way.
<#
.SYNOPSIS
Moves files from source to destination based on FileName
Creates destination folder if it does not exist.
.DESCIPTION
The script expects files with a prefix defined by a hyphen '-' i.e. 200-<filename>.<ext>.
There is no filename validation in this script; it will *probably* skip files without a prefix.
A folder based on the prefix will be created in the destination.
If your file is name string-cheese.txt then it will be moved to $DestinationIn\string\string-cheese.txt
.PARAMETER SourceIn
Source Path (folder) where your files exist.
.PARAMETER DestinationIn
Target Path (folder) where you want your files to go.
.EXAMPLE
& .\CleanUp-Files.ps1 -SourceIn "C:\Users\User\Documents\Files\" -DestinationIn "C:\Users\User\Documents\Backup\" -Verbose
.NOTES
Author: RepeatDaily
Email: RepeatedDaily#gmail.com
This script is provided as is, and will probably work as intended. Good Luck!
https://stackoverflow.com/questions/50662140/copy-file-based-a-specified-folder-based-on-file-name-create-folder-if-it-doesn
#>
[CmdletBinding()]
param (
[string]$SourceIn,
[string]$DestinationIn
)
function Set-DestinationPath {
param (
[string]$FileName,
[string]$Target
)
[string]$NewParentFolderName = $FileName.SubString(0,$FileName.IndexOf('-'))
[string]$DestinationPath = Join-Path -Path $Target -ChildPath $NewParentFolderName
return $DestinationPath
}
function Create-DestinationPath {
[CmdletBinding()]
param (
[string]$Target
)
if (-not(Test-Path -Path $Target)) {
Try {
New-Item -ItemType Directory -Path $Target | Write-Verbose
}
catch {
Write-Error $Error[0];
}
}
else {
Write-Verbose "$Target exists"
}
}
function Move-MyFiles {
[CmdletBinding()]
param (
[string]$Source,
[string]$Destination
)
[array]$FileList = Get-ChildItem $Source -File | Select-Object -ExpandProperty 'Name'
foreach ($file in $FileList) {
[string]$DestinationPath = Set-DestinationPath -FileName $file -Target $Destination
Create-DestinationPath -Target $DestinationPath
try {
Move-Item -Path (Join-Path -Path $Source -ChildPath $file) -Destination $DestinationPath | Write-Verbose
}
catch {
Write-Warning $Error[0]
}
}
}
Move-MyFiles -Source $SourceIn -Destination $DestinationIn
Here is something you might try. The number for the directory is grabbed from a regex match, "(\d+)\..*.pdf". When you are confident that the correct file copies will be made, remove the -WhatIf from the Copy-Item cmdlet.
I did not try to address the Write-Progress capability. Also, this will only copy .pdf files that begin with digits followed by a FULL STOP (period) character.
I do not fully understand the need for all of the Write-Host and Read-Host usage. It is not very PowerShell. pwshic
$SourceFolder = 'C:/src/t/copymaps'
$targetFolder = 'C:/src/t/copymaps/base'
$i = 0
$numFiles = (
Get-ChildItem -File -Path $SourceFolder -Filter "*.pdf" |
Where-Object -FilterScript { $_.Name -match "(\d+)\..*.pdf" } |
Measure-Object).Count
clear-host;
Write-Host 'This script will copy ' $numFiles ' files from ' $SourceFolder ' to ' $targetFolder
Read-host -prompt 'Press enter to start copying the files'
Get-ChildItem -File -Path $SourceFolder -Filter "*.pdf" |
Where-Object -FilterScript { $_.Name -match "(\d+)\..*.pdf" } |
ForEach-Object {
$NumberDir = Join-Path -Path $targetFolder -ChildPath $Matches[1]
$NumberDir = Join-Path -Path $NumberDir -ChildPath 'Repository'
if (-not (Test-Path $NumberDir)) {
New-Item -ItemType Directory -Path $NumberDir
}
Copy-Item -Path $_.FullName -Destination $NumberDir -Whatif
$i++
}
Write-Host 'Total number of files read from directory '$SourceFolder ' is ' $numFiles
Write-Host 'Total number of files that was copied to '$targetFolder ' is ' $i
Read-host -prompt "Press enter to complete..."
clear-host;

Using powershell to copy new and updated files

I am a complete novice when it comes to powershell, but I have been given a script that I need to improve so that we can move updated or new files from one server to another. I've managed to get to grips with the current script but am struggling to find the right cmdlets and paramters to achieve the desired behaviour.
The script I have is successful at detecting changed files and moving them to a location ready for transfer to another server, but it doesn't detect any new files.
Can anyone give me some guidance as to how I would be able to achieve both behaviours?
$CurrentLocation = "C:\current"
$PreviousLocation = "C:\prev"
$DeltaLocation = "C:\delta"
$source = #{}
#
# Get the Current Location file information
#
Get-ChildItem -recurse $CurrentLocation | Foreach-Object {
if ($_.PSIsContainer) { return }
$source.Add($_.FullName.Replace($CurrentLocation, ""), $_.LastWriteTime.ToString())
}
Write-Host "Content of Source"
$source
$changesDelta = #{}
$changesPrevious = #{}
#
# Get the Previous Directory contents and compare the dates against the Current Directory contents
#
Get-ChildItem -recurse $PreviousLocation | Foreach-Object {
if ($_.PSIsContainer) { return }
$File = $_.FullName.Replace($PreviousLocation, "")
if ($source.ContainsKey($File)) {
if ($source.Get_Item($File) -ne $_.LastWriteTime.ToString()) {
$changesDelta.Add($CurrentLocation+$File, $DeltaLocation+$File)
$changesPrevious.Add($CurrentLocation+$File, $PreviousLocation+$File)
}
}
}
Write-Host "Content of changesDelta:"
$changesDelta
Write-Host "Content of changesPrevious:"
$changesPrevious
#
# Copy the files into a temporary directory
#
foreach ($key in $changesDelta.Keys) {
New-Item -ItemType File -Path $changesDelta.Get_Item($key) -Force
Copy-Item $key $changesDelta.Get_Item($key) -Force
}
Write-Host $changesDelta.Count "Files copied to" $DeltaLocation
#
# Copy the files into the Previous Location to match the Current Location
#
foreach ($key in $changesPrevious.Keys) {
Copy-Item $key $changesDelta.Get_Item($key) -Force
}
Here's a simplified approach to your needs. One thing to note is that some of the constructs I've used require PSv3+. This does not copy directory structure, just the files. Additionally, it compares the basenames (ignoring extensions) which may or may not do what you want. It can be expanded to include extensions by using .Name instead of .BaseName
#requires -Version 3
$CurrentLocation = 'C:\current'
$PreviousLocation = 'C:\prev'
$DeltaLocation = 'C:\delta'
$Current = Get-ChildItem -LiteralPath $CurrentLocation -Recurse -File
$Previous = Get-ChildItem -LiteralPath $PreviousLocation -Recurse -File
ForEach ($File in $Current)
{
If ($File.BaseName -in $Previous.BaseName)
{
If ($File.LastWriteTime -gt ($Previous | Where-Object { $_.BaseName -eq $File.BaseName }).LastWriteTime)
{
Write-Output "File has been updated: $($File.FullName)"
Copy-Item -LiteralPath $File.FullName -Destination $DeltaLocation
}
}
Else
{
Write-Output "New file detected: $($File.FullName)"
Copy-Item -LiteralPath $File.FullName -Destination $DeltaLocation
}
}
Copy-Item -Path "$DeltaLocation\*" -Destination $PreviousLocation -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
}
}