Powershell Cleanup script. Excluded folder not being excluded - powershell

I wrote a simple script that will run as a scheduled task every weekend. This script cleans up files older than # days and you can give the name of a folder for exclusion as a parameter. This folder should not be cleaned up by the script. But somehow the script still deletes some files from the excluded folder. But in a strange way no files matching the conditions of the parameter.
For example I run the script to delete files older than 15 days and exclude the folder NOCLEANUP. but some files still get deleted from that folder, but there are still files older than 15 days in the NOCLEANUP folder.
Code below
Thanks in advance and apologies for the dirty code. Still new to PS.
Function CleanDir ($dir, $days, $exclude, $logpath)
{
$Limit = (Get-Date).AddDays(-$days)
$Path = $dir
#Folder to exclude
$ToExclude = $exclude
#Log location
$Log= $logpath
$Testpath = Test-Path -PathType Container -Path $Log
if ($Testpath -ne $true)
{
New-Item -ItemType Directory -Force -Path $Log
}
#Logs deleted files
cd $Log
Get-ChildItem -Path $Path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.LastwriteTime -lt $Limit } | Where-Object { $_.fullname -notmatch $ToExclude} | Where-Object { $_.fullname -notmatch '$RECYCLE.BIN'} | Out-File -FilePath CLEANUPLOG.TXT
# Delete files older than the $Limit.
Get-ChildItem -Path $Path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.LastwriteTime -lt $Limit } | Where-Object { $_.fullname -notlike $ToExclude} | Remove-Item -Force -Recurse
#Goes into every folder separately and deletes all empty subdirectorys without deleting the root folders.
$Folder = Get-ChildItem -Path $Path -Directory
$Folder.fullname | ForEach-Object
{
Get-ChildItem -Path $_ -Recurse -Force | Where-Object {$_.PSIsContainer -eq $True} | Where-Object {$_.GetFiles().Count -eq 0} | Remove-Item -Force -Recurse
}
}

Related

copy newer files without keeping folders

I have a folder with a number of subfolders containing files and want to copy all files to the root folder but only overwrite if newer.
In powershell I can do -
Get-ChildItem D:\VaM\Custom\Atom\Person\Morphs\temp2\female -Recurse -file | Copy-Item -Destination D:\VaM\Custom\Atom\Person\Morphs\female
But this will overwrite all files, I only want to overwrite files if the copied file is newer.
robocopy can overwrite only older this but keeps the folder structure.
Try this
$root = 'D:\VaM\Custom\Atom\Person\Morphs\temp2\female'
[bool]$Delete = $false
Get-ChildItem $root -Recurse -File |
Where-Object {$_.DirectoryName -ne $root } | # Do not touch files already seated in root
ForEach-Object {
$rootNameBrother = Get-Item "$root\$($_.Name)" -ea 0
if($rootNameBrother -and $rootNameBrother.LastWriteTime -lt $_.LastWriteTime) {
# RootFile with same name exists and is Older - Copy and override
Copy-Item -Path $_.FullName -Destination $rootNameBrother.FullName -Force
}
elseif ($rootNameBrother -and $rootNameBrother.LastWriteTime -ge $_.LastWriteTime) {
# RootFile with same name exists and is Newer or same Age
# Delete non root File if allowed
if($Delete) { Remove-Item $_.FullName -Force }
}
}
Set...
$Delete = $true
...if you wish to delete non root files that could not be copied because there already was a file with the same name and greater modiefydate in root.
You also can set the
$VerbosePreference = "Continue"
$WhatIfPreference = "Continue"
variables, just to be safe when you execute the script for the first time.
If you wish to delete all empty subfolder, you can run this:
$allFolders =`
Get-ChildItem $root -Recurse -Directory |
ForEach-Object {
# Add now Depth Script Property
$_ | Add-Member -PassThru -Force -MemberType ScriptProperty -Name Depth -Value {
# Get Depth of folder by looping through each letter and counting the backshlashes
(0..($this.FullName.Length - 1) | ForEach {$this.FullName.Substring($_,1)} | Where-Object {$_ -eq "\"}).Count
}
}
# Sort all Folder by new Depth Property annd Loop throught
$allFolders | Sort -Property Depth -Descending |
ForEach-Object {
# if .GetFileSystemInfos() method return null, the folder is empty
if($_.GetFileSystemInfos().Count -eq 0) {
Remove-Item $_.FullName -Force # Remove Folder
}
}
You can do it like this:
$source = 'D:\VaM\Custom\Atom\Person\Morphs\temp2\female'
$destination = 'D:\VaM\Custom\Atom\Person\Morphs\female'
Get-ChildItem -Path $source -Recurse -File | ForEach-Object {
# try and get the existing file in the destination folder
$destFile = Get-Item -Path (Join-Path -Path $destination -ChildPath $_.Name) -ErrorAction SilentlyContinue
if (!$destFile -or $_.LastWriteTime -gt $destFile.LastWriteTime) {
# copy the file if it either did not exist in the destination or if this file is newer
Write-Host "Copying file $($_.Name)"
$_ | Copy-Item -Destination $destination -Force
}
}
I ended up doing this:
Get-ChildItem G:\VaM\Custom\Atom\Person\Morphs\temp2\ -Recurse |
Where-Object { $_.PSIsContainer -eq $true } |
Foreach-Object { robocopy $_.FullName G:\VaM\Custom\Atom\Person\Morphs\female /xo /ndl /np /mt /nfl}
it runs through the directory structure and copys the contents of each directory to the destination but only overwrites older files.

Powershell command to delete subfolders without deleting the root

I'm having problems to create a PS command that allows me to delete several subfolders without deleting the roof folder.
I.E:
C:\Test has many subfolders:
C:\Test\Item1
C:\Test\Item2
C:\Test\Item3
And the folders Item1, Item2 and Item3 have many subfolders and files.
I would like to create a PS that would allow me to delete all the empty subfolders inside Item1, Item2 and Item3 without deleting Item1, Item2 and Item3 folders. It is possible that any of the Item folders is empty, but I don't want to delete them, just the empty content of each folder.
This is just an example, I have a have around 300 Item folders inside Test.
I usually would use this:
$path="C:\TEST"
do {
$dir = gci $path -directory -recurse | Where { (gci $_.fullName).count -eq 0 } | select -expandproperty FullName
$dir | Foreach-Object { Remove-Item $_ }
} while ($dir.count -gt 0)
But this deletes the folder root folder (Item1, Item2 or Item3) if they are empty.
Thanks in advance.
So you are looking to delete All Items inside Empty Subfolders or all items in General?
This will delete all Folders or Items in General inside of the Directory "C:\abc\"
$path = "C:\abc\"
Get-ChildItem -Path $path -Recurse| Foreach-object {Remove-item -Recurse -path $_.FullName }
This will delete all Folders that dont have any items in them.
$path = "C:\abc\"
Get-ChildItem -Path $path -Recurse | Where-Object {(Get-ChildItem $_.FullName).Count -eq 0} |Foreach-object {Remove-item -Recurse -path $_.FullName }
ยด
This will look inside "C:\abc\" Get all the children and delete all empty Directories inside the Children in your example this would be Item1,Item2,...
$Path = "C:\abc\"
$itemFolders= Get-ChildItem -Path $Path
$itemFolders| Foreach-Object {
Get-ChildItem -Path $_.FullName |
Where-Object {(Get-ChildItem $_.FullName).Count -eq 0} |
Foreach-object {Remove-item -Recurse -path $_.FullName }
}
Just a quick and dirty bit of Code as I dont have much time, hope I could be of help.
EDIT: Here is what i came up with, its not as performant as I'd like but it gets the job done and is fairly quick, try it out for yourself it worked for me - even threw in a couple of comments and output to clarify what's going on.
$Path="C:\abc\"
$itemFolders = Get-ChildItem $Path
#Get All Folders inside
$AllFolders = $itemFolders | Get-ChildItem -Recurse | Where-Object {$_.PSIsContainer} | Select -Property FullName
#First delete all files older than 30 days
$itemFolders | Get-ChildItem -Recurse -File | ForEach-Object{
$limit = (Get-Date).AddDays(-30)
if($_.LastWriteTime -lt $limit)
{
"{0} hasn't been modified in the last 30 days deleting it" -f $_.FullName
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue
}
}
#Check if there are files inside that are not containers
$AllFolders | ForEach-Object{
$files = Get-ChildItem -File -Recurse -Path $_.FullName
$directories = Get-ChildItem -Directory -Recurse -Path $_.FullName
#If There are any files inside the folder dont delete it.
if($files.Count -gt 0)
{
"Found {0} files inside {1} do not delete this" -f $files.Count, $_.FullName
}
#If There are no files and no directories inside delete it.
elseif($files.Count -eq 0 -and $directories.Count -eq 0)
{
"Empty Folder {0} deleting it" -f $_.FullName
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}
#If there are no files and empty directories inside delete it.
elseif($files.Count -eq 0 -and $directories.Count -gt 0)
{
"No Files but directories found in {0} since its recursive delete it" -f $_.FullName
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}
}

Deleting files in subfolders older than x days

I am trying to delete all files in subfolders of a given folder without deleting the subfolders themselves. I have tried various examples but they are not doing what I expect.
The basic structure of the file tree I am trying to negotiate is:
C:\Backups\Subfolder1
C:\Backups\Subfolder2
C:\Backups\Subfolder3
and I am using the following code:
$limit = (Get-Date).AddDays(-14)
$path = "C:\Backups"
Get-ChildItem -Path $path -Recurse -Force |
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } |
Remove-Item -WhatIf
I am finding that the files in the subdirectories are being ignored despite the -Recurse flag being used, although any files in the C:\Backups directory are included. If I remove the !$_.PSIsContainer clause the file in the subfolder is included but so are all of the directories.
Can anyone show me how to include the files in the subfolder while still ignoring the subfolders themselves?
If you are using powershell 3.0 you can simply use the -File switch:
$limit = (Get-Date).AddDays(-14)
$path = "C:\Backups"
Get-ChildItem -Path $path -File -Recurse | where { $_.LastWriteTime -lt $limit } | Remove-Item
The below code works for me. Are you on an older version of powershell?
$limit = (Get-Date).AddDays(-14)
$path = "C:\Users\nathan.cooper\Documents"
Get-ChildItem -Path $path -Recurse -Force |
where { (! $_.PSIsContainer) -and ($_.LastWriteTime -lt $limit) } |
Remove-Item -whatif
$limit = (Get-Date).AddDays(-14)
$files = Get-ChildItem -Path C:\Backups -Directory:$false -Recurse
$files | ForEach-Object -Process {
if($_.CreationTime -lt $limit)
{
Remove-Item $_.FullName -Force
}
}
The -Directory:$False parameter means you don't have to worry about deleting any directories because they won't be included in the array.

Powershell - delete old folders but not old files

I have the following code to keep on top of old folders which I no longer want to keep
Get-ChildItem -Path $path -Recurse -Force -EA SilentlyContinue|
Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } |
Remove-Item -Force -EA SilentlyContinue
Get-ChildItem -Path $path -Recurse -Force -EA SilentlyContinue|
Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path
$_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer })
-eq $null } | Remove-Item -Force -Recurse -EA SilentlyContinue
It deletes anything older than a certain number of days ($limit) including files and folders.
However, what I am after is ONLY deleting old folders and their contents.
For example, a day old folder may have file within that is a year old but I want to keep that folder and the old file. The code above keeps the folder but deletes the file. All I want to do is delete folders (and their contents) within the root that are older than the $limit else leave the other folders and content alone.
Thanks in advance.
Well look at this bit:
Get-ChildItem -Path $path -Recurse -Force -EA SilentlyContinue|
Where-Object { !$_.PSIsContainer -and $_.CreationTime -ge $limit } |
Remove-Item -Force -EA SilentlyContinue
It's basically saying "everything not a folder and older than specified is removed". So your first step is to remove that.
The second part is just deleting empty folders, you can keep it as-is or you could add to the Where statement to include the CreationTime:
Get-ChildItem -Path $path -Recurse -Force -EA SilentlyContinue|
Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit -and (Get-ChildItem -Path
$_.FullName -Recurse -Force | Where-Object { $_.CreationTime -lt $limit })
-eq $null } | Remove-Item -Force -Recurse -EA SilentlyContinue
The second Where statement returns a list of files and folders newer than $limit, and only deletes the folder if that is null.

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