Administration with PowerShell put simply, is brilliant! I generally use PowerShell at least once or twice a day for various tasks and any opportunity to do a bit of coding I take gladly. My most recent endeavour with this has been an archive job, in which we were using volumes on a virtual machine then backing up SQL databases to them and removing files based on their age and name – 5 days ish and “.BAK”. The old world method of doing this was a little annoying in my opinion as the version written back in the day had to have a line configured for each folder but since when I first encountered the script I was fairly new in the company I let it be.
One of the best things I find about using PowerShell is you can start simple and build, so without any further detail – “Get-ChildItem” (posh DIR)
Get-ChildItem -Path "C:\"
Very handy little bit of code as this forms the base of what we’re after doing, we need to identify all files within a given location and evaluate their age and type so using GCI with the following switches allows us to extent the use.
Get-ChildItem -Path C:\* -Include *BAK -Recurse
I’ll be honest I was a little surprised at how many results came back from this, I obviously don’t keep an eye on my local backups! I had a little muck around with checking the properties at this point as you can dig into various aspects of each object by simply specifying it within the pipe via a select or pipe the object to a format-list so that all properties are exposed, be warned though it can be information overload! Additionally my own personal preference when making scripts like this is to make them as flexible as possible so I started to change it up at this point by adding in variables to make the script more portable, I’m a bit of a nerd when it comes to formatting, specifically tabulation.
The next step was to get the GCI working with these variables, simple enough, declare variable, set variable and GO – no need for a code snippet here. After that I wanted to expose information about each item which met the criteria we were after so I used a foreach loop.
New-Variable -Name strLocation -Value 'C:\' -scope script New-Variable -Name strFileType -Value "BAK" -scope script foreach ($file in Get-ChildItem -Path $strLocation* -Include *$strFileType -Recurse) { write-host $file }
In the snippet above I’m just proving to myself that it’s working, if it enters the loop write out the name of the object you have context on.
To define the age of the file be expose one of the backups properties, I’m able to use that information by creating a variable which I then use to form a New-TimeSpan between the current objects CreationTime and the current date (get-date), what I want to do once I’ve got this context is do something with the file, in this case delete it however I like to test things first so I’ll start by writing this out to the current PS window.
New-Variable -Name strLocation -Value 'C:\' -scope script New-Variable -Name strFileType -Value "BAK" -scope script New-Variable -Name intAge -Value 7 -scope script foreach ($file in Get-ChildItem -Path $strLocation* -Include *$strFileType -Recurse) { $DaysOld = (New-TimeSpan -Start $file.CreationTime -End (get-date -format g)).Days if (($DaysOld -ge $intAge) -eq $true) { write-host $file.FullName } }
Once happy with the results you can then replace the write-host file out with the actual code required which is shown below.
Remove-Item -LiteralPath $file.FullName
And that’s it for a basic archive, you can tinker with that as a base but basically that’ll give you a simple delete with limited constraints, personally I might use it for my own PC at home for removing any video files which other users create – handy. Further to that below is my final script which I ended up producing which I introduced a few extra features (Logging and Debug), enjoy.
################################################################################################################################################ ## Name : FileArchive.ps1 ## Function : Written to remove files from a location ## Version : 1 ## Author : RT ## Usage : Admin/Advanced only ################################################################################################################################################ clear $error.clear() New-Variable -Name strLocation -Value 'C:\' -scope script New-Variable -Name strFileType -Value "BAK" -scope script New-Variable -Name strLogFile -Value "" -scope script New-Variable -Name strLogFileLocation -Value "C:\" -scope script New-Variable -Name intAge -Value 7 -scope script New-Variable -Name debug -Value 1 -scope script $strLogFile = Get-Date -uformat "%d%m" $strLogFile = "Log_"+$strLogFile + (Get-Date -UFormat "%Y") +".txt" if (($debug -eq 0)-eq $true) { new-item -Path $strLogFileLocation -Name $strLogFile -ItemType file } foreach ($file in Get-ChildItem -Path $strLocation* -Include *$strFileType -Recurse) { $DaysOld = (New-TimeSpan -Start $file.CreationTime -End (get-date -format g)).Days if (($DaysOld -ge $intAge) -eq $true) { $info = @{} $info.DateNow=(get-date -Format g) $info.DaysOld=$DaysOld $info.Created=$file.CreationTime $info.DIRLoc=$file.FullName $object = New-Object -TypeName PSObject –Prop $info if (($debug -eq 0)-eq $true) { $object | format-list | out-file -FilePath $strLogFileLocation$strLogFile -append Remove-Item -LiteralPath $file.FullName } if (($debug -eq 1)-eq $true) { $object | format-list } } } write-host $error Remove-Variable strLocation Remove-Variable strFileType Remove-Variable intAge Remove-Variable debug Remove-Variable strLogFile Remove-Variable strLogFileLocation