Delete files which are not locked (in use) - powershell

I'm trying to delete all files (not folders) in %TEMP% which are older than 30 days. The problem is that some files are in use by a program so they can not be deleted. I tried to solve the problem as follow:
function IsFileLocked($filePath){
#write-host $filePath
Rename-Item $filePath $filePath -ErrorVariable errs -ErrorAction SilentlyContinue
$errs.Count
if ($errs.Count -ne 0)
{
return $true #File is locked
}
else
{
return $false #File is not locked
}
}
$Path= "$env:temp"
if ((Test-Path -Path $Path) -ieq $true)
{
$Daysback = '-30'
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
get-childitem $Path -recurse | Where-Object {$_.LastWriteTime -lt $DatetoDelete } |
Where-Object {$_.PSIsContainer -eq $False }| Where-Object {(IsFileLocked -filePath "($_)") -eq $false }# | remove-item -force #-WhatIf
}
The problem is that (IsFileLocked -filePath "($_)") -eq $false doesn't return any element.
Is it possible that get-childitem blocks the files, so that all of them are locked when I run get-childitem?
Any other ideas how to solve this problem?

How about just removing files older than 30 days and ignore the errors:
$old = (Get-Date).AddDays(-30)
Get-ChildItem $env:TEMP -Recurse |
Where-Object {!$_.PSIsContainer -and $_.LastWriteTime -lt $old } |
Remove-Item -Force -ErrorAction SilentlyContinue

Related

script for deleting all files except 1st and 15th seems not working

I have a script like this:
$Path = "D:\test"
$Daysback = -15
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
Get-ChildItem $Path -Recurse | Where-Object {
$_.LastWriteTime -lt $DatetoDelete -and
!($_.LastWriteTime.Day -eq 1) -and
!($_.LastWriteTime.Day -eq 15)
} | Remove-Item -Recurse -Confirm:$false -Force
The idea is to delete all files older than 15 days, but not 1st and 15th in the Month.
Then I put that script in Task Scheduler to run monthly.
But when I try and run it, I can see dates which are not 1st and 15th, when they should be removed.
Anyone catch a mistake here?
You have one too many -and(s). When checking the date you want to see if either day condition is true (-or) then negate that result thus enclosing those two tests in parens and then negating the result.
$Path = "D:\test"
$Daysback = -15
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
Get-ChildItem $Path -Recurse |
? { ($_.LastWriteTime -lt $DatetoDelete) -and
(-not (($_.LastWriteTime.Day -eq 1) -or ($_.LastWriteTime.Day -eq 15))} |
Remove-Item -Recurse -Confirm:$false -Force
HTH
This worked for me, thanks all for help
$Path = "D:\test"
$Daysback = -15
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
Get-ChildItem $Path -Recurse |
Where-Object { ($_.LastWriteTime -lt $DatetoDelete) -and -not (($_.LastWriteTime.Day -eq 1) -or ($_.LastWriteTime.Day -eq 15))}|
Remove-Item -Recurse -Confirm:$false -Force

Add timestamp to output log file before each object

I have a powershell script which deletes files and folders older than 180 days, and I would like to add date and time of deletion in the log file before each object. Is that possible?
$limit = (Get-Date).AddDays(-180)
$path = "D:\RAZMJENA DOKUMENATA"
# Delete files older than the $limit.
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force -Verbose 4>&1 | out-file d:\Delete_script\deleted_files_log.txt -append
# 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 -Verbose 4>&1 | out-file d:\Delete_script\deleted_files_log.txt -append
#Delete remaining empty folders older than 180 days.
Get-ChildItem -Path $path -Directory -Recurse | Where {$_.lastwritetime -lt (Get-Date).AddDays($limit) -and (gci $_.fullName).count -eq 0} | Remove-Item -Force -Verbose 4>&1 | out-file d:\Delete_script\deleted_files_log.txt -append
You can do this in you code with add foreachloop
Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force -Verbose 4>&1|foreach{($_.Message).Tostring()+" "+((Get-Date).DateTime).ToString()} | out-file d:\Delete_script\deleted_files_log.txt -append
Yes you can add the current date to every line. For the better understanding I would assign a temporary variable. You can do this with every line of code:
$tmp = Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force -Verbose 4>&1
$date = Get-Date -Format "MM/dd/yyyy HH:mm" #Format the Date
"$date --> $tmp" | out-file d:\Delete_script\deleted_files_log.txt -append #Append to logfile
Or even better, create a function that you can call everytime you want to log:
function logToFile($tmp){
$date = Get-Date -Format "MM/dd/yyyy HH:mm" #Format the Date
"$date --> $tmp" | out-file d:\Delete_script\deleted_files_log.txt -append
}
Then you can call it whenever you want:
$tmp = Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit } | Remove-Item -Force -Verbose 4>&1
logToFile $tmp
If you want to have another format of the date you can get more informations on this page:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-date?view=powershell-7

Deleting files with Powershell recursively

I got somehow a weird issue, I am trying to use a process to automate the deletion of files from a folder and also child folders, I am trying to delete only files older than 7 days.
My code works but it deletes files that are under 7 days when going recursively into child items. . .anyone could lend a hand here? I just need to delete in each folder/sub-folder the files older than 7 days.
Param (
[string]$Source = "C:\Users\Loredanes\Downloads\",
[string]$Days = "1"
)
$Files = Get-ChildItem $Source -Recurse | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -lt (get-date).addminutes(-$($Days)) }
$Files | Remove-Item -Force
if ($Files.count -gt 0)
{
$Folders = #()
ForEach ($Folder in (Get-ChildItem -Path $Source -Recurse -Directory))
{
$Folders += New-Object PSObject -Property #{
Object = $Folder
Depth = ($Folder.FullName.Split("\")).Count
}
}
$Folders = $Folders | Sort Depth -Descending
ForEach ($Folder in $Folders)
{
If ($Folder.Object.GetFileSystemInfos().Count -eq 0)
{
Write-Host "Removing Folder: $($Folder)"
Remove-Item -Path $Folder.Object.FullName -Force
}
}
}
else
{
Write-Host "No Empty folders found after removing files older than $($Days) days."
}
This should do what you want:
$source = 'D:\Test'
$days = 7
# Remove Files
Get-ChildItem $Source -Recurse | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -lt (get-date).AddDays(-$($days)) } | % { Remove-Item -Path $_.FullName -Force }
# Remove empty directories
Get-ChildItem $source -Recurse | Where-Object { $_.PSIsContainer -and $_.GetFiles("*.*").Count -le 0 } | % { Remove-Item -Path $_.FullName -Force }

Moves files into new subfolder for each year/month

I am trying to move all files under each subfolder into another folder with subfoldername_mmm_yyyy name.
Below codes only move all files in all sub folders into one folder with the name subfoldername_subfoldername_mmm_yyyy.
I know my for each loops are incorrect but I don't know how to fix them, would someone please help?
$curr_date = Get-Date
$folder_path = "C:\Logs\"
$file_type = "C:\Logs\*.log*"
$destination = "C:\Archive\"
# delete tmp files if existed
$deletefile = Get-ChildItem $destination -recurse -include *.7z.tmp -force | remove-item
# set min age of files
$max_days = "-1"
# determine how far back we go based on current date
$zip_date = $curr_date.AddDays($max_days)
Get-ChildItem -Path $folder_path | Where-Object { $_.Attributes -eq "Directory" } | foreach {
# obtain all subfolders
$servername = Get-ChildItem -Path $folder_path | Where-Object { $_.Attributes -eq "Directory" }
# move all files into servername_mmm_yyyy folder
Get-ChildItem $file_type -Recurse | Where-Object { ($_.LastWriteTime -lt $zip_date) -and ($_.psIsContainer -eq $false)}| foreach {
$x = $_.LastWriteTime.ToShortDateString()
$month_year = Get-Date $x -Format MMM_yyyy
$file_destination = ($destination) + ($servername) + "_" + ($month_year)
if (test-path $file_destination) {
move-item $_.fullname $file_destination
}
else {
new-item -ItemType directory -Path $file_destination
move-item $_.fullname $file_destination
}
}
}
Change:
Get-ChildItem $file_type -Recurse | Where-Object { ($_.LastWriteTime -lt $zip_date) -and ($_.psIsContainer -eq $false)} ...
to
Get-ChildItem $file_type -Recurse | Where-Object { ($_.LastWriteTime -lt $zip_date) -and ($_.psIsContainer -eq $false) -and $_.Name.EndsWith(".log")}
and that should get you just the files you want to target
I figured out my problem. Here is how I do it.
I just need to obtain the folder name of each file and build the destination path. Therefore, I only need one foreach loop.
# move all files into servername_mmm_yyyy folder
Get-ChildItem $file_path -Recurse | Where-Object { ($_.LastWriteTime -lt $zip_date) -and ($_.psIsContainer -eq $false)}| foreach {
$x = $_.LastWriteTime.ToShortDateString()
$month_year = Get-Date $x -Format MMM_yyyy
$servername = $_.Directory.Name
$file_destination = ($destination)+($servername)+"_"+($month_year)
if (test-path $file_destination){
copy-item $_.fullname $file_destination
}
else {
new-item -ItemType directory -Path $file_destination
copy-item $_.fullname $file_destination
}
}

Loop stops prematurely

I am writing an application that looks through a directory tree and reports if a folder is inactive based on last write time and read only attribute.
However my loop stops after like 7 iterations even though there are thousands of folders.
My code looks like:
function FolderInactive{
Param([string]$Path)
$date = (Get-Date).AddDays(-365)
$anyReadOnly = $false
Get-ChildItem $Path -File -ErrorAction SilentlyContinue | ForEach-Object {
if($_.LastWriteTime -ge $date){
$false
continue
}
if($_.IsReadOnly -eq $false){
$anyReadOnly = $true
}
}
$anyReadOnly
}
Get-ChildItem "some drive" -Recurse | where {$_.PSIsContainer} | Foreach-Object {
Write-Host $_.FullName
FolderInactive($_.FullName)
}
If I comment out the FolderInactive function call in the Foreach loop it prints all the folders, but with the function call it stops after a few iterations. What is happening?
You cannot use continue with the Foreach-Object cmdlet. Foreach-Object is a cmdlet, not a loop. You instead want to use the loop:
function FolderInactive{
Param([string]$Path)
$date = (Get-Date).AddDays(-365)
$anyReadOnly = $false
$items = Get-ChildItem $Path -File -ErrorAction SilentlyContinue
foreach($item in $items)
{
if($item.LastWriteTime -ge $date){
$false
continue
}
if($item.IsReadOnly -eq $false){
$anyReadOnly = $true
}
}
$anyReadOnly
}
This also can be simplified:
function FolderInactive
{
Param([string]$Path)
$date = (Get-Date).AddYears(-1)
$null -ne (Get-ChildItem $Path -File -ErrorAction SilentlyContinue |
Where {$_.LastWriteTime -ge $date -and $_.IsReadOnly})
}