Log deleted files to a text file - powershell

I want to know how to log the actions from this script to a text file because I don't know how to do it as the cmdlet Start-Transcript doesn't work for me and I wasn't able to find a solution on the Internet.
The problem is that the Where-Object cmdlet doesn't output anything captured by Get-ChildItem.
Does anybody has a good idea to solve this?
$limit = (Get-Date).AddDays(-30)
$path = Split-Path -Parent $MyInvocation.MyCommand.Definition
Get-ChildItem -Path $path -Recurse -Force | Where-Object {
!$_.PSIsContainer -and
$_.LastWriteTime -lt $limit
} | Remove-Item -Force
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

try something like this
$limit = (Get-Date).AddDays(-30)
$path =Split-Path -Parent $MyInvocation.MyCommand.Definition
Get-ChildItem $path -file -recurse -force | where LastWriteTime -lt $limit |
Tee-Object -FilePath "c:\temp\deleted.txt" -Append | Remove-Item
Get-ChildItem $path -directory |
where {(Get-ChildItem $_.FullName -file -Recurse | select -First 1) -eq $null} |
Tee-Object -FilePath "c:\temp\deleted.txt" -Append | Remove-Item

howdy error666,
you can use use a few different methods ...
Tee-Object = fork the stream to a file
-PipelineVariable = accumulate the info in a variable
use a loop = put a log-to-file step in it
put a ForEach-Object in the pipeline
that can both log your info and do the Remove-Item.
the loop is the easiest to understand. [grin] however, if you want to keep it in a pipeline, you could add a ForEach-Object where the Where-Object scriptblock is and put both the filter test and the various actions in that block.
take care,
lee

Related

Powershell delete all folders except one

I tried
Get-ChildItem -Path 'C:\temp' -Recurse Select Name | Where {$_ -notlike 'C:\temp\one*'} | sort length -Descending | Remove-Item -force
but it doesn't work
Get-ChildItem : A positional parameter cannot be found that accepts argument 'Name'
What's wrong
You were missing a |
Get-ChildItem -Path 'C:\temp' -Recurse | Select -ExpandProperty FullName | Where {$_ -notlike 'C:\temp\one*'} | Remove-Item -force
Try this with -Exclude (And why sort when deleting files?)
Get-ChildItem -Path 'C:\temp' -Recurse -Exclude 'C:\temp\one*' | Remove-Item -force
Use the function below:
Function Delete-Except
{
$path = ""
$exceptions = #(
#Enter files/folders to omit#
)
try:
Get-ChildItem $source -Exclude $exceptions| Remove-Item $_ -Force -Recurse
catch:
Write-Host "Delete operation failed." - Foregroundcolor Red
Pause
}

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

How do I print out the results of my delete script in Powershell

I'm trying to find a way to get my script to print out a log file of what files are actually being deleted. Does anyone know how I could go about doing this? Here is my screen I would like to add that onto.
Where-Object { -not $_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } |
Remove-Item -Force
Unfortunately, the Remove-Item cmdlet doesn't support the -Passthru parameter, which might make this easier. However, you could do this:
Where-Object { -not $_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } |
Tee-Object -FilePath .\Log.txt |
Remove-Item -Force
But that's a bit ugly because it outputs the directory listing from Get-ChildItem. You could do this instead to capture just the paths:
Where-Object { -not $_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } |
Select-Object -ExpandProperty FullName |
Tee-Object -FilePath .\Log.txt |
Remove-Item -Force
Also, note that if you're using PowerShell v3.0 or later, the Get-ChildItem cmdlet supports the -File and -Directory parameters, so you don't need to do the whole -not $_.PsIsContainer stuff.
The overall easiest way if you just need a log would be to use a Transcript and Verbose Output.
your script would look like this, make sure you pay attention to the addition of -Verbose to your command.
Start-Transcript C:\Logs\Remove.txt
Some-Command | Where-Object { -not $_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } | Remove-Item -Force -Verbose
Stop-Transcript
then the C:\Logs\Remove.txt file will have a message like this for each removed file:
VERBOSE: Performing the operation "Remove File" on target "H:\dns.csv".
You would need a loop:
Get-ChildItem -Path $Targets |
Where-Object { -not $_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } |
ForEach-Object {
$_ | Remove-Item -Force
$_.FullName | Out-File -FilePath $LogFile -Append
}
Simplest way to write output to log file is by using -Verbose and then use Write-Verbose or 4> after the command
Where-Object { -not $_.PSIsContainer -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } | Remove-Item -Verbose 4> $log_file_path

How to add print to console in PowerShell script?

I am new to PowerShell and I have created the following code to delete specific files and folders:
$myFolderPath = "C:\Test"
$myLimit = (Get-Date).AddDays(-14)
# Delete files according to filter.
Get-ChildItem -Path $myFolderPath -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $myLimit} | Remove-Item -Force
# Delete empty folders.
Get-ChildItem -Path $myFolderPath -Recurse -Force | Where-Object { $_.PSIsContainer -and (Get-ChildItem -Path $_.FullName -Recurse -Force | Where-Object { !$_.PSIsContainer }) -eq $null } | Remove-Item -Force -Recurse
Is it possible to print out the full path of each item that will be removed to the console before the actual Remove-Item operation will be performed?
I guess sth. has to be added here....
... | Remove-Item -Force
and here...
... | Remove-Item -Force -Recurse
but I cannot find out how to implement that in an elegant way (without code duplication).
You can replace the remove-Item-Parts with
Foreach-Object { $_.fullname; Remove-Item -Path $_.Fullname (-Recurse) -Force}
LotPings comment might be better idea, if that is what you want.
It does not get a lot of attention but Tee-Object could be a simple addition to the pipeline here. Redirect the output to a variable that you can print later.
...Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $myLimit} |
Tee-Object -Variable removed | Remove-Item -Force
$removed | Write-Host
All of the file objects piped will be sent to $removed and then to Remove-Item. Since you have more than one delete pipeline you can also use the -Append parameter so that all files are saved in one variable if you so desired.
However this does not mean they were deleted. Just they made it passed the pipe. If you really wanted to be sure you should be using another utility like robocopy which has logging features.

Suppress automatic confirmation of deletion in powershell

I am trying to write a silent script that deletes files older than 14 days and removes empty folders. The part that deletes files work fine, but the part that deletes folders is popping up a confirmation window no matter what I do to suppress it. Here's my code:
$date=(get-date).AddDays(-14)
$ConfirmPreference="None"
$DebugPreference="SilentlyContinue"
$ErrorActionPreference="SilentlyContinue"
$ProgressPreference="SilentlyContinue"
$VerbosePreference="SilentlyContinue"
$WarningPreference="SilentlyContinue"
$OutputEncoding=[console]::OutputEncoding
function FullNuke ([string] $strPath) {
Get-ChildItem -Path $strPath -Recurse -Force | Where-Object {!$_.PSIsContainer -and $_.LastAccessTime -lt $date} | Remove-Item -Force
#The line below is the one that triggers the confirmation
Get-ChildItem -Path $strPath -Recurse -Force | Where-Object {$_.PSIsContainer -and #(Get-ChildItem -LiteralPath $_.FullName -Recurse -Force | Where-Object {!$_.PSIsContainer}).Length -eq 0} | Remove-Item -Force
}
Most of the answers I have found say to add -Recurse to my final Remove-Item command, but that would be the opposite of what I want. If the folder is empty, I want it removed. If it is not empty, I do not want it removed. I'm not sure why non-empty folders are even being caught in the first place.
UPDATE
After much frustration, I discovered that the second line was processing items in reverse order, thus requiring confirmation. It was also not properly identifying empty folders, which also triggered confirmation. I ended up using the following function.
function FullNuke ([string] $strPath) {
Get-ChildItem -Path $strPath -Recurse -Force | Where-Object {!$_.PSIsContainer} | Where-Object {$_.LastAccessTime -lt $date} | Remove-Item -Force
Get-ChildItem -Path $strPath -Recurse -Force | Where-Object {$_.PSIsContainer} | Where-Object {#(Get-ChildItem -LiteralPath $_.FullName -Recurse -Force).Length -eq 0} | Remove-Item -Force
}
I put it here because while it is a solution (it erases files and folders to my satisfaction), it is not an answer to my posted question.
Remove -Force from first Get-ChildItem and add -Recurse and -Confirm:$false.
This will work:
Get-ChildItem -Path $strPath -Recurse |
Where-Object {$_.PSIsContainer -and
#(Get-ChildItem -LiteralPath $_.FullName -Recurse -Force |
Where-Object {!$_.PSIsContainer}).Length -eq 0} |
Remove-Item -Force -Recurse -Confirm:$false
If you are using v3 or higher powershell client you can use the -directory and -file switches for Get-ChildItem and use this:
function FullNuke ([string] $strPath) {
Get-ChildItem -Path $strPath -Recurse -Force -File | Where-Object {$_.LastAccessTime -lt $date} | Remove-Item -Force
Get-ChildItem -Path $strPath -Recurse -Force -Directory | Where-Object {(gci $_.FullName -File -Recurse -Force).count -eq 0} | Remove-Item -Force -Recurse
}
Yes, I added -Recurse to the folder removal because with my testing no folders with any files in them were being passed to that point, and if it is a folder with nothing but empty folders in it then they all need to go anyway right?