5 minute read

Last week I was one of the lucky PowerShell Summit attendees and had the chance to assist to the official launch of the Scripting Games 2013 !! (with a special video created by Sean ;-)

Apart from the PowerShell stars like Ed Wilson, Don Jones, Bruce Payette, Alan Renouf, Lee Holmes, Richard Siddaway, Jeffery Snover…. I met some awesome people there and It was really cool to talk about our passion for PowerShell, How this amazing tool is saving our life each days! Scripting Games 2013 - Advanced Event #1 - An Archival Atrocity

For the first time, I decided this year to participate to the Scripting Games 2013 organize and hosted by the PowerShell.org team.

I chose the Advanced Track and here is the first script I submitted yesterday.

Feel free to comment and send me your critics.

Instruction

Download the instruction here (skydrive)

Dr.Scripto is in a tizzy! It seems that someone has allowed a series of application log files to pile up for around two years, and they're starting to put the pinch on free disk space on a server. Your job is to help get the old files off to a new location. Actually, this happened last week, too. You might as well create a tool to do the archiving. The current sets of 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, * C:\Application\Log\ThisAppAlso. Within those subfolders, the filenames are random GUIDs with a .LOG filename extension. Once 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 - although that path will change from time to time. You need to maintain the subfolder structure, so that files from C:\Application\Log\App1 get moved to\\NASServer\Archives\App1, and so forth. Make those paths parameters, so that Dr.Scripto can just run this tool with whatever paths are appropriate at the time. The 90-day period should be a parameter too. You want to ensure that any errors that happen during the move are clearly displayed to whoever is running your command. If no errors occur, your command doesn't need to display any output - "no news is good news."

VOTE :-) Anybody can vote even if you do not participate to the Scripting Games

Annotations

  • Line 75 - Adding Support to Verbose/Debug…

  • Line 76 - Adding Support to WhatIf/Confirm parameters

  • Line 85 and 92 - Adding Validation to verify that the path specified by the user exist. I have to admit I could have gone a bit deeper on that :-/

  • Line 110 - Bad Bad Baaaaad… I used the back tick! I know… I should had use splatting instead… I’m learning!

  • Line 125 - Here I use a small shortcut to get the parent folder name for the current file (inside the foreach loop), then verify if this folder exist in the Archive destination folder at the line 131

Script

function Move-Log {
<#
 .SYNOPSIS
  Move logs between two specified locations.

 .DESCRIPTION
  Move logs between two specified locations
         Optionaly, you can specify the age in day(s) of the file(s) that need be 
  moved (default = 90) and their File Extention (default = *.log)
        
         If directories are present in the path, those will be re-created
  in the destination path.

 .PARAMETER  Path
  Location path where the logs are located. Default value is
  current folder (.\)

 .PARAMETER  Destination
  Location path where the logs will be moved.
 
 .PARAMETER  Type
  Type of File Extention that need to be moved. Default value is *.log

 .PARAMETER  OlderThan
  Age in Day(s) of the file(s) that need to be moved. Default value is 90.

 .EXAMPLE
  PS C:\> Move-Log -Path "c:\Applications" -Destination "\\Server\Share"
  
  This example shows how to call the Move-Log function with 
  Path and Destination parameters to move old logs from the local 
  directory C:\Applications to the remote share \\server\share.

 .EXAMPLE
  PS C:\> Move-Log -Path "c:\Applications" -Destination "x:\Backup\Apps\Archives"
  
  This example shows how to call the Move-Log function with Path and 
  Destination parameters to move old logs from C:\Applications to 
  x:\Backup\Apps\Archives

 .EXAMPLE
  PS C:\> Get-Location | Move-Log -Destination "\\Server\Share"

  This example shows how to call the Move-Log function with Path and
  Destination parameters, using the pipeline input for the Path parameter.

 .EXAMPLE
  PS C:\> "C:\Applications","D:\Applications" | Move-Log -Destination "\\Server\Share"

  This example shows how to call the Move-Log function with Path and
  Destination parameters, using the pipeline input for the Path parameter.

 .EXAMPLE
  PS C:\> Move-Log -Path "C:\Applications" -Destination "\\Server\Share" -OlderThan 90 -type *.log
  
  This example shows how to call the Move-Log function with Path, 
  Destination, OlderThan and type parameters. This will move logs with the
  extention *.log older than 90 days from c:\Application to the remote 
  share \\server\share.

 .INPUTS
  System.String

 .OUTPUTS
  None, only if Errors occure

 .NOTES
  NAME    : Move-Log.ps1
  AUTHOR  : Francois-Xavier Cat
  TWITTER : @lazywinadmin
  EMAIL   : [email protected]
  WWW     : www.lazywinadmin.com
#>

 [CmdletBinding(
        SupportsShouldProcess=$true,
        ConfirmImpact="Medium")]

 param(

 [Parameter(Mandatory=$true,
   Position = 0,
   ValueFromPipeline=$true,
   HelpMessage="Enter the Path where your Application folders are located. Default is the current location")]
        [ValidateScript({Test-Path $_})]
        [alias("Source")]
  [System.String]
  $Path = ".\",
    
        [Parameter(Mandatory=$true,
          HelpMessage="Enter the Path where your logs will be moved")]
        [ValidateScript({Test-Path $_})]
        [string]
        $Destination,

        [Parameter(HelpMessage="Enter the file(s) extentions. Default value is `"*.log`"")]
        [string[]]
        $Type = "*.log",

        [Parameter(HelpMessage="Enter the age of the file(s) that need to be archive. Default value is 90 days")]
        [Int]
        $OlderThan = 90

 )

 PROCESS {
  try {
            # Get the Logs
            Write-Verbose "PROCESS - Looking for Logs older than $OlderThan days..."
            $Files= Get-ChildItem `
                            -Path $Path `
                            -include $Type `
                            -Recurse `
                            -File |
                        Where-Object {$_.LastWriteTime -lt (get-date).AddDays(-$OlderThan) }
            
            # If Logs are found
            if ($Files){

                foreach ($File in $Files){

     Write-Verbose "PROCESS - Logs found!"

                    # Get the Name of the Parent Folder
                    $ParentFolder = Split-Path -Path (Split-Path $File -Parent) -Leaf
                    
                    # Build the Destination Path for the current $file
                    $DestinationFolder = Join-Path -Path $Destination -ChildPath $ParentFolder

                    # Verify this Folder Name exist in the Destination Path
                    if (-not(Test-Path -Path $DestinationFolder)){
      
                        # Creating the Folder in the $destination if does not exist
                        Write-Verbose -Message "PROCESS - Creating folder in the Destination path: $ParentFolder"
                        New-Item -Name $ParentFolder -ItemType directory -Path $Destination | Out-Null

                    }#if

                    # Move the file
                    Write-Verbose -Message "PROCESS - Moving $File to $DestinationFolder"
                    Move-Item -Path $File.FullName -Destination $DestinationFolder -Force
                
                }#foreach ($file in $files)

            }#if($files)
            
   # If no old logs are found, do the following
   else{
                Write-Verbose -Message "PROCESS - No Logs to move"
                }#else
  }#try

  catch {
            Throw "An Error occured during the PROCESS Block"
  }#catch

 }#Process

}#function Move-Log


```

Thanks for reading! Feel free to contact me or leave me a comment below!

Twitter: @lazywinadmin
Email: [email protected]

Leave a comment