user3391373
user3391373

Reputation: 55

Power shell cannot remove item

I currently hit the wall with this email script. The problem is the third line where I need to delete logs older than one day.

$Path = "D:\Log\delete_trace.log"
Write-Output "before delete"> $Path 
**(Get-ChildItem "D:\trace" -Recurse | 
    Select-Object -ExpandProperty Fullname) >> $Path  
(Get-ChildItem "D:\trace" -Recurse | 
  Where-Object {$_.LastWriteTime -ge (Get-Date).addDays(-1)} |
    Remove-Item -Force) >> $Path**
Write-Output "preserved"  >> $Path
(Get-ChildItem "D:\trace" -Recurse | 
    Select-Object -ExpandProperty Fullname) >> $Path

$body =  Get-Content $Path |%{ "$_`n" }|Out-String

Send-MailMessage -from [email protected] -to "[email protected]" -subject "Trace logs delete status"  -Body $body  -smtpServer smtp.company.com

So when I execute the third line I get this error:

Remove-Item : Cannot remove item D:\trace\509436.trc: The process cannot access the file 'D:\trace\509436.trc' because it is being used by another process.

I'm aware that the problem is in the first file which is currently logging, but why is the script trying to delete the first file, although I put (Get-Date).addDays(-1) ?

How to bypass this ?

Thank you

Upvotes: 0

Views: 454

Answers (2)

Theo
Theo

Reputation: 61068

CFou is correct about using -lt to get files older than the reference date.

Also, I would set that reference date to midnight using (Get-Date).AddDays(-1).Date

Your code uses Get-ChildItem three times, for every step of the way, but you could suffice with just one call.

Something like this:

$Path = "D:\Log\delete_trace.log"
$refDate = (Get-Date).AddDays(-1).Date   # set to midnight

# create the log file
Set-Content -Path $Path -Value "before delete"
$files = Get-ChildItem "D:\trace" -File -Recurse
# add all files found to the file
$files.Fullname | Add-Content -Path $Path  

# filter out files older than the reference date (-lt, not -ge)
$removed = @($files | Where-Object {$_.LastWriteTime -lt $refDate})
if ($removed.Count) {
    # if you have any, remove these files and add their fullnames to the log
    Add-Content -Path $Path -Value "`r`ndeleted files"
    $removed.FullName | Add-Content -Path $Path  
    $removed | Remove-Item -Force
}

# filter out the complete file list to only keep the files that were not removed
$preserved = @($files.FullName | Where-Object { $removed.FullName -notcontains $_ })
if ($preserved.Count) {
    # if you have any, add their fullnames to the log
    Add-Content -Path $Path -Value "`r`npreserved files"
    $preserved | Add-Content $preserved
}

# send the email. Best thing is to build a Hashtable for all parameters and use that (called Splatting)
$mailParams = @{
    To         = '[email protected]' 
    From       = '[email protected]'
    Subject    = 'Trace logs delete status'
    Body       = Get-Content -Path $Path -Raw
    SmtpServer = 'smtp.company.com'
    # maybe more parameters go here..
    # BodyAsHtml = $true
}
Send-MailMessage @mailParams

If you are sending the email as HTML with extra parameter BodyAsHtml = $true, you need to set the body to

Body = (Get-Content -Path $Path) -join '<br />'

1. Splatting makes code better readable and maintainable on cmdlets that use a lot of parameters. 2. If you want the output on console screen aswell you can add switch PassThru to both the Set-Content and the Add-Content cmdlets.

Upvotes: 1

CFou
CFou

Reputation: 1180

This will remove logs younger than one day

Get-ChildItem "D:\trace" -Recurse | 
  Where-Object {$_.LastWriteTime -ge (Get-Date).addDays(-1)} |
    Remove-Item -Force

if you want to remove logs older than one day

Get-ChildItem "D:\trace" -Recurse | 
  Where-Object {$_.LastWriteTime -lt (Get-Date).addDays(-1)} |
    Remove-Item -Force

However, @Adis1102 is right when he says you will not have your delete log appended, Tee-Object cmdlet is useful for this :

Get-ChildItem "D:\trace" -Recurse | 
   Where-Object {$_.LastWriteTime -lt (Get-Date).addDays(-1)} | Tee $Path -Append | 
     Remove-Item -Force

Upvotes: 3

Related Questions