2

I have a Powershell script that will delete a file that is at least X days old. I was wondering how I would alter it to print the file before deleting it. The script is

$limit = (Get-Date).AddDays(-45)
$path = "\\noc2-storage\IT_Backup\Daily_SQL\"                                                #"

# Delete files older than the $limit.
echo "Deleting files: "
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
mklement0
  • 382,024
  • 64
  • 607
  • 775
kevorski
  • 816
  • 1
  • 11
  • 29

3 Answers3

4

The easiest approach - and the one that is generally applicably - is to use the -Verbose common parameter:

Write-Verbose -Verbose "Deleting files:"
Get-ChildItem -Path $path -Recurse -Force | 
 Where-Object { ! $_.PSIsContainer -and $_.CreationTime -lt $limit } | 
  Remove-Item -Force -Verbose

Note that in PSv3+ you can simplify this somewhat by using the -Files switch with Get-ChildItem, which directly limits the output to files only, which then allows simplification of the Where-Object call to a so-called comparison statement:

Write-Verbose -Verbose "Deleting files:"
Get-ChildItem -File -Path $path -Recurse -Force | 
 Where-Object CreationTime -lt $limit | 
  Remove-Item -Force -Verbose

If you only want to echo what would be deleted - i.e., to perform a dry run - use the -WhatIf common parameter with Remove-Item, instead of -Verbose.


Also note that I've replaced echo "Deleting files: " with Write-Verbose -Verbose "Deleting files:".

In PowerShell, echo is an alias for Write-Output, which writes to the success stream, which is where output data is meant to go.

In fact, writing to that stream is the default action, so your command could be simplified to just:

"Deleting files: "    # implicitly output the string to the success stream

That said, status messages such as the above do not belong in the success stream, and using the separate stream for verbose output is one option.

Write-Verbose -Verbose generates such verbose output explicitly, but the usual mechanism is to let a function / cmdlet's -Verbose common parameter or the $VerbosePreference preference variable drive whether verbose output should be shown or not.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Thank you for this answer. I would like to add a message stating how many files have been deleted. Is there an easy way to add this option to the script; if a file has been deleted, add +1 to a count. – kevorski Apr 19 '17 at 23:22
  • 1
    @kevorski: If you add `-ov files` (`-OutVariable files`) to the `Where-Object` call, information about all target files is saved in collection `$files`. `$files.Count` will then tell you how many files were targeted. If this doesn't fully answer your follow-up question, please post a _new_ question (and feel free to notify me here). – mklement0 Apr 20 '17 at 01:04
0

For this - you could modify the command you already have pretty easily.

$limit = (Get-Date).AddDays(-45)
$path = "\\noc2-storage\IT_Backup\Daily_SQL\"

# Delete files older than the $limit.
$files = Get-ChildItem -Path $path -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.CreationTime -lt $limit }
ForEach ($file in $files) {
  Write-Verbose -Verbose "Deleting: $file"
  Remove-Item -force $file
}


# 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
Bryce McDonald
  • 1,760
  • 12
  • 22
  • While PSv5 has made `Write-Host` _less_ [harmful](http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/) (with its ability to suppress/capture its output), it's still the wrong tool to use in most cases, including this one. – mklement0 Apr 18 '17 at 02:22
  • Thanks for the tip! I've changed the script to use write-verbose instead of write-host. Have any useful links handy on why Write-Verbose is superior to Write-Host? – Bryce McDonald Apr 18 '17 at 02:27
  • All cmdlets support `-Verbose` directly, so there's no need for a `ForEach-Object` - which is another reason to avoid `Write-Host`, because the `-Verbose` common parameter gives you the status output for free. Here's the [`Write-Verbose` help page](https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/write-verbose), which doesn't provide too much conceptual information, however. The blog post I've already linked to has more information, and [this answer](http://stackoverflow.com/a/40034706/45375) of mine has more about `Write-Host`. – mklement0 Apr 18 '17 at 02:31
0

Assuming you want to print the file name and don't want to print the file contents: Have you tried passing -verbose to Remove-Item?

Vivek Athalye
  • 2,974
  • 2
  • 23
  • 32