Issue with Copying files from and too within certain dates in Powershell - powershell

I am new to power shell, I am trying to copy files from one location to another between specific dates.
I have an issue with the dates part it seems to be copying all the files regardless of the dates, any idea why?
$StartDate = (Get-date).Addyears(-2)
$EndDate = (Get-date).Adddays(-2)
$src = "C:\Sites\T\Test01"
$dst = "C:\Customer\"
Get-ChildItem $src -exclude "Aeromark" -Recurse | Copy-Item -Destination $dst -Force |
Where-Object {($_.LastWriteTime.Date -ge $StartDate.Date) -and ($_.LastWriteTime.Date -le $EndDate.Date)}

Where-Object needs to go before Copy-Item in your particular case. The Copy-Item command is being called before Where-Object excludes the files based on date.
Here is your code re-arranged:
Get-ChildItem $src -exclude "Aeromark" -Recurse |
Where-Object {($_.LastWriteTime.Date -ge $StartDate.Date) -and ($_.LastWriteTime.Date -le $EndDate.Date)} |
Copy-Item -Destination $dst -Force

Related

I'm writing my first powershell script to remove old TMP/LOG files on exchange

I'm writing a custom script to keep our Exchange servers clean. It consists of several parts.
The last part is to clean TEMP folders, and it's working with no problems.
The first part is where my problem is. I want to select all .BAK .TMP and .XML files and delete them if they are over 3 days old, and select and delete all .log files if they are over 30 days old. But no files are being selected.
$Path ="$env:SystemDrive\Program Files (x86)\GFI\MailEssentials\EmailSecurity\DebugLogs\", "$env:SystemDrive\Program Files (x86)\GFI\MailEssentials\AntiSpam\DebugLogs\", "$env:SystemDrive\inetpub\logs", "$env:windir\System32\LogFiles"
# How long do you want to keep files by default?
$Daysback = "3"
# How long do you want to keep .log files? (Recommended 30 days at least)
$DaysbackLog = "30"
$DatetoDelete = (Get-Date).AddDays(-$Daysback)
$DatetoDeleteLog = (Get-Date).AddDays(-$DaysbackLog)
Get-ChildItem $Path -Recurse -Hidden | Where-Object {($_.extension -like ".log" -and $_.LastWriteTime -lt $DatetoDeleteLog)} | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
Get-ChildItem $Path -Recurse -Hidden | Where-Object {($_.extension -like ".bak", "tmp", "xml" -and $_.LastWriteTime -lt $DatetoDelete)} | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
# The following lines clears temp folder and empty folders in the temp folder.
Get-ChildItem "$env:windir\Temp", "$env:TEMP" -recurse | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
Get-ChildItem "$env:windir\Temp", "$env:TEMP" -recurse | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Where {$_.PSIsContainer -and #(Get-ChildItem -LiteralPath:$_.fullname).Count -eq 0} | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
There are a few ways to do this, but much of it is based on personal preference and/or performance. The latter of which is not likely to be a big design factor here.
$Path = #(
"$env:SystemDrive\Program Files (x86)\GFI\MailEssentials\EmailSecurity\DebugLogs\"
"$env:SystemDrive\Program Files (x86)\GFI\MailEssentials\AntiSpam\DebugLogs\"
"$env:SystemDrive\inetpub\logs"
"$env:windir\System32\LogFiles"
)
# Extensions
$Extensions = "*.bak", "*.tmp", "*.xml"
# Temp folders to clean up
$Temps = "$env:windir\Temp", "$env:TEMP"
# How long do you want to keep files by default?
$Daysback = "3"
# How long do you want to keep .log files? (Recommended 30 days at least)
$DaysbackLog = "30"
$DatetoDelete = (Get-Date).AddDays(-$Daysback)
$DatetoDeleteLog = (Get-Date).AddDays(-$DaysbackLog)
Get-ChildItem $Path -Filter "*.log" -Recurse -Hidden |
Where-Object { $_.LastWriteTime -le $DatetoDeleteLog } |
Remove-Item -Force -ErrorAction SilentlyContinue -WhatIf
# > Move filtering left, which works because you are only looking for a single
# extension.
# > Change to -le to accommodate edge case where $_.LastWriteTime is right on
# the boundary.
$Extensions |
ForEach-Object{
Get-ChildItem $Path -Filter $_ -Recurse -Hidden
} |
Where-Object { $_.LastWriteTime -le $DatetoDelete } |
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
# Set up extensions as an array of wild card filters.
# -Filter is much faster than -Include which may be another alternative approach
Get-ChildItem $Temps -File -Recurse |
Where-Object { $_.LastWriteTime -le $DatetoDelete } |
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
Get-ChildItem $Temps -Directory -Recurse |
Where-Object { !$_.GetFileSystemInfos() } |
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
I haven't tested any of the refactor. However, the approach is to simply rerun the Get-ChildItem cmdlet for each needed scenario. In my experience that's faster than trying to use the -Include parameter to grab all the extensions in 1 shot, while still be faster and easier to read than adding to a Where{} clause to filter on extension.
In the part for clearing the temp folders. I use the .Net Method .GetFileSystemInfos() on the [System.IO.DirectoryInfo] objects returned from Get-ChildItem. The method returns an array of all child objects, so if it's null we know the folder is empty. That sounds complicated, but as you can see it significantly shrinks the code and will likely perform better. I use the -File & -Directory parameters respectively to make sure to make sure I've got the right object types.
This is a little more advanced, but another way I played with to clean up the temp folders is to use a ForEach-Object loop with 2 process blocks.
$Temps |
ForEach-Object -Process {
# 1st process block get Empty directories:
Get-ChildItem -Directory -Recurse |
Where-Object{ !$_.GetFileSystemInfos() }
}, {
# 2nd process block get files older than the boundary date.
Get-ChildItem -File -Recurse |
Where-Object { $_.LastWriteTime -le $DatetoDelete }
} |
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -WhatIf
Again untested, and I'm not sure how this will preform. Nevertheless, since I developed it thought I'd share.
Note: the -Process argument is necessary so that ForEach-Object assigns both block to process.
Check out ForEach-Object with Multiple Script Blocks for more information.

Powershell compress files older than X days from folder path by keeping folder structure (folder + sub-folders) and also exclude a few sub-folders

I'm pretty new to Powershell in general, I've come across some partial solutions, but I can't find the right fit.
Ideally I would like to Archive (Zip) with Powershell but only files of a certain age (x days/months), but I would prefer keeping the folder structure and also add exclusions.
Here's what I've been trying to use (without success):
$inputFolder = "C:\Temp\Test"
$excludeFolders = #("\subfolderToKeep")
$ouputFileName="C:\Temp\archive.zip"
$Daysback = "-5"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
$tempFolder = [System.IO.Path]::GetTempFileName()
Remove-Item $tempFolder -Force
New-Item -Type Directory -Path $tempFolder -Force
$exclude =#()
$excludeFolders | ForEach-Object {
$exclude+=(Join-Path $inputFolder $_)
Get-ChildItem (Join-Path $inputFolder $_) -Recurse |
ForEach-Object{$exclude+=$_.FullName}}
Get-ChildItem $inputFolder -Recurse | Where-Object { $_.FullName -notin $exclude -and $_.LastWriteTime -lt $DatetoDelete } |
Copy-Item -Destination {Join-Path $tempFolder $_.FullName.Substring($inputFolder.length)}
Get-ChildItem $tempFolder |
Compress-Archive -DestinationPath $ouputFileName -Update
The current setup would work without the date filtering:
-and $_.LastWriteTime -lt $DatetoDelete

Delete old files after X days by default with exception on certain dirs [Powershell]

I'm trying to fix the following scenario:
I have directory which has multiple subdirectories and files where I need to set something like retention policy, by default I would set to have files no older than 365 days where there are some special directories where I would like to keep for a different period of time other than my default value. These directories are specified in a txt file with the following syntax
Content of Drive:\Path\to\special_dirs.txt
D:\Path\to\vendor1 -396
D:\Path\to\vendor2 -45
This is what I have come up so far (It is working on the special directories only, the next part where I want to proceed with the rest does not work):
# Script to remove old files from Archive: D:\Path\to
# Declaring variables to be used
$controlfile = "Drive:\Path\to\list\special_dirs.txt"
$dir = "D:\Path\to"
$default_days = "-365"
$excluded_dirs = Get-Content $controlfile | Foreach-Object {$_.Split()[0]}
foreach ($line in Get-Content $controlfile) {
$split = $line.split(" ")
$file_path = $split[0]
$max_days = $split[1]
Get-ChildItem $file_path -Include *.* -File -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays($max_days))} | Remove-Item -Force -Recurse -Verbose -WhatIf
}
# Removing everything else older than 365 days old
Get-ChildItem -Path $dir -Include *.* -File -Recurse -Directory -Exclude $excluded_dirs | Where-Object {($_.LastWriteTime -lt $curr_date.AddDays($default_days))} | Remove-Item -Force -Recurse -Verbose -WhatIf
I'm not looking to remove directories even if they are empty, I just want to remove files, the last part of the script just deletes everything older than 365 day where there is a directory that I would like to keep 30 days more than the default period of time, any ideas on how to get this done?
I used the file list so that I can keep adding directories to vendors where I can keep longer than or even less than the default days.
What about something like this?..
$30DayDirs = #('C:\Temp\Test1\','C:\Temp\Test2\')
$60DayDirs = #('C:\Temp\Test3\')
$365DayDirs = #('C:\Temp\Test4\')
foreach($file in $30DayDirs){
$file = Get-ChildItem $30DayDirs -Recurse |where LastWriteTime -LT (Get-Date).AddDays(-30)
Remove-Item $file.FullName -Force -Recurse
}
foreach($file in $60DayDirs){
$file = Get-ChildItem $60DayDirs -Recurse |where LastWriteTime -LT (Get-Date).AddDays(-60)
Remove-Item $file.FullName -Force -Recurse
}
foreach($file in $365DayDirs){
$file = Get-ChildItem $365DayDirs -Recurse |where LastWriteTime -LT (Get-Date).AddDays(-365)
Remove-Item $file.FullName -Force -Recurse
}
I have fixed my issue with the following:
# Script to remove old files from DFS Archive: D:\Path\to
# Declaring variables to be used
$controlfile = "Drive:\Path\to\list\special_dirs.txt"
$dir = "D:\Path\to"
$default_days = "-365"
$excluded_dirs = Get-Content $controlfile | Foreach-Object {$_.Split()[0]}
# Removing old files from special directories first
cd $dir
foreach ($line in Get-Content $controlfile) {
$split = $line.split(" ")
$file_path = $split[0]
$max_days = $split[1]
Get-ChildItem $file_path -Include *.* -File -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays($max_days))} | Remove-Item -Force -Recurse -Verbose
}
# Removing everything else older than 365 days old
Get-ChildItem $dir -Directory -Exclude $excluded_dirs | Get-ChildItem -Include *.* -File -Recurse | Where-Object {($_.LastWriteTime -lt (Get-Date).AddDays($default_days))} | Remove-Item -Force -Recurse -Verbose
And I have modified my special_dirs.txt file to:
vendor1 -396
vendor2 -45

Move files with specific date using Powershell Get-ChildItem

Need some help with a powershell script.
I need to move files by a specific last modified date with similar names.
Here is the script I tried running and it just hangs...
$SourceFolder = "C:\documents\testing123.txt"
$targetFolder = "D:\documents"
Get-ChildItem -Path $SourceFolder -Filter E0100* | where-object {$_.LastWriteTime -eq ("08/01/2015") | move-item -destination $targetFolder
Since, LastWriteTime is a DateTime the -ge in comparing an exact time. Here is an example that copies using a date range that I believe you desire.
$SourceFolder = "C:\documents\testing123.txt"
$targetFolder = "D:\documents"
$startTime =[DateTime]"08/01/2015"
$endTime = $startTime.AddDays(1)
Get-ChildItem -Path $SourceFolder -Filter E0100* |
Where-Object {$_.LastWriteTime -ge $startTime -and $_.LastWriteTime -lt $endTime} |
Move-Item -destination $targetFolder
As others have mentioned, the source folder path seems incorrect.
Here is a robocopy version of the script I tried (date, paths, and filter have been changed)
$SourceFolder = "D:\test"
$targetFolder = "D:\test2"
$startTime =[DateTime]"01/05/2017"
$endTime = $startTime.AddDays(1)
$files = #()
Get-ChildItem -Path $SourceFolder -Filter * |
Where-Object {$_.LastWriteTime -ge $startTime -and $_.LastWriteTime -lt $endTime -and $_.Attributes -ne 'Directory'} |
ForEach-Object { $files += $_.Name}
if($files.Count -gt 0)
{
Write-Verbose "running robocopy $SourceFolder $targetFolder $files /mov" -Verbose
robocopy $SourceFolder $targetFolder $files /mov
}
This is a simple two-line PowerShell that will get move your files by date and file type. You can change the Move-Item to Copy-Item if you do not want to move them.
$Now=Get-Date
Get-ChildItem E:\scripts\logs\*.txt | Where-Object { $_.LastWriteTime -lt $Now.AddDays(-7) } | Move-Item -Destination E:\scripts\logs\Archive\7Days

Delete files older than 15 days using PowerShell

I would like to delete only the files that were created more than 15 days ago in a particular folder. How could I do this using PowerShell?
The given answers will only delete files (which admittedly is what is in the title of this post), but here's some code that will first delete all of the files older than 15 days, and then recursively delete any empty directories that may have been left behind. My code also uses the -Force option to delete hidden and read-only files as well. Also, I chose to not use aliases as the OP is new to PowerShell and may not understand what gci, ?, %, etc. are.
$limit = (Get-Date).AddDays(-15)
$path = "C:\Some\Path"
# Delete files older than the $limit.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force
# Delete any empty directories left behind after deleting the old files.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse
And of course if you want to see what files/folders will be deleted before actually deleting them, you can just add the -WhatIf switch to the Remove-Item cmdlet call at the end of both lines.
If you only want to delete files that haven't been updated in 15 days, vs. created 15 days ago, then you can use $_.LastWriteTime instead of $_.CreationTime.
The code shown here is PowerShell v2.0 compatible, but I also show this code and the faster PowerShell v3.0 code as handy reusable functions on my blog.
just simply (PowerShell V5)
Get-ChildItem "C:\temp" -Recurse -File | Where CreationTime -lt (Get-Date).AddDays(-15) | Remove-Item -Force
Another way is to subtract 15 days from the current date and compare CreationTime against that value:
$root = 'C:\root\folder'
$limit = (Get-Date).AddDays(-15)
Get-ChildItem $root -Recurse | ? {
-not $_.PSIsContainer -and $_.CreationTime -lt $limit
} | Remove-Item
Basically, you iterate over files under the given path, subtract the CreationTime of each file found from the current time, and compare against the Days property of the result. The -WhatIf switch will tell you what will happen without actually deleting the files (which files will be deleted), remove the switch to actually delete the files:
$old = 15
$now = Get-Date
Get-ChildItem $path -Recurse |
Where-Object {-not $_.PSIsContainer -and $now.Subtract($_.CreationTime).Days -gt $old } |
Remove-Item -WhatIf
Try this:
dir C:\PURGE -recurse |
where { ((get-date)-$_.creationTime).days -gt 15 } |
remove-item -force
Esperento57's script doesn't work in older PowerShell versions. This example does:
Get-ChildItem -Path "C:\temp" -Recurse -force -ErrorAction SilentlyContinue | where {($_.LastwriteTime -lt (Get-Date).AddDays(-15) ) -and (! $_.PSIsContainer)} | select name| Remove-Item -Verbose -Force -Recurse -ErrorAction SilentlyContinue
If you are having problems with the above examples on a Windows 10 box, try replacing .CreationTime with .LastwriteTime. This worked for me.
dir C:\locationOfFiles -ErrorAction SilentlyContinue | Where { ((Get-Date)-$_.LastWriteTime).days -gt 15 } | Remove-Item -Force
Another alternative (15. gets typed to [timespan] automatically):
ls -file | where { (get-date) - $_.creationtime -gt 15. } | Remove-Item -Verbose
#----- Define parameters -----#
#----- Get current date ----#
$Now = Get-Date
$Days = "15" #----- define amount of days ----#
$Targetfolder = "C:\Logs" #----- define folder where files are located ----#
$Extension = "*.log" #----- define extension ----#
$Lastwrite = $Now.AddDays(-$Days)
#----- Get files based on lastwrite filter and specified folder ---#
$Files = Get-Childitem $Targetfolder -include $Extension -Recurse | where {$_.LastwriteTime -le "$Lastwrite"}
foreach ($File in $Files)
{
if ($File -ne $Null)
{
write-host "Deleting File $File" backgroundcolor "DarkRed"
Remove-item $File.Fullname | out-null
}
else {
write-host "No more files to delete" -forgroundcolor "Green"
}
}
$limit = (Get-Date).AddDays(-15)
$path = "C:\Some\Path"
# Delete files older than the $limit.
Get-ChildItem -Path $path -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force -Recurse
This will delete old folders and it content.
The following code will delete files older than 15 days in a folder.
$Path = 'C:\Temp'
$Daysback = "-15"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
Get-ChildItem $Path -Recurse | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Remove-Item