Having participated in the 2013 Winter Scripting Camp I was excited to try out my scripting skills again in the 2013 Scripting Games. While my scripting skills have advanced a lot of over the past 6 months since I co-founded the Philadelphia PowerShell User Group (PhillyPoSH), I still feel that I’m not cut out for the advanced events just yet. Especially considering the Beginner events of Winter Scripting Camp took me much longer than I expected. For those 2 events I struggled to get the answer down to one or two lines. While I believed that my scripting skills have evolved, the beginner events left me feeling as if I hadn’t advanced that much. For a quick history of the games and my submissions for the Winter Scripting Camp check the presentation I gave at PhillyPosh in March of this year.
So the 1st event for both the advanced and beginner track of the Scripting Games is over and the voting phase for the 1st event is under way. As a recap the question for the beginner track was
The log files are located in C:\Application\Log. There are three applications that write logs here, and each uses its own subfolder. For example, C:\Application\Log\App1, C:\Application\Log\OtherApp, and C:\Application\Log\ThisAppAlso. Within those subfolders, the filenames are random GUIDs with a .log filename extension. After they are created on disk, the files are never touched again by the applications.
Your goal is to grab all of the files older than 90 days and move them to \\NASServer\Archives. You need to maintain the subfolder structure, so that files from C:\Application\Log\App1 get moved to \\NASServer\Archives\App1, and so forth.
You want to ensure that any errors that happen during the move are clearly displayed to whoever is running your command. You also want your command to be as concise as possible — Dr. Scripto says a one-liner would be awesome, if you can pull it off, but it’s not mandatory that your command be that concise. It’s also okay to use full command and parameter names. If no errors occur, your command doesn’t need to display any output — “no news is good news.”
After trying a few attempts I originally came up with
Get-ChildItem -Path "C:\Application\Log" -Recurse -Filter *.log | Where-object {$_.CreationTime -le (get-date).AddDays(-90)} | Select Name,Directory,FullName | ForEach-Object {Move-Item $_.FullName -Destination ("\\NASServer\Archives\"+($_.Directory.Name)+"\"+$_.Name)}
At the time, I kept having issues getting $_.Directory.Name to work. When I referenced it I would get an error that the property Directory didn’t exist. Using Select-Object fixed it for me, but upon further review I noticed that it worked without Select-Object. So I guess I probably had a misspelling somewhere when I originally wrote out the command.
I also thought that I need to include the full file name path when copying to the destination, which obviously isn’t the case. My command would essentially say : copy C:\Application\Logs\SomeOtherApp\Test.log to \\NASserver\Archive\SomeOtherApp\Test.log
when it should have just dropped the file name mention in the destination and used \\NASserver\Archive\SomeOtherApp\ instead.
I also didn’t realize my query for *.log would return files with extensions like *.log123 etc. Encasing the filter in double quotations will ensure that I only look for *.log files
So after reviewing and voting on some entries I realized I could have shorten (and corrected) my command to
Get-ChildItem -Path "C:\Application\Log" -Recurse -Filter "*.log" | Where-object {$_.CreationTime -le (get-date).AddDays(-90)} | ForEach-Object {Move-Item $_.FullName -Destination ("\\NASServer\Archives\"+$_.Directory.Name)}
One of the cool parts about this year’s Scripting Games is that every can vote and comment on everyone else’s scripts. So far I’ve seen the following interesting things:
- Using a wildcard in the path name instead of using the –Filter parameters
-
Get-ChildItem -Path C:\Application\Logs\*\*.Log -recurse
-
- Even though the question didn’t ask for it some contestants made a check for the destination folders and created them (using New-item) If they weren’t present, as an example in a foreach loop. Using New-Item alone will create the destination files and directories but will not remove them from the source.
-
if (-not(Test-Path $ArchiveDirectory)) {New-Item $ArchiveDirectory -ItemType Directory | Out-Null} Move-Item $file.FullName $ArchiveDirectory }
-
Blooger Bartek Bielawski posted his answers to both the beginner and the advanced track and I found his use of script block in the beginner event to be very interesting.
Get-ChildItem -Path C:\Application\Log\*\*.Log | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-90)} | Move-Item -Destination {"\\NASServer\Archives\{0}\" -f $_.Directory.Name}
I still plan to vote on a few of the beginner entries this week until the next event opens. As I come across more interesting answers I’ll update this post